summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--api/current.xml726
-rw-r--r--cmds/am/src/com/android/commands/am/Am.java13
-rw-r--r--cmds/dumpstate/dumpstate.c1
-rw-r--r--cmds/installd/installd.h2
-rw-r--r--cmds/stagefright/Android.mk6
-rw-r--r--common/java/com/android/common/OperationScheduler.java1
-rw-r--r--common/java/com/android/common/speech/Recognition.java40
-rw-r--r--core/java/android/accounts/AccountManager.java1449
-rw-r--r--core/java/android/accounts/AccountManagerService.java55
-rw-r--r--core/java/android/app/Activity.java44
-rw-r--r--core/java/android/app/ActivityThread.java123
-rw-r--r--core/java/android/app/AliasActivity.java3
-rw-r--r--core/java/android/app/ApplicationErrorReport.java102
-rw-r--r--core/java/android/app/BackupAgent.java105
-rw-r--r--core/java/android/app/ContextImpl.java16
-rw-r--r--core/java/android/app/DeviceAdminInfo.java14
-rw-r--r--core/java/android/app/DevicePolicyManager.java21
-rw-r--r--core/java/android/app/Dialog.java14
-rw-r--r--core/java/android/app/IDevicePolicyManager.aidl1
-rw-r--r--core/java/android/app/ISearchManager.aidl7
-rw-r--r--core/java/android/app/SearchDialog.java22
-rw-r--r--core/java/android/app/SearchManager.java85
-rw-r--r--core/java/android/app/UiModeManager.java83
-rw-r--r--core/java/android/backup/AbsoluteFileBackupHelper.java1
-rw-r--r--core/java/android/backup/BackupDataInput.java2
-rw-r--r--core/java/android/backup/BackupDataOutput.java2
-rw-r--r--core/java/android/backup/BackupHelper.java15
-rw-r--r--core/java/android/backup/BackupHelperAgent.java21
-rw-r--r--core/java/android/backup/BackupHelperDispatcher.java6
-rw-r--r--core/java/android/backup/BackupManager.java58
-rw-r--r--core/java/android/backup/FileBackupHelper.java30
-rw-r--r--core/java/android/backup/FileBackupHelperBase.java10
-rw-r--r--core/java/android/backup/SharedPreferencesBackupHelper.java8
-rw-r--r--core/java/android/backup/package.html22
-rw-r--r--core/java/android/bluetooth/BluetoothDevice.java4
-rw-r--r--core/java/android/content/ComponentName.java2
-rw-r--r--core/java/android/content/ContentResolver.java4
-rw-r--r--core/java/android/content/Context.java12
-rw-r--r--core/java/android/content/Intent.java24
-rw-r--r--core/java/android/content/IntentFilter.java3
-rw-r--r--core/java/android/content/SyncStorageEngine.java2
-rw-r--r--core/java/android/content/pm/ApplicationInfo.java13
-rw-r--r--core/java/android/content/pm/IPackageManager.aidl2
-rw-r--r--core/java/android/content/pm/PackageParser.java16
-rw-r--r--core/java/android/content/pm/RegisteredServicesCache.java2
-rw-r--r--core/java/android/content/res/AssetManager.java76
-rw-r--r--core/java/android/content/res/Resources.java2
-rw-r--r--core/java/android/content/res/StringBlock.java3
-rw-r--r--core/java/android/content/res/TypedArray.java3
-rw-r--r--core/java/android/content/res/XmlBlock.java5
-rw-r--r--core/java/android/database/sqlite/SQLiteCompiledSql.java14
-rw-r--r--core/java/android/database/sqlite/SQLiteDatabase.java4
-rw-r--r--core/java/android/database/sqlite/SQLiteProgram.java13
-rw-r--r--core/java/android/net/ConnectivityManager.java34
-rw-r--r--core/java/android/net/IConnectivityManager.aidl4
-rw-r--r--core/java/android/net/InterfaceConfiguration.java8
-rw-r--r--core/java/android/net/SSLCertificateSocketFactory.java3
-rw-r--r--core/java/android/net/WebAddress.java2
-rw-r--r--core/java/android/net/http/AndroidHttpClient.java (renamed from common/java/com/android/common/AndroidHttpClient.java)4
-rw-r--r--core/java/android/net/http/CertificateChainValidator.java3
-rw-r--r--core/java/android/net/http/HttpDateTime.java (renamed from common/java/com/android/common/HttpDateTime.java)7
-rw-r--r--core/java/android/os/BatteryStats.java85
-rw-r--r--core/java/android/os/Debug.java14
-rw-r--r--core/java/android/os/storage/IMountService.aidl7
-rw-r--r--core/java/android/pim/RecurrenceSet.java54
-rw-r--r--core/java/android/pim/vcard/VCardComposer.java153
-rw-r--r--core/java/android/provider/ContactsContract.java50
-rw-r--r--core/java/android/provider/Settings.java47
-rw-r--r--core/java/android/provider/Telephony.java2
-rw-r--r--core/java/android/server/search/SearchManagerService.java111
-rw-r--r--core/java/android/server/search/Searchables.java202
-rw-r--r--core/java/android/speech/RecognizerIntent.java9
-rw-r--r--core/java/android/test/InstrumentationTestCase.java8
-rw-r--r--core/java/android/text/AndroidBidi.java48
-rw-r--r--core/java/android/text/AutoText.java4
-rw-r--r--core/java/android/text/Html.java3
-rw-r--r--core/java/android/text/Layout.java5
-rw-r--r--core/java/android/text/StaticLayout.java461
-rw-r--r--core/java/android/text/util/Linkify.java2
-rw-r--r--core/java/android/util/Patterns.java (renamed from common/java/com/android/common/Patterns.java)2
-rw-r--r--core/java/android/util/TimeUtils.java2
-rw-r--r--core/java/android/util/XmlPullAttributes.java3
-rw-r--r--core/java/android/view/View.java42
-rw-r--r--core/java/android/view/ViewGroup.java30
-rwxr-xr-xcore/java/android/view/WindowOrientationListener.java234
-rw-r--r--core/java/android/webkit/CacheManager.java2
-rw-r--r--core/java/android/webkit/CookieManager.java117
-rw-r--r--core/java/android/webkit/PluginManager.java3
-rw-r--r--core/java/android/webkit/WebView.java166
-rw-r--r--core/java/android/widget/AbsListView.java13
-rw-r--r--core/java/android/widget/AbsSpinner.java44
-rw-r--r--core/java/android/widget/CheckedTextView.java4
-rw-r--r--core/java/android/widget/CompoundButton.java2
-rw-r--r--core/java/android/widget/ExpandableListConnector.java3
-rw-r--r--core/java/android/widget/LinearLayout.java52
-rw-r--r--core/java/android/widget/ListView.java1
-rw-r--r--core/java/android/widget/ProgressBar.java24
-rw-r--r--core/java/android/widget/ScrollView.java138
-rw-r--r--core/java/android/widget/TextView.java23
-rw-r--r--core/java/android/widget/VideoView.java44
-rw-r--r--core/java/com/android/internal/app/AlertController.java28
-rw-r--r--core/java/com/android/internal/app/TetherActivity.java2
-rw-r--r--core/java/com/android/internal/content/PackageHelper.java11
-rw-r--r--core/java/com/android/internal/content/PackageMonitor.java287
-rw-r--r--core/java/com/android/internal/content/SyncStateContentProviderHelper.java13
-rw-r--r--core/java/com/android/internal/net/DNParser.java (renamed from common/java/com/android/common/DNParser.java)5
-rw-r--r--core/java/com/android/internal/net/DomainNameValidator.java (renamed from common/java/com/android/common/DomainNameValidator.java)4
-rw-r--r--core/java/com/android/internal/os/BatteryStatsImpl.java24
-rw-r--r--core/java/com/android/internal/os/PowerProfile.java2
-rw-r--r--core/java/com/android/internal/util/FastXmlSerializer.java (renamed from common/java/com/android/common/FastXmlSerializer.java)2
-rw-r--r--core/java/com/android/internal/util/XmlUtils.java (renamed from common/java/com/android/common/XmlUtils.java)3
-rw-r--r--core/java/com/android/internal/widget/LockPatternUtils.java38
-rw-r--r--core/jni/Android.mk1
-rw-r--r--core/jni/AndroidRuntime.cpp2
-rw-r--r--core/jni/android_text_AndroidBidi.cpp81
-rw-r--r--core/jni/android_util_AssetManager.cpp22
-rw-r--r--core/jni/android_util_StringBlock.cpp5
-rw-r--r--core/res/res/drawable-hdpi/btn_dropdown_disabled.9.pngbin0 -> 1374 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_dropdown_disabled_focused.9.pngbin0 -> 1775 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_search_dialog_default.9.pngbin711 -> 712 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_search_dialog_pressed.9.pngbin1355 -> 2588 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_search_dialog_selected.9.pngbin1380 -> 2596 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_search_dialog_voice_default.9.pngbin914 -> 898 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_search_dialog_voice_pressed.9.pngbin1555 -> 2362 bytes
-rw-r--r--core/res/res/drawable-hdpi/btn_search_dialog_voice_selected.9.pngbin1607 -> 2477 bytes
-rw-r--r--core/res/res/drawable-hdpi/spinnerbox_arrow_first.9.pngbin491 -> 0 bytes
-rw-r--r--core/res/res/drawable-hdpi/spinnerbox_arrow_last.9.pngbin489 -> 0 bytes
-rw-r--r--core/res/res/drawable-hdpi/spinnerbox_arrow_middle.9.pngbin486 -> 0 bytes
-rw-r--r--core/res/res/drawable-hdpi/spinnerbox_arrow_single.9.pngbin451 -> 0 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_dropdown_disabled.9.pngbin0 -> 901 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_dropdown_disabled_focused.9.pngbin0 -> 1118 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_search_dialog_voice_default.9.pngbin3371 -> 597 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_search_dialog_voice_pressed.9.pngbin3722 -> 1237 bytes
-rw-r--r--core/res/res/drawable-mdpi/btn_search_dialog_voice_selected.9.pngbin3690 -> 1241 bytes
-rw-r--r--core/res/res/drawable-mdpi/spinnerbox_arrow_first.9.pngbin3053 -> 0 bytes
-rw-r--r--core/res/res/drawable-mdpi/spinnerbox_arrow_last.9.pngbin3052 -> 0 bytes
-rw-r--r--core/res/res/drawable-mdpi/spinnerbox_arrow_middle.9.pngbin3020 -> 0 bytes
-rw-r--r--core/res/res/drawable-mdpi/spinnerbox_arrow_single.9.pngbin3037 -> 0 bytes
-rw-r--r--core/res/res/drawable/btn_circle.xml2
-rw-r--r--core/res/res/drawable/btn_dropdown.xml24
-rw-r--r--core/res/res/drawable/spinnerbox_arrows.xml27
-rw-r--r--core/res/res/layout/alert_dialog.xml3
-rw-r--r--core/res/res/layout/search_bar.xml7
-rw-r--r--core/res/res/layout/status_bar_expanded.xml11
-rw-r--r--core/res/res/values/arrays.xml11
-rw-r--r--core/res/res/values/attrs_manifest.xml36
-rw-r--r--core/res/res/values/config.xml3
-rw-r--r--core/res/res/values/public.xml1
-rw-r--r--core/res/res/values/strings.xml10
-rw-r--r--core/tests/coretests/Android.mk2
-rw-r--r--core/tests/coretests/src/android/app/SearchablesTest.java62
-rw-r--r--core/tests/coretests/src/android/text/StaticLayoutBidiTest.java137
-rw-r--r--core/tests/coretests/src/android/text/StaticLayoutTest.java4
-rw-r--r--core/tests/coretests/src/android/widget/expandablelistview/ExpandableListBasicTest.java70
-rw-r--r--core/tests/coretests/src/android/widget/expandablelistview/ExpandableListWithHeaders.java9
-rw-r--r--core/tests/coretests/src/android/widget/expandablelistview/ExpandableListWithHeadersTest.java17
-rw-r--r--core/tests/coretests/src/android/widget/expandablelistview/InflatedExpandableListView.java2
-rw-r--r--core/tests/coretests/src/android/widget/expandablelistview/PositionTesterContextMenuListener.java43
-rw-r--r--docs/html/guide/practices/design/performance.jd20
-rw-r--r--include/binder/Parcel.h4
-rw-r--r--include/media/stagefright/AudioPlayer.h3
-rw-r--r--include/media/stagefright/OMXCodec.h2
-rw-r--r--include/ui/GraphicBuffer.h17
-rw-r--r--include/utils/Flattenable.h62
-rw-r--r--include/utils/ResourceTypes.h2
-rw-r--r--keystore/java/android/security/SystemKeyStore.java3
-rw-r--r--libs/audioflinger/AudioPolicyManagerBase.cpp46
-rw-r--r--libs/binder/Parcel.cpp70
-rw-r--r--libs/rs/rsContext.cpp2
-rw-r--r--libs/rs/rsContext.h4
-rw-r--r--libs/rs/rsProgramFragment.cpp4
-rw-r--r--libs/rs/rsSampler.cpp14
-rw-r--r--libs/rs/rsSampler.h2
-rw-r--r--libs/rs/rsType.cpp18
-rw-r--r--libs/rs/rsType.h2
-rw-r--r--libs/surfaceflinger/Android.mk1
-rw-r--r--libs/surfaceflinger/LayerBase.h1
-rw-r--r--libs/surfaceflinger/SurfaceFlinger.cpp45
-rw-r--r--libs/surfaceflinger/Transform.cpp390
-rw-r--r--libs/surfaceflinger/Transform.h94
-rw-r--r--libs/surfaceflinger_client/ISurface.cpp7
-rw-r--r--libs/ui/GraphicBuffer.cpp125
-rw-r--r--libs/utils/Android.mk1
-rw-r--r--libs/utils/Flattenable.cpp24
-rw-r--r--libs/utils/ResourceTypes.cpp45
-rwxr-xr-xlocation/java/com/android/internal/location/GpsLocationProvider.java13
-rw-r--r--location/java/com/android/internal/location/GpsXtraDownloader.java2
-rw-r--r--media/java/android/media/MediaFile.java30
-rw-r--r--media/jni/android_media_ResampleInputStream.cpp2
-rw-r--r--media/libstagefright/AudioPlayer.cpp8
-rw-r--r--media/libstagefright/AwesomePlayer.cpp23
-rw-r--r--media/libstagefright/MPEG4Extractor.cpp119
-rw-r--r--media/libstagefright/OMXCodec.cpp17
-rw-r--r--media/libstagefright/Prefetcher.cpp4
-rw-r--r--media/libstagefright/codecs/mp3dec/MP3Decoder.cpp23
-rw-r--r--media/libstagefright/include/AwesomePlayer.h3
-rw-r--r--media/libstagefright/include/MPEG4Extractor.h2
-rw-r--r--media/libstagefright/omx/OMX.cpp43
-rw-r--r--media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaProfileReader.java135
-rw-r--r--media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaRecorderTest.java77
-rw-r--r--media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaMetadataRetrieverTest.java15
-rw-r--r--mms-common/Android.mk1
-rw-r--r--mms-common/java/com/android/mmscommon/telephony/TelephonyProvider.java2
-rw-r--r--packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java8
-rw-r--r--packages/SettingsProvider/res/values/defaults.xml18
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java64
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java4
-rw-r--r--packages/TtsService/jni/android_tts_SynthProxy.cpp24
-rw-r--r--preloaded-classes1266
-rw-r--r--sax/tests/saxtests/src/android/sax/SafeSaxTest.java2
-rw-r--r--services/java/com/android/server/AccessibilityManagerService.java85
-rw-r--r--services/java/com/android/server/AlarmManagerService.java29
-rw-r--r--services/java/com/android/server/AppWidgetService.java2
-rw-r--r--services/java/com/android/server/BackupManagerService.java27
-rw-r--r--services/java/com/android/server/ConnectivityService.java58
-rw-r--r--services/java/com/android/server/DevicePolicyManagerService.java64
-rw-r--r--services/java/com/android/server/DockObserver.java59
-rw-r--r--services/java/com/android/server/InputMethodManagerService.java266
-rw-r--r--services/java/com/android/server/KeyInputQueue.java2
-rw-r--r--services/java/com/android/server/LocationManagerService.java24
-rw-r--r--services/java/com/android/server/MountService.java177
-rw-r--r--services/java/com/android/server/NetworkManagementService.java4
-rwxr-xr-xservices/java/com/android/server/NotificationManagerService.java27
-rw-r--r--services/java/com/android/server/PackageManagerService.java179
-rw-r--r--services/java/com/android/server/RecognitionManagerService.java130
-rw-r--r--services/java/com/android/server/SystemServer.java17
-rw-r--r--services/java/com/android/server/TwilightCalculator.java32
-rw-r--r--services/java/com/android/server/WallpaperManagerService.java121
-rw-r--r--services/java/com/android/server/am/ActivityManagerService.java263
-rw-r--r--services/java/com/android/server/am/PendingIntentRecord.java34
-rw-r--r--services/java/com/android/server/am/ServiceRecord.java12
-rw-r--r--services/java/com/android/server/connectivity/Tethering.java485
-rw-r--r--services/java/com/android/server/status/ExpandedView.java19
-rw-r--r--services/java/com/android/server/status/StatusBarPolicy.java5
-rw-r--r--services/java/com/android/server/status/StatusBarService.java60
-rw-r--r--services/java/com/android/server/status/StorageNotification.java19
-rw-r--r--services/java/com/android/server/status/TrackingView.java2
-rw-r--r--telephony/java/com/android/internal/telephony/DataConnectionTracker.java3
-rw-r--r--telephony/java/com/android/internal/telephony/IccPhoneBookInterfaceManager.java8
-rw-r--r--telephony/java/com/android/internal/telephony/IccProvider.java146
-rw-r--r--telephony/java/com/android/internal/telephony/PhoneSubInfo.java5
-rw-r--r--telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java12
-rw-r--r--telephony/java/com/android/internal/telephony/cdma/EriManager.java2
-rw-r--r--telephony/java/com/android/internal/telephony/cdma/RuimPhoneBookInterfaceManager.java31
-rw-r--r--telephony/java/com/android/internal/telephony/cdma/RuimSmsInterfaceManager.java8
-rw-r--r--telephony/java/com/android/internal/telephony/gsm/GsmDataConnection.java2
-rw-r--r--telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java12
-rw-r--r--telephony/java/com/android/internal/telephony/gsm/SimPhoneBookInterfaceManager.java31
-rw-r--r--telephony/java/com/android/internal/telephony/gsm/SimSmsInterfaceManager.java20
-rw-r--r--telephony/java/com/android/internal/telephony/gsm/SpnOverride.java2
-rw-r--r--telephony/java/com/android/internal/telephony/gsm/VoiceMailConstants.java3
-rw-r--r--test-runner/src/android/test/InstrumentationTestRunner.java88
-rw-r--r--test-runner/tests/src/android/test/InstrumentationTestRunnerTest.java40
-rw-r--r--tests/AndroidTests/res/raw/alt_ip_only.crt (renamed from common/tests/res/raw/alt_ip_only.crt)0
-rw-r--r--tests/AndroidTests/res/raw/subject_alt_only.crt (renamed from common/tests/res/raw/subject_alt_only.crt)0
-rw-r--r--tests/AndroidTests/res/raw/subject_only.crt (renamed from common/tests/res/raw/subject_only.crt)0
-rw-r--r--tests/AndroidTests/res/raw/subject_with_alt_names.crt (renamed from common/tests/res/raw/subject_with_alt_names.crt)0
-rw-r--r--tests/AndroidTests/res/raw/subject_with_wild_alt_name.crt (renamed from common/tests/res/raw/subject_with_wild_alt_name.crt)0
-rw-r--r--tests/AndroidTests/res/raw/wild_alt_name_only.crt (renamed from common/tests/res/raw/wild_alt_name_only.crt)0
-rwxr-xr-xtests/AndroidTests/src/com/android/unit_tests/AsecTests.java44
-rw-r--r--tests/AndroidTests/src/com/android/unit_tests/DNParserTest.java (renamed from common/tests/src/com/android/common/DNParserTest.java)4
-rw-r--r--tests/AndroidTests/src/com/android/unit_tests/DomainNameValidatorTest.java (renamed from common/tests/src/com/android/common/DomainNameValidatorTest.java)4
-rwxr-xr-xtests/AndroidTests/src/com/android/unit_tests/PackageManagerTests.java170
-rw-r--r--tests/AndroidTests/src/com/android/unit_tests/PatternsTest.java (renamed from common/tests/src/com/android/common/PatternsTest.java)10
-rw-r--r--tests/CoreTests/android/core/MiscRegressionTest.java10
-rw-r--r--tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java24
-rw-r--r--tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java15
-rw-r--r--tests/LocationTracker/Android.mk10
-rw-r--r--tests/LocationTracker/AndroidManifest.xml30
-rw-r--r--tests/LocationTracker/res/layout/entrylist_item.xml25
-rw-r--r--tests/LocationTracker/res/menu/menu.xml37
-rw-r--r--tests/LocationTracker/res/values/strings.xml48
-rwxr-xr-xtests/LocationTracker/res/xml/preferences.xml63
-rwxr-xr-xtests/LocationTracker/src/com/android/locationtracker/SettingsActivity.java35
-rw-r--r--tests/LocationTracker/src/com/android/locationtracker/TrackerActivity.java226
-rw-r--r--tests/LocationTracker/src/com/android/locationtracker/TrackerService.java445
-rw-r--r--tests/LocationTracker/src/com/android/locationtracker/data/CSVFormatter.java87
-rw-r--r--tests/LocationTracker/src/com/android/locationtracker/data/DateUtils.java61
-rw-r--r--tests/LocationTracker/src/com/android/locationtracker/data/IFormatter.java27
-rw-r--r--tests/LocationTracker/src/com/android/locationtracker/data/KMLFormatter.java88
-rw-r--r--tests/LocationTracker/src/com/android/locationtracker/data/TrackerDataHelper.java173
-rw-r--r--tests/LocationTracker/src/com/android/locationtracker/data/TrackerEntry.java253
-rw-r--r--tests/LocationTracker/src/com/android/locationtracker/data/TrackerListHelper.java75
-rw-r--r--tests/LocationTracker/src/com/android/locationtracker/data/TrackerProvider.java126
-rw-r--r--tests/SslLoad/src/com/android/sslload/SslLoad.java2
-rw-r--r--tools/aapt/Resource.cpp8
-rw-r--r--tools/aapt/StringPool.cpp8
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Canvas.java5
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Matrix.java5
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Paint.java5
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java2
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeContext.java2
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeTypedArray.java8
-rw-r--r--tools/preload/20100223.compiledbin0 -> 21723744 bytes
-rw-r--r--tools/preload/MemoryUsage.java4
-rw-r--r--tools/preload/Policy.java7
-rw-r--r--tools/preload/Record.java17
-rw-r--r--wifi/java/android/net/wifi/WifiStateTracker.java22
298 files changed, 10260 insertions, 4055 deletions
diff --git a/api/current.xml b/api/current.xml
index 33a8020..e688ab4 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -6785,6 +6785,17 @@
visibility="public"
>
</field>
+<field name="restoreAnyVersion"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843451"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="restoreNeedsApplication"
type="int"
transient="false"
@@ -14630,7 +14641,7 @@
</parameter>
<parameter name="features" type="java.lang.String[]">
</parameter>
-<parameter name="activityForPrompting" type="android.app.Activity">
+<parameter name="activity" type="android.app.Activity">
</parameter>
<parameter name="addAccountOptions" type="android.os.Bundle">
</parameter>
@@ -26277,6 +26288,83 @@
</parameter>
</method>
</interface>
+<class name="UiModeManager"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="disableCarMode"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getNightMode"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="setNightMode"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="mode" type="int">
+</parameter>
+</method>
+<field name="MODE_AUTO"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="3"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="MODE_NIGHT"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="MODE_NOTNIGHT"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
<class name="WallpaperInfo"
extends="java.lang.Object"
abstract="false"
@@ -34549,6 +34637,17 @@
visibility="public"
>
</field>
+<field name="UI_MODE_SERVICE"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;uimode&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="VIBRATOR_SERVICE"
type="java.lang.String"
transient="false"
@@ -89879,6 +89978,356 @@
</package>
<package name="android.net.http"
>
+<class name="AndroidHttpClient"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="org.apache.http.client.HttpClient">
+</implements>
+<method name="close"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="disableCurlLogging"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="enableCurlLogging"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="name" type="java.lang.String">
+</parameter>
+<parameter name="level" type="int">
+</parameter>
+</method>
+<method name="execute"
+ return="org.apache.http.HttpResponse"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="request" type="org.apache.http.client.methods.HttpUriRequest">
+</parameter>
+<exception name="IOException" type="java.io.IOException">
+</exception>
+</method>
+<method name="execute"
+ return="org.apache.http.HttpResponse"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="request" type="org.apache.http.client.methods.HttpUriRequest">
+</parameter>
+<parameter name="context" type="org.apache.http.protocol.HttpContext">
+</parameter>
+<exception name="IOException" type="java.io.IOException">
+</exception>
+</method>
+<method name="execute"
+ return="org.apache.http.HttpResponse"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="target" type="org.apache.http.HttpHost">
+</parameter>
+<parameter name="request" type="org.apache.http.HttpRequest">
+</parameter>
+<exception name="IOException" type="java.io.IOException">
+</exception>
+</method>
+<method name="execute"
+ return="org.apache.http.HttpResponse"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="target" type="org.apache.http.HttpHost">
+</parameter>
+<parameter name="request" type="org.apache.http.HttpRequest">
+</parameter>
+<parameter name="context" type="org.apache.http.protocol.HttpContext">
+</parameter>
+<exception name="IOException" type="java.io.IOException">
+</exception>
+</method>
+<method name="execute"
+ return="T"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="request" type="org.apache.http.client.methods.HttpUriRequest">
+</parameter>
+<parameter name="responseHandler" type="org.apache.http.client.ResponseHandler&lt;? extends T&gt;">
+</parameter>
+<exception name="ClientProtocolException" type="org.apache.http.client.ClientProtocolException">
+</exception>
+<exception name="IOException" type="java.io.IOException">
+</exception>
+</method>
+<method name="execute"
+ return="T"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="request" type="org.apache.http.client.methods.HttpUriRequest">
+</parameter>
+<parameter name="responseHandler" type="org.apache.http.client.ResponseHandler&lt;? extends T&gt;">
+</parameter>
+<parameter name="context" type="org.apache.http.protocol.HttpContext">
+</parameter>
+<exception name="ClientProtocolException" type="org.apache.http.client.ClientProtocolException">
+</exception>
+<exception name="IOException" type="java.io.IOException">
+</exception>
+</method>
+<method name="execute"
+ return="T"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="target" type="org.apache.http.HttpHost">
+</parameter>
+<parameter name="request" type="org.apache.http.HttpRequest">
+</parameter>
+<parameter name="responseHandler" type="org.apache.http.client.ResponseHandler&lt;? extends T&gt;">
+</parameter>
+<exception name="ClientProtocolException" type="org.apache.http.client.ClientProtocolException">
+</exception>
+<exception name="IOException" type="java.io.IOException">
+</exception>
+</method>
+<method name="execute"
+ return="T"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="target" type="org.apache.http.HttpHost">
+</parameter>
+<parameter name="request" type="org.apache.http.HttpRequest">
+</parameter>
+<parameter name="responseHandler" type="org.apache.http.client.ResponseHandler&lt;? extends T&gt;">
+</parameter>
+<parameter name="context" type="org.apache.http.protocol.HttpContext">
+</parameter>
+<exception name="ClientProtocolException" type="org.apache.http.client.ClientProtocolException">
+</exception>
+<exception name="IOException" type="java.io.IOException">
+</exception>
+</method>
+<method name="getCompressedEntity"
+ return="org.apache.http.entity.AbstractHttpEntity"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="data" type="byte[]">
+</parameter>
+<parameter name="resolver" type="android.content.ContentResolver">
+</parameter>
+<exception name="IOException" type="java.io.IOException">
+</exception>
+</method>
+<method name="getConnectionManager"
+ return="org.apache.http.conn.ClientConnectionManager"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getMinGzipSize"
+ return="long"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="resolver" type="android.content.ContentResolver">
+</parameter>
+</method>
+<method name="getParams"
+ return="org.apache.http.params.HttpParams"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getUngzippedContent"
+ return="java.io.InputStream"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="entity" type="org.apache.http.HttpEntity">
+</parameter>
+<exception name="IOException" type="java.io.IOException">
+</exception>
+</method>
+<method name="modifyRequestToAcceptGzipResponse"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="request" type="org.apache.http.HttpRequest">
+</parameter>
+</method>
+<method name="newInstance"
+ return="android.net.http.AndroidHttpClient"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="userAgent" type="java.lang.String">
+</parameter>
+<parameter name="context" type="android.content.Context">
+</parameter>
+</method>
+<method name="newInstance"
+ return="android.net.http.AndroidHttpClient"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="userAgent" type="java.lang.String">
+</parameter>
+</method>
+<field name="DEFAULT_SYNC_MIN_GZIP_BYTES"
+ type="long"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+<class name="HttpDateTime"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="HttpDateTime"
+ type="android.net.http.HttpDateTime"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="parse"
+ return="java.lang.Long"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="timeString" type="java.lang.String">
+</parameter>
+<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException">
+</exception>
+</method>
+</class>
<class name="SslCertificate"
extends="java.lang.Object"
abstract="false"
@@ -113095,6 +113544,28 @@
visibility="public"
>
</method>
+<method name="getGlobalClassInitCount"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getGlobalClassInitTime"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="getGlobalExternalAllocCount"
return="int"
abstract="false"
@@ -113341,6 +113812,28 @@
visibility="public"
>
</method>
+<method name="resetGlobalClassInitCount"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="resetGlobalClassInitTime"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="resetGlobalExternalAllocCount"
return="void"
abstract="false"
@@ -133377,6 +133870,17 @@
visibility="public"
>
</field>
+<field name="ACTION_ADD_ACCOUNT"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.settings.ADD_ACCOUNT_SETTINGS&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="ACTION_AIRPLANE_MODE_SETTINGS"
type="java.lang.String"
transient="false"
@@ -133685,6 +134189,17 @@
visibility="public"
>
</field>
+<field name="EXTRA_AUTHORITIES"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;authorities&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
</class>
<class name="Settings.NameValueTable"
extends="java.lang.Object"
@@ -137618,6 +138133,17 @@
visibility="public"
>
</field>
+<field name="EXTRA_CALLING_PACKAGE"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;calling_package&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="EXTRA_LANGUAGE"
type="java.lang.String"
transient="false"
@@ -163356,6 +163882,134 @@
>
</field>
</class>
+<class name="Patterns"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="concatGroups"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="matcher" type="java.util.regex.Matcher">
+</parameter>
+</method>
+<method name="digitsAndPlusOnly"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="matcher" type="java.util.regex.Matcher">
+</parameter>
+</method>
+<field name="DOMAIN_NAME"
+ type="java.util.regex.Pattern"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="EMAIL_ADDRESS"
+ type="java.util.regex.Pattern"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="GOOD_IRI_CHAR"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;a-zA-Z0-9\u00a0-\ud7ff\uf900-\ufdcf\ufdf0-\uffef&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="IP_ADDRESS"
+ type="java.util.regex.Pattern"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="PHONE"
+ type="java.util.regex.Pattern"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TOP_LEVEL_DOMAIN"
+ type="java.util.regex.Pattern"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TOP_LEVEL_DOMAIN_STR"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;((aero|arpa|asia|a[cdefgilmnoqrstuwxz])|(biz|b[abdefghijmnorstvwyz])|(cat|com|coop|c[acdfghiklmnoruvxyz])|d[ejkmoz]|(edu|e[cegrstu])|f[ijkmor]|(gov|g[abdefghilmnpqrstuwy])|h[kmnrtu]|(info|int|i[delmnoqrst])|(jobs|j[emop])|k[eghimnprwyz]|l[abcikrstuvy]|(mil|mobi|museum|m[acdeghklmnopqrstuvwxyz])|(name|net|n[acefgilopruz])|(org|om)|(pro|p[aefghklmnrstwy])|qa|r[eosuw]|s[abcdeghijklmnortuvyz]|(tel|travel|t[cdfghjklmnoprtvwz])|u[agksyz]|v[aceginu]|w[fs]|(xn\\-\\-0zwm56d|xn\\-\\-11b5bs3a9aj6g|xn\\-\\-80akhbyknj4f|xn\\-\\-9t4b11yi5a|xn\\-\\-deba0ad|xn\\-\\-g6w251d|xn\\-\\-hgbk6aj7f53bba|xn\\-\\-hlcj6aya9esc7a|xn\\-\\-jxalpdlp|xn\\-\\-kgbechtv|xn\\-\\-zckzah)|y[etu]|z[amw])&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TOP_LEVEL_DOMAIN_STR_FOR_WEB_URL"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;(?:(?:aero|arpa|asia|a[cdefgilmnoqrstuwxz])|(?:biz|b[abdefghijmnorstvwyz])|(?:cat|com|coop|c[acdfghiklmnoruvxyz])|d[ejkmoz]|(?:edu|e[cegrstu])|f[ijkmor]|(?:gov|g[abdefghilmnpqrstuwy])|h[kmnrtu]|(?:info|int|i[delmnoqrst])|(?:jobs|j[emop])|k[eghimnprwyz]|l[abcikrstuvy]|(?:mil|mobi|museum|m[acdeghklmnopqrstuvwxyz])|(?:name|net|n[acefgilopruz])|(?:org|om)|(?:pro|p[aefghklmnrstwy])|qa|r[eosuw]|s[abcdeghijklmnortuvyz]|(?:tel|travel|t[cdfghjklmnoprtvwz])|u[agksyz]|v[aceginu]|w[fs]|(?:xn\\-\\-0zwm56d|xn\\-\\-11b5bs3a9aj6g|xn\\-\\-80akhbyknj4f|xn\\-\\-9t4b11yi5a|xn\\-\\-deba0ad|xn\\-\\-g6w251d|xn\\-\\-hgbk6aj7f53bba|xn\\-\\-hlcj6aya9esc7a|xn\\-\\-jxalpdlp|xn\\-\\-kgbechtv|xn\\-\\-zckzah)|y[etu]|z[amw]))&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="WEB_URL"
+ type="java.util.regex.Pattern"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
<class name="PrintStreamPrinter"
extends="java.lang.Object"
abstract="false"
@@ -211651,6 +212305,17 @@
<parameter name="measureSpec" type="int">
</parameter>
</method>
+<method name="resume"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="seekTo"
return="void"
abstract="false"
@@ -211764,6 +212429,17 @@
visibility="public"
>
</method>
+<method name="suspend"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
</class>
<class name="ViewAnimator"
extends="android.widget.FrameLayout"
@@ -215715,7 +216391,7 @@
synchronized="false"
static="true"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</method>
@@ -215798,7 +216474,7 @@
value="&quot;/sdcard/dmtrace.trace&quot;"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -215835,6 +216511,28 @@
visibility="public"
>
</field>
+<field name="KIND_GLOBAL_CLASS_INIT_COUNT"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="32"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="KIND_GLOBAL_CLASS_INIT_TIME"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="64"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="KIND_GLOBAL_EXT_ALLOCATED_BYTES"
type="int"
transient="false"
@@ -215934,6 +216632,28 @@
visibility="public"
>
</field>
+<field name="KIND_THREAD_CLASS_INIT_COUNT"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2097152"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="KIND_THREAD_CLASS_INIT_TIME"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="4194304"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="KIND_THREAD_EXT_ALLOCATED_BYTES"
type="int"
transient="false"
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index d640de1..b6c9de4 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -88,6 +88,8 @@ public class Am {
if (op.equals("start")) {
runStart();
+ } else if (op.equals("startservice")) {
+ runStartService();
} else if (op.equals("instrument")) {
runInstrument();
} else if (op.equals("broadcast")) {
@@ -183,6 +185,15 @@ public class Am {
return intent;
}
+ private void runStartService() throws Exception {
+ Intent intent = makeIntent();
+ System.out.println("Starting service: " + intent);
+ ComponentName cn = mAm.startService(null, intent, intent.getType());
+ if (cn == null) {
+ System.err.println("Error: Not found; no service started.");
+ }
+ }
+
private void runStart() throws Exception {
Intent intent = makeIntent();
System.out.println("Starting: " + intent);
@@ -496,6 +507,8 @@ public class Am {
" start an Activity: am start [-D] <INTENT>\n" +
" -D: enable debugging\n" +
"\n" +
+ " start a Service: am startservice <INTENT>\n" +
+ "\n" +
" send a broadcast Intent: am broadcast <INTENT>\n" +
"\n" +
" start an Instrumentation: am instrument [flags] <COMPONENT>\n" +
diff --git a/cmds/dumpstate/dumpstate.c b/cmds/dumpstate/dumpstate.c
index 78f90a1..adec5a4 100644
--- a/cmds/dumpstate/dumpstate.c
+++ b/cmds/dumpstate/dumpstate.c
@@ -96,6 +96,7 @@ static void dumpstate() {
run_command("NETWORK INTERFACES", 10, "netcfg", NULL);
dump_file("NETWORK ROUTES", "/proc/net/route");
+ dump_file("ARP CACHE", "/proc/net/arp");
#ifdef FWDUMP_bcm4329
run_command("DUMP WIFI FIRMWARE LOG", 60,
diff --git a/cmds/installd/installd.h b/cmds/installd/installd.h
index 92ae310..8e4adb1 100644
--- a/cmds/installd/installd.h
+++ b/cmds/installd/installd.h
@@ -68,7 +68,7 @@
/* other handy constants */
#define PROTECTED_DIR_PREFIX "/data/app-private/"
-#define SDCARD_DIR_PREFIX "/asec/"
+#define SDCARD_DIR_PREFIX getenv("ASEC_MOUNTPOINT")
#define DALVIK_CACHE_PREFIX "/data/dalvik-cache/"
#define DALVIK_CACHE_POSTFIX "/classes.dex"
diff --git a/cmds/stagefright/Android.mk b/cmds/stagefright/Android.mk
index 68d8bb0..52f767e 100644
--- a/cmds/stagefright/Android.mk
+++ b/cmds/stagefright/Android.mk
@@ -17,6 +17,8 @@ LOCAL_C_INCLUDES:= \
LOCAL_CFLAGS += -Wno-multichar
+LOCAL_MODULE_TAGS := debug
+
LOCAL_MODULE:= stagefright
include $(BUILD_EXECUTABLE)
@@ -39,6 +41,8 @@ LOCAL_C_INCLUDES:= \
LOCAL_CFLAGS += -Wno-multichar
+LOCAL_MODULE_TAGS := debug
+
LOCAL_MODULE:= record
include $(BUILD_EXECUTABLE)
@@ -61,6 +65,8 @@ LOCAL_C_INCLUDES:= \
LOCAL_CFLAGS += -Wno-multichar
+LOCAL_MODULE_TAGS := debug
+
LOCAL_MODULE:= audioloop
include $(BUILD_EXECUTABLE)
diff --git a/common/java/com/android/common/OperationScheduler.java b/common/java/com/android/common/OperationScheduler.java
index 0c7ca83..0a48fe7 100644
--- a/common/java/com/android/common/OperationScheduler.java
+++ b/common/java/com/android/common/OperationScheduler.java
@@ -17,6 +17,7 @@
package com.android.common;
import android.content.SharedPreferences;
+import android.net.http.HttpDateTime;
import android.text.format.Time;
import java.util.Map;
diff --git a/common/java/com/android/common/speech/Recognition.java b/common/java/com/android/common/speech/Recognition.java
index 6f164a9..a79a19b 100644
--- a/common/java/com/android/common/speech/Recognition.java
+++ b/common/java/com/android/common/speech/Recognition.java
@@ -19,18 +19,42 @@ package com.android.common.speech;
/**
* Utilities for voice recognition implementations.
*
- * @see android.app.RecognitionService
+ * @see android.speech.RecognitionService
+ * @see android.speech.RecognizerIntent
*/
public class Recognition {
-
+
+ /**
+ * The key to the extra in the Bundle returned by
+ * android.speech.RecognizerIntent#ACTION_GET_LANGUAGE_DETAILS
+ * which is an ArrayList of CharSequences which are hints that can be shown to
+ * the user for voice actions currently supported by voice search for the user's current
+ * language preference for voice search (i.e., the one defined in the extra
+ * android.speech.RecognizerIntent#EXTRA_LANGUAGE_PREFERENCE).
+ *
+ * If this is paired with EXTRA_HINT_CONTEXT, should return a set of hints that are
+ * appropriate for the provided context.
+ *
+ * The CharSequences are SpannedStrings and will contain segments wrapped in
+ * <annotation action="true"></annotation>. This is to indicate the section of the text
+ * which represents the voice action, to be highlighted in the UI if so desired.
+ */
+ public static final String EXTRA_HINT_STRINGS = "android.speech.extra.HINT_STRINGS";
+
+ /**
+ * The key to an extra to be included in the request intent for
+ * android.speech.RecognizerIntent#ACTION_GET_LANGUAGE_DETAILS.
+ * Should be an int of one of the values defined below. If an
+ * unknown int value is provided, it should be ignored.
+ */
+ public static final String EXTRA_HINT_CONTEXT = "android.speech.extra.HINT_CONTEXT";
+
/**
- * The extra key used in an intent to the speech recognizer for voice search. Not
- * generally to be used by developers. The system search dialog uses this, for example,
- * to set a calling package for identification by a voice search API. If this extra
- * is set by anyone but the system process, it should be overridden by the voice search
- * implementation.
+ * A set of values for EXTRA_HINT_CONTEXT.
*/
- public final static String EXTRA_CALLING_PACKAGE = "calling_package";
+ public static final int HINT_CONTEXT_UNKNOWN = 0;
+ public static final int HINT_CONTEXT_VOICE_SEARCH_HELP = 1;
+ public static final int HINT_CONTEXT_CAR_HOME = 2;
private Recognition() { } // don't instantiate
}
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java
index 43a0f30..e2263fc 100644
--- a/core/java/android/accounts/AccountManager.java
+++ b/core/java/android/accounts/AccountManager.java
@@ -43,36 +43,92 @@ import java.util.Map;
import com.google.android.collect.Maps;
/**
- * A class that helps with interactions with the AccountManager Service. It provides
- * methods to allow for account, password, and authtoken management for all accounts on the
- * device. One accesses the {@link AccountManager} by calling:
- * <pre>
- * AccountManager accountManager = AccountManager.get(context);
- * </pre>
+ * This class provides access to a centralized registry of the user's
+ * online accounts. With this service, users only need to enter their
+ * credentials (username and password) once for any account, granting
+ * applications access to online resources with "one-click" approval.
*
- * <p>
- * The AccountManager Service provides storage for the accounts known to the system,
- * provides methods to manage them, and allows the registration of authenticators to
- * which operations such as addAccount and getAuthToken are delegated.
- * <p>
- * Many of the calls take an {@link AccountManagerCallback} and {@link Handler} as parameters.
- * These calls return immediately but run asynchronously. If a callback is provided then
- * {@link AccountManagerCallback#run} will be invoked wen the request completes, successfully
- * or not. An {@link AccountManagerFuture} is returned by these requests and also passed into the
- * callback. The result if retrieved by calling {@link AccountManagerFuture#getResult()} which
- * either returns the result or throws an exception as appropriate.
- * <p>
- * The asynchronous request can be made blocking by not providing a callback and instead
- * calling {@link AccountManagerFuture#getResult()} on the future that is returned. This will
- * cause the running thread to block until the result is returned. Keep in mind that one
- * should not block the main thread in this way. Instead one should either use a callback,
- * thus making the call asynchronous, or make the blocking call on a separate thread.
- * getResult() will throw an {@link IllegalStateException} if you call it from the main thread
- * before the request has completed, i.e. before the callback has been invoked.
- * <p>
- * If one wants to ensure that the callback is invoked from a specific handler then they should
- * pass the handler to the request. This makes it easier to ensure thread-safety by running
- * all of one's logic from a single handler.
+ * <p>Different online services have different ways of handling accounts and
+ * authentication, so the account manager uses pluggable <em>authenticator</em>
+ * modules for different <em>account types</em>. The authenticators (which
+ * may be written by third parties) handle the actual details of validating
+ * account credentials and storing account information. For example, Google,
+ * Facebook, and Microsoft Exchange each have their own authenticator.
+ *
+ * <p>Many servers support some notion of an <em>authentication token</em>,
+ * which can be used to authenticate a request to the server without sending
+ * the user's actual password. (Auth tokens are normally created with a
+ * separate request which does include the user's credentials.) AccountManager
+ * can generate these auth tokens for applications, so the application doesn't
+ * need to handle passwords directly. Auth tokens are normally reusable, and
+ * cached by AccountManager, but must be refreshed periodically. It's the
+ * responsibility of applications to <em>invalidate</em> auth tokens when they
+ * stop working so the AccountManager knows it needs to regenerate them.
+ *
+ * <p>Applications accessing a server normally go through these steps:
+ *
+ * <ul>
+ * <li>Get an instance of AccountManager using {@link #get(Context)}.
+ *
+ * <li>List the available accounts using {@link #getAccountsByType} or
+ * {@link #getAccountsByTypeAndFeatures}. Normally applications will only
+ * be interested in accounts with one particular <em>type</em>, which
+ * identifies the authenticator. Account <em>features</em> are used to
+ * identify particular account subtypes and capabilities. Both the account
+ * type and features are authenticator-specific strings, and must be known by
+ * the application in coordination with its preferred authenticators.
+ *
+ * <li>Select one or more of the available accounts, possibly by asking the
+ * user for their preference. If no suitable accounts are available,
+ * {@link #addAccount} may be called to prompt the user to create an
+ * account of the appropriate type.
+ *
+ * <li>Request an auth token for the selected account(s) using one of the
+ * {@link #getAuthToken} methods or related helpers. Refer to the description
+ * of each method for exact usage and error handling details.
+ *
+ * <li>Make the request using the auth token. The form of the auth token,
+ * the format of the request, and the protocol used are all specific to the
+ * service you are accessing. The application makes the request itself, using
+ * whatever network and protocol libraries are useful.
+ *
+ * <li><b>Important:</b> If the request fails with an authentication error,
+ * it could be that a cached auth token is stale and no longer honored by
+ * the server. The application must call {@link #invalidateAuthToken} to remove
+ * the token from the cache, otherwise requests will continue failing! After
+ * invalidating the auth token, immediately go back to the "Request an auth
+ * token" step above. If the process fails the second time, then it can be
+ * treated as a "genuine" authentication failure and the user notified or other
+ * appropriate actions taken.
+ * </ul>
+ *
+ * <p>Some AccountManager methods may require interaction with the user to
+ * prompt for credentials, present options, or ask the user to add an account.
+ * The caller may choose whether to allow AccountManager to directly launch the
+ * necessary user interface and wait for the user, or to return an Intent which
+ * the caller may use to launch the interface, or (in some cases) to install a
+ * notification which the user can select at any time to launch the interface.
+ * To have AccountManager launch the interface directly, the caller must supply
+ * the current foreground {@link Activity} context.
+ *
+ * <p>Many AccountManager methods take {@link AccountManagerCallback} and
+ * {@link Handler} as parameters. These methods return immediately but
+ * run asynchronously. If a callback is provided then
+ * {@link AccountManagerCallback#run} will be invoked on the Handler's
+ * thread when the request completes, successfully or not.
+ * An {@link AccountManagerFuture} is returned by these requests and also
+ * supplied to the callback (if any). The result is retrieved by calling
+ * {@link AccountManagerFuture#getResult()} which waits for the operation
+ * to complete (if necessary) and either returns the result or throws an
+ * exception if an error occurred during the operation.
+ * To make the request synchronously, call
+ * {@link AccountManagerFuture#getResult()} immediately on receiving the
+ * future from the method. No callback need be supplied.
+ *
+ * <p>Requests which may block, including
+ * {@link AccountManagerFuture#getResult()}, must never be called on
+ * the application's main event thread. These operations throw
+ * {@link IllegalStateException} if they are used on the main thread.
*/
public class AccountManager {
private static final String TAG = "AccountManager";
@@ -85,34 +141,65 @@ public class AccountManager {
public static final int ERROR_CODE_BAD_ARGUMENTS = 7;
public static final int ERROR_CODE_BAD_REQUEST = 8;
- public static final String KEY_ACCOUNTS = "accounts";
- public static final String KEY_AUTHENTICATOR_TYPES = "authenticator_types";
- public static final String KEY_USERDATA = "userdata";
- public static final String KEY_AUTHTOKEN = "authtoken";
- public static final String KEY_PASSWORD = "password";
+ /**
+ * The Bundle key used for the {@link String} account name in results
+ * from methods which return information about a particular account.
+ */
public static final String KEY_ACCOUNT_NAME = "authAccount";
+
+ /**
+ * The Bundle key used for the {@link String} account type in results
+ * from methods which return information about a particular account.
+ */
public static final String KEY_ACCOUNT_TYPE = "accountType";
- public static final String KEY_ERROR_CODE = "errorCode";
- public static final String KEY_ERROR_MESSAGE = "errorMessage";
+
+ /**
+ * The Bundle key used for the auth token value in results
+ * from {@link #getAuthToken} and friends.
+ */
+ public static final String KEY_AUTHTOKEN = "authtoken";
+
+ /**
+ * The Bundle key used for an {@link Intent} in results from methods that
+ * may require the caller to interact with the user. The Intent can
+ * be used to start the corresponding user interface activity.
+ */
public static final String KEY_INTENT = "intent";
- public static final String KEY_BOOLEAN_RESULT = "booleanResult";
+
+ /**
+ * The Bundle key used to supply the password directly in options to
+ * {@link #confirmCredentials}, rather than prompting the user with
+ * the standard password prompt.
+ */
+ public static final String KEY_PASSWORD = "password";
+
+ public static final String KEY_ACCOUNTS = "accounts";
public static final String KEY_ACCOUNT_AUTHENTICATOR_RESPONSE = "accountAuthenticatorResponse";
public static final String KEY_ACCOUNT_MANAGER_RESPONSE = "accountManagerResponse";
+ public static final String KEY_AUTHENTICATOR_TYPES = "authenticator_types";
public static final String KEY_AUTH_FAILED_MESSAGE = "authFailedMessage";
public static final String KEY_AUTH_TOKEN_LABEL = "authTokenLabelKey";
+ public static final String KEY_BOOLEAN_RESULT = "booleanResult";
+ public static final String KEY_ERROR_CODE = "errorCode";
+ public static final String KEY_ERROR_MESSAGE = "errorMessage";
+ public static final String KEY_USERDATA = "userdata";
+
public static final String ACTION_AUTHENTICATOR_INTENT =
"android.accounts.AccountAuthenticator";
public static final String AUTHENTICATOR_META_DATA_NAME =
- "android.accounts.AccountAuthenticator";
+ "android.accounts.AccountAuthenticator";
public static final String AUTHENTICATOR_ATTRIBUTES_NAME = "account-authenticator";
private final Context mContext;
private final IAccountManager mService;
private final Handler mMainHandler;
+
/**
* Action sent as a broadcast Intent by the AccountsService
- * when accounts are added to and/or removed from the device's
- * database.
+ * when accounts are added, accounts are removed, or an
+ * account's credentials (saved password, etc) are changed.
+ *
+ * @see #addOnAccountsUpdatedListener
*/
public static final String LOGIN_ACCOUNTS_CHANGED_ACTION =
"android.accounts.LOGIN_ACCOUNTS_CHANGED";
@@ -136,26 +223,36 @@ public class AccountManager {
}
/**
- * Retrieve an AccountManager instance that is associated with the context that is passed in.
- * Certain calls such as {@link #addOnAccountsUpdatedListener} use this context internally,
- * so the caller must take care to use a {@link Context} whose lifetime is associated with
- * the listener registration.
+ * Gets an AccountManager instance associated with a Context.
+ * The {@link Context} will be used as long as the AccountManager is
+ * active, so make sure to use a {@link Context} whose lifetime is
+ * commensurate with any listeners registered to
+ * {@link #addOnAccountsUpdatedListener} or similar methods.
+ *
+ * <p>It is safe to call this method from the main thread.
+ *
+ * <p>No permission is required to call this method.
+ *
* @param context The {@link Context} to use when necessary
- * @return an {@link AccountManager} instance that is associated with context
+ * @return An {@link AccountManager} instance
*/
public static AccountManager get(Context context) {
return (AccountManager) context.getSystemService(Context.ACCOUNT_SERVICE);
}
/**
- * Get the password that is associated with the account. Returns null if the account does
- * not exist.
- * <p>
- * It is safe to call this method from the main thread.
- * <p>
- * Requires that the caller has permission
- * {@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS} and is running
- * with the same UID as the Authenticator for the account.
+ * Gets the saved password associated with the account.
+ * This is intended for authenticators and related code; applications
+ * should get an auth token instead.
+ *
+ * <p>It is safe to call this method from the main thread.
+ *
+ * <p>This method requires the caller to hold the permission
+ * {@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS}
+ * and to have the same UID as the account's authenticator.
+ *
+ * @param account The account to query for a password
+ * @return The account's password, null if none or if the account doesn't exist
*/
public String getPassword(final Account account) {
try {
@@ -167,14 +264,19 @@ public class AccountManager {
}
/**
- * Get the user data named by "key" that is associated with the account.
- * Returns null if the account does not exist or if it does not have a value for key.
- * <p>
- * It is safe to call this method from the main thread.
- * <p>
- * Requires that the caller has permission
- * {@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS} and is running
- * with the same UID as the Authenticator for the account.
+ * Gets the user data named by "key" associated with the account.
+ * This is intended for authenticators and related code to store
+ * arbitrary metadata along with accounts. The meaning of the keys
+ * and values is up to the authenticator for the account.
+ *
+ * <p>It is safe to call this method from the main thread.
+ *
+ * <p>This method requires the caller to hold the permission
+ * {@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS}
+ * and to have the same UID as the account's authenticator.
+ *
+ * @param account The account to query for user data
+ * @return The user data, null if the account or key doesn't exist
*/
public String getUserData(final Account account, final String key) {
try {
@@ -186,14 +288,15 @@ public class AccountManager {
}
/**
- * Query the AccountManager Service for an array that contains a
- * {@link AuthenticatorDescription} for each registered authenticator.
- * @return an array that contains all the authenticators known to the AccountManager service.
- * This array will be empty if there are no authenticators and will never return null.
- * <p>
- * It is safe to call this method from the main thread.
- * <p>
- * No permission is required to make this call.
+ * Lists the currently registered authenticators.
+ *
+ * <p>It is safe to call this method from the main thread.
+ *
+ * <p>No permission is required to call this method.
+ *
+ * @return An array of {@link AuthenticatorDescription} for every
+ * authenticator known to the AccountManager service. Empty (never
+ * null) if no authenticators are known.
*/
public AuthenticatorDescription[] getAuthenticatorTypes() {
try {
@@ -205,13 +308,16 @@ public class AccountManager {
}
/**
- * Query the AccountManager Service for all accounts.
- * @return an array that contains all the accounts known to the AccountManager service.
- * This array will be empty if there are no accounts and will never return null.
- * <p>
- * It is safe to call this method from the main thread.
- * <p>
- * Requires that the caller has permission {@link android.Manifest.permission#GET_ACCOUNTS}
+ * Lists all accounts of any type registered on the device.
+ * Equivalent to getAccountsByType(null).
+ *
+ * <p>It is safe to call this method from the main thread.
+ *
+ * <p>This method requires the caller to hold the permission
+ * {@link android.Manifest.permission#GET_ACCOUNTS}.
+ *
+ * @return An array of {@link Account}, one for each account. Empty
+ * (never null) if no accounts have been added.
*/
public Account[] getAccounts() {
try {
@@ -223,15 +329,20 @@ public class AccountManager {
}
/**
- * Query the AccountManager for the set of accounts that have a given type. If null
- * is passed as the type than all accounts are returned.
- * @param type the account type by which to filter, or null to get all accounts
- * @return an array that contains the accounts that match the specified type. This array
- * will be empty if no accounts match. It will never return null.
- * <p>
- * It is safe to call this method from the main thread.
- * <p>
- * Requires that the caller has permission {@link android.Manifest.permission#GET_ACCOUNTS}
+ * Lists all accounts of a particular type. The account type is a
+ * string token corresponding to the authenticator and useful domain
+ * of the account. For example, there are types corresponding to Google
+ * and Facebook. The exact string token to use will be published somewhere
+ * associated with the authenticator in question.
+ *
+ * <p>It is safe to call this method from the main thread.
+ *
+ * <p>This method requires the caller to hold the permission
+ * {@link android.Manifest.permission#GET_ACCOUNTS}.
+ *
+ * @param type The type of accounts to return, null to retrieve all accounts
+ * @return An array of {@link Account}, one per matching account. Empty
+ * (never null) if no accounts of the specified type have been added.
*/
public Account[] getAccountsByType(String type) {
try {
@@ -243,45 +354,27 @@ public class AccountManager {
}
/**
- * Tests that the given account has the specified features. If this account does not exist
- * then this call returns false.
- * <p>
- * This call returns immediately but runs asynchronously and the result is accessed via the
- * {@link AccountManagerFuture} that is returned. This future is also passed as the sole
- * parameter to the {@link AccountManagerCallback}. If the caller wished to use this
- * method asynchronously then they will generally pass in a callback object that will get
- * invoked with the {@link AccountManagerFuture}. If they wish to use it synchronously then
- * they will generally pass null for the callback and instead call
- * {@link android.accounts.AccountManagerFuture#getResult()} on this method's return value,
- * which will then block until the request completes.
- * <p>
- * Do not block the main thread waiting this method's result.
- * <p>
- * Not allowed from main thread (but allowed from other threads):
- * <pre>
- * Boolean result = hasFeatures(account, features, callback, handler).getResult();
- * </pre>
- * Allowed from main thread:
- * <pre>
- * hasFeatures(account, features, new AccountManagerCallback<Boolean>() {
- * public void run(AccountManagerFuture<Boolean> future) {
- * Boolean result = future.getResult();
- * // use result
- * }
- * }, handler);
- * </pre>
- * <p>
- * Requires that the caller has permission {@link android.Manifest.permission#GET_ACCOUNTS}.
+ * Finds out whether a particular account has all the specified features.
+ * Account features are authenticator-specific string tokens identifying
+ * boolean account properties. For example, features are used to tell
+ * whether Google accounts have a particular service (such as Google
+ * Calendar or Google Talk) enabled. The feature names and their meanings
+ * are published somewhere associated with the authenticator in question.
+ *
+ * <p>This method may be called from any thread, but the returned
+ * {@link AccountManagerFuture} must not be used on the main thread.
+ *
+ * <p>This method requires the caller to hold the permission
+ * {@link android.Manifest.permission#GET_ACCOUNTS}.
*
* @param account The {@link Account} to test
- * @param features the features for which to test
- * @param callback A callback to invoke when the request completes. If null then
- * no callback is invoked.
- * @param handler The {@link Handler} to use to invoke the callback. If null then the
- * main thread's {@link Handler} is used.
- * @return an {@link AccountManagerFuture} that represents the future result of the call.
- * The future result is a {@link Boolean} that is true if the account exists and has the
- * specified features.
+ * @param features An array of the account features to check
+ * @param callback Callback to invoke when the request completes,
+ * null for no callback
+ * @param handler {@link Handler} identifying the callback thread,
+ * null for the main thread
+ * @return An {@link AccountManagerFuture} which resolves to a Boolean,
+ * true if the account exists and has all of the specified features.
*/
public AccountManagerFuture<Boolean> hasFeatures(final Account account,
final String[] features,
@@ -300,18 +393,73 @@ public class AccountManager {
}
/**
- * Add an account to the AccountManager's set of known accounts.
- * <p>
- * It is safe to call this method from the main thread.
- * <p>
- * Requires that the caller has permission
- * {@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS} and is running
- * with the same UID as the Authenticator for the account.
- * @param account The account to add
- * @param password The password to associate with the account. May be null.
- * @param userdata A bundle of key/value pairs to set as the account's userdata. May be null.
- * @return true if the account was sucessfully added, false otherwise, for example,
- * if the account already exists or if the account is null
+ * Lists all accounts of a type which have certain features. The account
+ * type identifies the authenticator (see {@link #getAccountsByType}).
+ * Account features are authenticator-specific string tokens identifying
+ * boolean account properties (see {@link #hasFeatures}).
+ *
+ * <p>Unlike {@link #getAccountsByType}, this method calls the authenticator,
+ * which may contact the server or do other work to check account features,
+ * so the method returns an {@link AccountManagerFuture}.
+ *
+ * <p>This method may be called from any thread, but the returned
+ * {@link AccountManagerFuture} must not be used on the main thread.
+ *
+ * <p>This method requires the caller to hold the permission
+ * {@link android.Manifest.permission#GET_ACCOUNTS}.
+ *
+ * @param type The type of accounts to return, must not be null
+ * @param features An array of the account features to require,
+ * may be null or empty
+ * @param callback Callback to invoke when the request completes,
+ * null for no callback
+ * @param handler {@link Handler} identifying the callback thread,
+ * null for the main thread
+ * @return An {@link AccountManagerFuture} which resolves to an array of
+ * {@link Account}, one per account of the specified type which
+ * matches the requested features.
+ */
+ public AccountManagerFuture<Account[]> getAccountsByTypeAndFeatures(
+ final String type, final String[] features,
+ AccountManagerCallback<Account[]> callback, Handler handler) {
+ return new Future2Task<Account[]>(handler, callback) {
+ public void doWork() throws RemoteException {
+ if (type == null) {
+ Log.e(TAG, "Type is null");
+ set(new Account[0]);
+ return;
+ }
+ mService.getAccountsByFeatures(mResponse, type, features);
+ }
+ public Account[] bundleToResult(Bundle bundle) throws AuthenticatorException {
+ if (!bundle.containsKey(KEY_ACCOUNTS)) {
+ throw new AuthenticatorException("no result in response");
+ }
+ final Parcelable[] parcelables = bundle.getParcelableArray(KEY_ACCOUNTS);
+ Account[] descs = new Account[parcelables.length];
+ for (int i = 0; i < parcelables.length; i++) {
+ descs[i] = (Account) parcelables[i];
+ }
+ return descs;
+ }
+ }.start();
+ }
+
+ /**
+ * Adds an account directly to the AccountManager. Normally used by sign-up
+ * wizards associated with authenticators, not directly by applications.
+ *
+ * <p>It is safe to call this method from the main thread.
+ *
+ * <p>This method requires the caller to hold the permission
+ * {@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS}
+ * and to have the same UID as the added account's authenticator.
+ *
+ * @param account The {@link Account} to add
+ * @param password The password to associate with the account, null for none
+ * @param userdata String values to use for the account's userdata, null for none
+ * @return Whether the account was successfully added. False if the account
+ * already exists, the account is null, or another error occurs.
*/
public boolean addAccountExplicitly(Account account, String password, Bundle userdata) {
try {
@@ -323,43 +471,25 @@ public class AccountManager {
}
/**
- * Removes the given account. If this account does not exist then this call has no effect.
- * <p>
- * This call returns immediately but runs asynchronously and the result is accessed via the
- * {@link AccountManagerFuture} that is returned. This future is also passed as the sole
- * parameter to the {@link AccountManagerCallback}. If the caller wished to use this
- * method asynchronously then they will generally pass in a callback object that will get
- * invoked with the {@link AccountManagerFuture}. If they wish to use it synchronously then
- * they will generally pass null for the callback and instead call
- * {@link android.accounts.AccountManagerFuture#getResult()} on this method's return value,
- * which will then block until the request completes.
- * <p>
- * Do not block the main thread waiting this method's result.
- * <p>
- * Not allowed from main thread (but allowed from other threads):
- * <pre>
- * Boolean result = removeAccount(account, callback, handler).getResult();
- * </pre>
- * Allowed from main thread:
- * <pre>
- * removeAccount(account, new AccountManagerCallback<Boolean>() {
- * public void run(AccountManagerFuture<Boolean> future) {
- * Boolean result = future.getResult();
- * // use result
- * }
- * }, handler);
- * </pre>
- * <p>
- * Requires that the caller has permission {@link android.Manifest.permission#MANAGE_ACCOUNTS}.
+ * Removes an account from the AccountManager. Does nothing if the account
+ * does not exist. Does not delete the account from the server.
+ * The authenticator may have its own policies preventing account
+ * deletion, in which case the account will not be deleted.
+ *
+ * <p>This method may be called from any thread, but the returned
+ * {@link AccountManagerFuture} must not be used on the main thread.
+ *
+ * <p>This method requires the caller to hold the permission
+ * {@link android.Manifest.permission#MANAGE_ACCOUNTS}.
*
* @param account The {@link Account} to remove
- * @param callback A callback to invoke when the request completes. If null then
- * no callback is invoked.
- * @param handler The {@link Handler} to use to invoke the callback. If null then the
- * main thread's {@link Handler} is used.
- * @return an {@link AccountManagerFuture} that represents the future result of the call.
- * The future result is a {@link Boolean} that is true if the account is successfully removed
- * or false if the authenticator refuses to remove the account.
+ * @param callback Callback to invoke when the request completes,
+ * null for no callback
+ * @param handler {@link Handler} identifying the callback thread,
+ * null for the main thread
+ * @return An {@link AccountManagerFuture} which resolves to a Boolean,
+ * true if the account has been successfully removed,
+ * false if the authenticator forbids deleting this account.
*/
public AccountManagerFuture<Boolean> removeAccount(final Account account,
AccountManagerCallback<Boolean> callback, Handler handler) {
@@ -377,14 +507,20 @@ public class AccountManager {
}
/**
- * Removes the given authtoken. If this authtoken does not exist for the given account type
- * then this call has no effect.
- * <p>
- * It is safe to call this method from the main thread.
- * <p>
- * Requires that the caller has permission {@link android.Manifest.permission#MANAGE_ACCOUNTS}.
- * @param accountType the account type of the authtoken to invalidate
- * @param authToken the authtoken to invalidate
+ * Removes an auth token from the AccountManager's cache. Does nothing if
+ * the auth token is not currently in the cache. Applications must call this
+ * method when the auth token is found to have expired or otherwise become
+ * invalid for authenticating requests. The AccountManager does not validate
+ * or expire cached auth tokens otherwise.
+ *
+ * <p>It is safe to call this method from the main thread.
+ *
+ * <p>This method requires the caller to hold the permission
+ * {@link android.Manifest.permission#MANAGE_ACCOUNTS} or
+ * {@link android.Manifest.permission#USE_CREDENTIALS}
+ *
+ * @param accountType The account type of the auth token to invalidate
+ * @param authToken The auth token to invalidate
*/
public void invalidateAuthToken(final String accountType, final String authToken) {
try {
@@ -396,20 +532,21 @@ public class AccountManager {
}
/**
- * Gets the authtoken named by "authTokenType" for the specified account if it is cached
- * by the AccountManager. If no authtoken is cached then null is returned rather than
- * asking the authenticaticor to generate one. If the account or the
- * authtoken do not exist then null is returned.
- * <p>
- * It is safe to call this method from the main thread.
- * <p>
- * Requires that the caller has permission
- * {@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS} and is running
- * with the same UID as the Authenticator for the account.
- * @param account the account whose authtoken is to be retrieved, must not be null
- * @param authTokenType the type of authtoken to retrieve
- * @return an authtoken for the given account and authTokenType, if one is cached by the
- * AccountManager, null otherwise.
+ * Gets an auth token from the AccountManager's cache. If no auth
+ * token is cached for this account, null will be returned -- a new
+ * auth token will not be generated, and the server will not be contacted.
+ * Intended for use by the authenticator, not directly by applications.
+ *
+ * <p>It is safe to call this method from the main thread.
+ *
+ * <p>This method requires the caller to hold the permission
+ * {@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS}
+ * and to have the same UID as the account's authenticator.
+ *
+ * @param account The account to fetch an auth token for
+ * @param authTokenType The type of auth token to fetch, see {#getAuthToken}
+ * @return The cached auth token for this account and type, or null if
+ * no auth token is cached or the account does not exist.
*/
public String peekAuthToken(final Account account, final String authTokenType) {
if (account == null) {
@@ -428,16 +565,19 @@ public class AccountManager {
}
/**
- * Sets the password for the account. The password may be null. If the account does not exist
- * then this call has no affect.
- * <p>
- * It is safe to call this method from the main thread.
- * <p>
- * Requires that the caller has permission
- * {@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS} and is running
- * with the same UID as the Authenticator for the account.
- * @param account the account whose password is to be set. Must not be null.
- * @param password the password to set for the account. May be null.
+ * Sets or forgets a saved password. This modifies the local copy of the
+ * password used to automatically authenticate the user; it does
+ * not change the user's account password on the server. Intended for use
+ * by the authenticator, not directly by applications.
+ *
+ * <p>It is safe to call this method from the main thread.
+ *
+ * <p>This method requires the caller to hold the permission
+ * {@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS}
+ * and have the same UID as the account's authenticator.
+ *
+ * @param account The account to set a password for
+ * @param password The password to set, null to clear the password
*/
public void setPassword(final Account account, final String password) {
if (account == null) {
@@ -453,13 +593,18 @@ public class AccountManager {
}
/**
- * Sets the password for account to null. If the account does not exist then this call
- * has no effect.
- * <p>
- * It is safe to call this method from the main thread.
- * <p>
- * Requires that the caller has permission {@link android.Manifest.permission#MANAGE_ACCOUNTS}.
- * @param account the account whose password is to be cleared. Must not be null.
+ * Forgets a saved password. This erases the local copy of the password;
+ * it does not change the user's account password on the server.
+ * Has the same effect as setPassword(account, null) but requires fewer
+ * permissions, and may be used by applications or management interfaces
+ * to "sign out" from an account.
+ *
+ * <p>It is safe to call this method from the main thread.
+ *
+ * <p>This method requires the caller to hold the permission
+ * {@link android.Manifest.permission#MANAGE_ACCOUNTS}
+ *
+ * @param account The account whose password to clear
*/
public void clearPassword(final Account account) {
if (account == null) {
@@ -475,17 +620,19 @@ public class AccountManager {
}
/**
- * Sets account's userdata named "key" to the specified value. If the account does not
- * exist then this call has no effect.
- * <p>
- * It is safe to call this method from the main thread.
- * <p>
- * Requires that the caller has permission
- * {@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS} and is running
- * with the same UID as the Authenticator for the account.
- * @param account the account whose userdata is to be set. Must not be null.
- * @param key the key of the userdata to set. Must not be null.
- * @param value the value to set. May be null.
+ * Sets one userdata key for an account. Intended by use for the
+ * authenticator to stash state for itself, not directly by applications.
+ * The meaning of the keys and values is up to the authenticator.
+ *
+ * <p>It is safe to call this method from the main thread.
+ *
+ * <p>This method requires the caller to hold the permission
+ * {@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS}
+ * and to have the same UID as the account's authenticator.
+ *
+ * @param account The account to set the userdata for
+ * @param key The userdata key to set. Must not be null
+ * @param value The value to set, null to clear this userdata key
*/
public void setUserData(final Account account, final String key, final String value) {
if (account == null) {
@@ -505,17 +652,20 @@ public class AccountManager {
}
/**
- * Sets the authtoken named by "authTokenType" to the value specified by authToken.
+ * Adds an auth token to the AccountManager cache for an account.
* If the account does not exist then this call has no effect.
- * <p>
- * It is safe to call this method from the main thread.
- * <p>
- * Requires that the caller has permission
- * {@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS} and is running
- * with the same UID as the Authenticator for the account.
- * @param account the account whose authtoken is to be set. Must not be null.
- * @param authTokenType the type of the authtoken to set. Must not be null.
- * @param authToken the authToken to set. May be null.
+ * Replaces any previous auth token for this account and auth token type.
+ * Intended for use by the authenticator, not directly by applications.
+ *
+ * <p>It is safe to call this method from the main thread.
+ *
+ * <p>This method requires the caller to hold the permission
+ * {@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS}
+ * and to have the same UID as the account's authenticator.
+ *
+ * @param account The account to set an auth token for
+ * @param authTokenType The type of the auth token, see {#getAuthToken}
+ * @param authToken The auth token to add to the cache
*/
public void setAuthToken(Account account, final String authTokenType, final String authToken) {
try {
@@ -527,25 +677,27 @@ public class AccountManager {
}
/**
- * Convenience method that makes a blocking call to
- * {@link #getAuthToken(Account, String, boolean, AccountManagerCallback, Handler)}
- * then extracts and returns the value of {@link #KEY_AUTHTOKEN} from its result.
- * <p>
- * It is not safe to call this method from the main thread. See {@link #getAuthToken}.
- * <p>
- * Requires that the caller has permission {@link android.Manifest.permission#USE_CREDENTIALS}.
- * @param account the account whose authtoken is to be retrieved, must not be null
- * @param authTokenType the type of authtoken to retrieve
- * @param notifyAuthFailure if true, cause the AccountManager to put up a "sign-on" notification
- * for the account if no authtoken is cached by the AccountManager and the the authenticator
- * does not have valid credentials to get an authtoken.
- * @return an authtoken for the given account and authTokenType, if one is cached by the
- * AccountManager, null otherwise.
- * @throws AuthenticatorException if the authenticator is not present, unreachable or returns
- * an invalid response.
- * @throws OperationCanceledException if the request is canceled for any reason
- * @throws java.io.IOException if the authenticator experiences an IOException while attempting
- * to communicate with its backend server.
+ * This convenience helper synchronously gets an auth token with
+ * {@link #getAuthToken(Account, String, boolean, AccountManagerCallback, Handler)}.
+ *
+ * <p>This method may block while a network request completes, and must
+ * never be made from the main thread.
+ *
+ * <p>This method requires the caller to hold the permission
+ * {@link android.Manifest.permission#USE_CREDENTIALS}.
+ *
+ * @param account The account to fetch an auth token for
+ * @param authTokenType The auth token type, see {#link getAuthToken}
+ * @param notifyAuthFailure If true, display a notification and return null
+ * if authentication fails; if false, prompt and wait for the user to
+ * re-enter correct credentials before returning
+ * @return An auth token of the specified type for this account, or null
+ * if authentication fails or none can be fetched.
+ * @throws AuthenticatorException if the authenticator failed to respond
+ * @throws OperationCanceledException if the request was canceled for any
+ * reason, including the user canceling a credential request
+ * @throws java.io.IOException if the authenticator experienced an I/O problem
+ * creating a new auth token, usually because of network trouble
*/
public String blockingGetAuthToken(Account account, String authTokenType,
boolean notifyAuthFailure)
@@ -556,64 +708,57 @@ public class AccountManager {
}
/**
- * Request that an authtoken of the specified type be returned for an account.
- * If the Account Manager has a cached authtoken of the requested type then it will
- * service the request itself. Otherwise it will pass the request on to the authenticator.
- * The authenticator can try to service this request with information it already has stored
- * in the AccountManager but may need to launch an activity to prompt the
- * user to enter credentials. If it is able to retrieve the authtoken it will be returned
- * in the result.
- * <p>
- * If the authenticator needs to prompt the user for credentials it will return an intent to
- * an activity that will do the prompting. The supplied activity will be used to launch the
- * intent and the result will come from the launched activity.
- * <p>
- * This call returns immediately but runs asynchronously and the result is accessed via the
- * {@link AccountManagerFuture} that is returned. This future is also passed as the sole
- * parameter to the {@link AccountManagerCallback}. If the caller wished to use this
- * method asynchronously then they will generally pass in a callback object that will get
- * invoked with the {@link AccountManagerFuture}. If they wish to use it synchronously then
- * they will generally pass null for the callback and instead call
- * {@link android.accounts.AccountManagerFuture#getResult()} on this method's return value,
- * which will then block until the request completes.
- * <p>
- * Do not block the main thread waiting this method's result.
- * <p>
- * Not allowed from main thread (but allowed from other threads):
- * <pre>
- * Bundle result = getAuthToken(
- * account, authTokenType, options, activity, callback, handler).getResult();
- * </pre>
- * Allowed from main thread:
- * <pre>
- * getAuthToken(account, authTokenType, options, activity, new AccountManagerCallback<Bundle>() {
- * public void run(AccountManagerFuture<Bundle> future) {
- * Bundle result = future.getResult();
- * // use result
- * }
- * }, handler);
- * </pre>
- * <p>
- * Requires that the caller has permission {@link android.Manifest.permission#USE_CREDENTIALS}.
- *
- * @param account The account whose credentials are to be updated.
- * @param authTokenType the auth token to retrieve as part of updating the credentials.
- * May be null.
- * @param options authenticator specific options for the request
- * @param activity If the authenticator returns a {@link #KEY_INTENT} in the result then
- * the intent will be started with this activity. If you do not with to have the intent
- * started automatically then use the other form,
- * {@link #getAuthToken(Account, String, boolean, AccountManagerCallback, android.os.Handler)}
- * @param callback A callback to invoke when the request completes. If null then
- * no callback is invoked.
- * @param handler The {@link Handler} to use to invoke the callback. If null then the
- * main thread's {@link Handler} is used.
- * @return an {@link AccountManagerFuture} that represents the future result of the call.
- * The future result is a {@link Bundle} that contains:
+ * Gets an auth token of the specified type for a particular account,
+ * prompting the user for credentials if necessary. This method is
+ * intended for applications running in the foreground where it makes
+ * sense to ask the user directly for a password.
+ *
+ * <p>If a previously generated auth token is cached for this account and
+ * type, then it will be returned. Otherwise, if we have a saved password
+ * the server accepts, it will be used to generate a new auth token.
+ * Otherwise, the user will be asked for a password, which will be sent to
+ * the server to generate a new auth token.
+ *
+ * <p>The value of the auth token type depends on the authenticator.
+ * Some services use different tokens to access different functionality --
+ * for example, Google uses different auth tokens to access Gmail and
+ * Google Calendar for the same account.
+ *
+ * <p>This method may be called from any thread, but the returned
+ * {@link AccountManagerFuture} must not be used on the main thread.
+ *
+ * <p>This method requires the caller to hold the permission
+ * {@link android.Manifest.permission#USE_CREDENTIALS}.
+ *
+ * @param account The account to fetch an auth token for
+ * @param authTokenType The auth token type, an authenticator-dependent
+ * string token, must not be null
+ * @param options Authenticator-specific options for the request,
+ * may be null or empty
+ * @param activity The {@link Activity} context to use for launching a new
+ * authenticator-defined sub-Activity to prompt the user for a password
+ * if necessary; used only to call startActivity(); must not be null.
+ * @param callback Callback to invoke when the request completes,
+ * null for no callback
+ * @param handler {@link Handler} identifying the callback thread,
+ * null for the main thread
+ * @return An {@link AccountManagerFuture} which resolves to a Bundle with
+ * at least the following fields:
+ * <ul>
+ * <li> {@link #KEY_ACCOUNT_NAME} - the name of the account you supplied
+ * <li> {@link #KEY_ACCOUNT_TYPE} - the type of the account
+ * <li> {@link #KEY_AUTHTOKEN} - the auth token you wanted
+ * </ul>
+ *
+ * (Other authenticator-specific values may be returned.) If an auth token
+ * could not be fetched, {@link AccountManagerFuture#getResult()} throws:
* <ul>
- * <li> {@link #KEY_ACCOUNT_NAME}, {@link #KEY_ACCOUNT_TYPE} and {@link #KEY_AUTHTOKEN}
+ * <li> {@link AuthenticatorException} if the authenticator failed to respond
+ * <li> {@link OperationCanceledException} if the operation is canceled for
+ * any reason, incluidng the user canceling a credential request
+ * <li> {@link IOException} if the authenticator experienced an I/O problem
+ * creating a new auth token, usually because of network trouble
* </ul>
- * If the user presses "back" then the request will be canceled.
*/
public AccountManagerFuture<Bundle> getAuthToken(
final Account account, final String authTokenType, final Bundle options,
@@ -630,67 +775,71 @@ public class AccountManager {
}
/**
- * Request that an authtoken of the specified type be returned for an account.
- * If the Account Manager has a cached authtoken of the requested type then it will
- * service the request itself. Otherwise it will pass the request on to the authenticator.
- * The authenticator can try to service this request with information it already has stored
- * in the AccountManager but may need to launch an activity to prompt the
- * user to enter credentials. If it is able to retrieve the authtoken it will be returned
- * in the result.
- * <p>
- * If the authenticator needs to prompt the user for credentials, rather than returning the
- * authtoken it will instead return an intent for
- * an activity that will do the prompting. If an intent is returned and notifyAuthFailure
- * is true then a notification will be created that launches this intent. This intent can be
- * invoked by the caller directly to start the activity that prompts the user for the
- * updated credentials. Otherwise this activity will not be run until the user activates
- * the notification.
- * <p>
- * This call returns immediately but runs asynchronously and the result is accessed via the
- * {@link AccountManagerFuture} that is returned. This future is also passed as the sole
- * parameter to the {@link AccountManagerCallback}. If the caller wished to use this
- * method asynchronously then they will generally pass in a callback object that will get
- * invoked with the {@link AccountManagerFuture}. If they wish to use it synchronously then
- * they will generally pass null for the callback and instead call
- * {@link android.accounts.AccountManagerFuture#getResult()} on this method's return value,
- * which will then block until the request completes.
- * <p>
- * Do not block the main thread waiting this method's result.
- * <p>
- * Not allowed from main thread (but allowed from other threads):
- * <pre>
- * Bundle result = getAuthToken(
- * account, authTokenType, notifyAuthFailure, callback, handler).getResult();
- * </pre>
- * Allowed from main thread:
- * <pre>
- * getAuthToken(account, authTokenType, notifyAuthFailure, new AccountManagerCallback<Bundle>() {
- * public void run(AccountManagerFuture<Bundle> future) {
- * Bundle result = future.getResult();
- * // use result
- * }
- * }, handler);
- * </pre>
- * <p>
- * Requires that the caller has permission {@link android.Manifest.permission#USE_CREDENTIALS}.
- *
- * @param account The account whose credentials are to be updated.
- * @param authTokenType the auth token to retrieve as part of updating the credentials.
- * May be null.
- * @param notifyAuthFailure if true and the authenticator returns a {@link #KEY_INTENT} in the
- * result then a "sign-on needed" notification will be created that will launch this intent.
- * @param callback A callback to invoke when the request completes. If null then
- * no callback is invoked.
- * @param handler The {@link Handler} to use to invoke the callback. If null then the
- * main thread's {@link Handler} is used.
- * @return an {@link AccountManagerFuture} that represents the future result of the call.
- * The future result is a {@link Bundle} that contains either:
+ * Gets an auth token of the specified type for a particular account,
+ * optionally raising a notification if the user must enter credentials.
+ * This method is intended for background tasks and services where the
+ * user should not be immediately interrupted with a password prompt.
+ *
+ * <p>If a previously generated auth token is cached for this account and
+ * type, then it will be returned. Otherwise, if we have saved credentials
+ * the server accepts, it will be used to generate a new auth token.
+ * Otherwise, an Intent will be returned which, when started, will prompt
+ * the user for a password. If the notifyAuthFailure parameter is set,
+ * the same Intent will be associated with a status bar notification,
+ * alerting the user that they need to enter a password at some point.
+ *
+ * <p>If the intent is left in a notification, you will need to wait until
+ * the user gets around to entering a password before trying again,
+ * which could be hours or days or never. When it does happen, the
+ * account manager will broadcast the {@link #LOGIN_ACCOUNTS_CHANGED_ACTION}
+ * {@link Intent}, which applications can use to trigger another attempt
+ * to fetch an auth token.
+ *
+ * <p>If notifications are not enabled, it is the application's
+ * responsibility to launch the returned intent at some point to let
+ * the user enter credentials. In either case, the result from this
+ * call will not wait for user action.
+ *
+ * <p>The value of the auth token type depends on the authenticator.
+ * Some services use different tokens to access different functionality --
+ * for example, Google uses different auth tokens to access Gmail and
+ * Google Calendar for the same account.
+ *
+ * <p>This method may be called from any thread, but the returned
+ * {@link AccountManagerFuture} must not be used on the main thread.
+ *
+ * <p>This method requires the caller to hold the permission
+ * {@link android.Manifest.permission#USE_CREDENTIALS}.
+ *
+ * @param account The account to fetch an auth token for
+ * @param authTokenType The auth token type, an authenticator-dependent
+ * string token, must not be null
+ * @param notifyAuthFailure True to add a notification to prompt the
+ * user for a password if necessary, false to leave that to the caller
+ * @param callback Callback to invoke when the request completes,
+ * null for no callback
+ * @param handler {@link Handler} identifying the callback thread,
+ * null for the main thread
+ * @return An {@link AccountManagerFuture} which resolves to a Bundle with
+ * at least the following fields on success:
* <ul>
- * <li> {@link #KEY_INTENT}, which is to be used to prompt the user for the credentials
- * <li> {@link #KEY_ACCOUNT_NAME}, {@link #KEY_ACCOUNT_TYPE} and {@link #KEY_AUTHTOKEN}
- * if the authenticator is able to retrieve the auth token
+ * <li> {@link #KEY_ACCOUNT_NAME} - the name of the account you supplied
+ * <li> {@link #KEY_ACCOUNT_TYPE} - the type of the account
+ * <li> {@link #KEY_AUTHTOKEN} - the auth token you wanted
+ * </ul>
+ *
+ * (Other authenticator-specific values may be returned.) If the user
+ * must enter credentials, the returned Bundle contains only
+ * {@link #KEY_INTENT} with the {@link Intent} needed to launch a prompt.
+ *
+ * <p>If an error occurred, {@link AccountManagerFuture#getResult()} throws:
+ * <ul>
+ * <li> {@link AuthenticatorException} if the authenticator failed to respond
+ * <li> {@link OperationCanceledException} if the operation is canceled for
+ * any reason, incluidng the user canceling a credential request
+ * <li> {@link IOException} if the authenticator experienced an I/O problem
+ * creating a new auth token, usually because of network trouble
* </ul>
- * If the user presses "back" then the request will be canceled.
*/
public AccountManagerFuture<Bundle> getAuthToken(
final Account account, final String authTokenType, final boolean notifyAuthFailure,
@@ -706,57 +855,52 @@ public class AccountManager {
}
/**
- * Request that an account be added with the given accountType. This request
- * is processed by the authenticator for the account type. If no authenticator is registered
- * in the system then {@link AuthenticatorException} is thrown.
- * <p>
- * This call returns immediately but runs asynchronously and the result is accessed via the
- * {@link AccountManagerFuture} that is returned. This future is also passed as the sole
- * parameter to the {@link AccountManagerCallback}. If the caller wished to use this
- * method asynchronously then they will generally pass in a callback object that will get
- * invoked with the {@link AccountManagerFuture}. If they wish to use it synchronously then
- * they will generally pass null for the callback and instead call
- * {@link android.accounts.AccountManagerFuture#getResult()} on this method's return value,
- * which will then block until the request completes.
- * <p>
- * Do not block the main thread waiting this method's result.
- * <p>
- * Not allowed from main thread (but allowed from other threads):
- * <pre>
- * Bundle result = addAccount(
- * account, authTokenType, features, options, activity, callback, handler).getResult();
- * </pre>
- * Allowed from main thread:
- * <pre>
- * addAccount(account, authTokenType, features, options, activity, new AccountManagerCallback<Bundle>() {
- * public void run(AccountManagerFuture<Bundle> future) {
- * Bundle result = future.getResult();
- * // use result
- * }
- * }, handler);
- * </pre>
- * <p>
- * Requires that the caller has permission {@link android.Manifest.permission#MANAGE_ACCOUNTS}.
- *
- * @param accountType The type of account to add. This must not be null.
- * @param authTokenType The account that is added should be able to service this auth token
- * type. This may be null.
- * @param requiredFeatures The account that is added should support these features.
- * This array may be null or empty.
- * @param addAccountOptions A bundle of authenticator-specific options that is passed on
- * to the authenticator. This may be null.
- * @param activity If the authenticator returns a {@link #KEY_INTENT} in the result then
- * the intent will be started with this activity. If activity is null then the result will
- * be returned as-is.
- * @param callback A callback to invoke when the request completes. If null then
- * no callback is invoked.
- * @param handler The {@link Handler} to use to invoke the callback. If null then the
- * main thread's {@link Handler} is used.
- * @return an {@link AccountManagerFuture} that represents the future result of the call.
- * The future result is a {@link Bundle} that contains either:
+ * Asks the user to add an account of a specified type. The authenticator
+ * for this account type processes this request with the appropriate user
+ * interface. If the user does elect to create a new account, the account
+ * name is returned.
+ *
+ * <p>This method may be called from any thread, but the returned
+ * {@link AccountManagerFuture} must not be used on the main thread.
+ *
+ * <p>This method requires the caller to hold the permission
+ * {@link android.Manifest.permission#MANAGE_ACCOUNTS}.
+ *
+ * @param accountType The type of account to add; must not be null
+ * @param authTokenType The type of auth token (see {@link #getAuthToken})
+ * this account will need to be able to generate, null for none
+ * @param requiredFeatures The features (see {@link #hasFeatures}) this
+ * account must have, null for none
+ * @param addAccountOptions Authenticator-specific options for the request,
+ * may be null or empty
+ * @param activity The {@link Activity} context to use for launching a new
+ * authenticator-defined sub-Activity to prompt the user to create an
+ * account; used only to call startActivity(); if null, the prompt
+ * will not be launched directly, but the necessary {@link Intent}
+ * will be returned to the caller instead
+ * @param callback Callback to invoke when the request completes,
+ * null for no callback
+ * @param handler {@link Handler} identifying the callback thread,
+ * null for the main thread
+ * @return An {@link AccountManagerFuture} which resolves to a Bundle with
+ * these fields if activity was specified and an account was created:
* <ul>
- * <li> {@link #KEY_INTENT}, or
- * <li> {@link #KEY_ACCOUNT_NAME}, {@link #KEY_ACCOUNT_TYPE}
+ * <li> {@link #KEY_ACCOUNT_NAME} - the name of the account created
+ * <li> {@link #KEY_ACCOUNT_TYPE} - the type of the account
+ * </ul>
+ *
+ * If no activity was specified, the returned Bundle contains only
+ * {@link #KEY_INTENT} with the {@link Intent} needed to launch the
+ * actual account creation process.
+ *
+ * <p>If an error occurred, {@link AccountManagerFuture#getResult()} throws:
+ * <ul>
+ * <li> {@link AuthenticatorException} if no authenticator was registered for
+ * this account type or the authenticator failed to respond
+ * <li> {@link OperationCanceledException} if the operation was canceled for
+ * any reason, including the user canceling the creation process
+ * <li> {@link IOException} if the authenticator experienced an I/O problem
+ * creating a new account, usually because of network trouble
* </ul>
*/
public AccountManagerFuture<Bundle> addAccount(final String accountType,
@@ -778,128 +922,59 @@ public class AccountManager {
}
/**
- * Queries for accounts that match the given account type and feature set.
- * <p>
- * This call returns immediately but runs asynchronously and the result is accessed via the
- * {@link AccountManagerFuture} that is returned. This future is also passed as the sole
- * parameter to the {@link AccountManagerCallback}. If the caller wished to use this
- * method asynchronously then they will generally pass in a callback object that will get
- * invoked with the {@link AccountManagerFuture}. If they wish to use it synchronously then
- * they will generally pass null for the callback and instead call
- * {@link android.accounts.AccountManagerFuture#getResult()} on this method's return value,
- * which will then block until the request completes.
- * <p>
- * Do not block the main thread waiting this method's result.
- * <p>
- * Not allowed from main thread (but allowed from other threads):
- * <pre>
- * Account[] result =
- * getAccountsByTypeAndFeatures(accountType, features, callback, handler).getResult();
- * </pre>
- * Allowed from main thread:
- * <pre>
- * getAccountsByTypeAndFeatures(accountType, features, new AccountManagerCallback<Account[]>() {
- * public void run(AccountManagerFuture<Account[]> future) {
- * Account[] result = future.getResult();
- * // use result
- * }
- * }, handler);
- * </pre>
- * <p>
- * Requires that the caller has permission {@link android.Manifest.permission#GET_ACCOUNTS}.
- *
- * @param type The type of {@link Account} to return. If null is passed in then an empty
- * array will be returned.
- * @param features the features with which to filter the accounts list. Each returned account
- * will have all specified features. This may be null, which will mean the account list will
- * not be filtered by features, making this functionally identical to
- * {@link #getAccountsByType(String)}.
- * @param callback A callback to invoke when the request completes. If null then
- * no callback is invoked.
- * @param handler The {@link Handler} to use to invoke the callback. If null then the
- * main thread's {@link Handler} is used.
- * @return an {@link AccountManagerFuture} that represents the future result of the call.
- * The future result is a an {@link Account} array that contains accounts of the specified
- * type that match all the requested features.
- */
- public AccountManagerFuture<Account[]> getAccountsByTypeAndFeatures(
- final String type, final String[] features,
- AccountManagerCallback<Account[]> callback, Handler handler) {
- return new Future2Task<Account[]>(handler, callback) {
- public void doWork() throws RemoteException {
- if (type == null) {
- Log.e(TAG, "Type is null");
- set(new Account[0]);
- return;
- }
- mService.getAccountsByFeatures(mResponse, type, features);
- }
- public Account[] bundleToResult(Bundle bundle) throws AuthenticatorException {
- if (!bundle.containsKey(KEY_ACCOUNTS)) {
- throw new AuthenticatorException("no result in response");
- }
- final Parcelable[] parcelables = bundle.getParcelableArray(KEY_ACCOUNTS);
- Account[] descs = new Account[parcelables.length];
- for (int i = 0; i < parcelables.length; i++) {
- descs[i] = (Account) parcelables[i];
- }
- return descs;
- }
- }.start();
- }
-
- /**
- * Requests that the authenticator checks that the user knows the credentials for the account.
- * This is typically done by returning an intent to an activity that prompts the user to
- * enter the credentials. This request
- * is processed by the authenticator for the account. If no matching authenticator is
- * registered in the system then {@link AuthenticatorException} is thrown.
- * <p>
- * This call returns immediately but runs asynchronously and the result is accessed via the
- * {@link AccountManagerFuture} that is returned. This future is also passed as the sole
- * parameter to the {@link AccountManagerCallback}. If the caller wished to use this
- * method asynchronously then they will generally pass in a callback object that will get
- * invoked with the {@link AccountManagerFuture}. If they wish to use it synchronously then
- * they will generally pass null for the callback and instead call
- * {@link android.accounts.AccountManagerFuture#getResult()} on this method's return value,
- * which will then block until the request completes.
- * <p>
- * Do not block the main thread waiting this method's result.
- * <p>
- * Not allowed from main thread (but allowed from other threads):
- * <pre>
- * Bundle result = confirmCredentials(
- * account, options, activity, callback, handler).getResult();
- * </pre>
- * Allowed from main thread:
- * <pre>
- * confirmCredentials(account, options, activity, new AccountManagerCallback<Bundle>() {
- * public void run(AccountManagerFuture<Bundle> future) {
- * Bundle result = future.getResult();
- * // use result
- * }
- * }, handler);
- * </pre>
- * <p>
- * Requires that the caller has permission {@link android.Manifest.permission#MANAGE_ACCOUNTS}.
- *
- * @param account The account whose credentials are to be checked
- * @param options authenticator specific options for the request
- * @param activity If the authenticator returns a {@link #KEY_INTENT} in the result then
- * the intent will be started with this activity. If activity is null then the result will
- * be returned as-is.
- * @param callback A callback to invoke when the request completes. If null then
- * no callback is invoked.
- * @param handler The {@link Handler} to use to invoke the callback. If null then the
- * main thread's {@link Handler} is used.
- * @return an {@link AccountManagerFuture} that represents the future result of the call.
- * The future result is a {@link Bundle} that contains either:
+ * Confirms that the user knows the password for an account to make extra
+ * sure they are the owner of the account. The user-entered password can
+ * be supplied directly, otherwise the authenticator for this account type
+ * prompts the user with the appropriate interface. This method is
+ * intended for applications which want extra assurance; for example, the
+ * phone lock screen uses this to let the user unlock the phone with an
+ * account password if they forget the lock pattern.
+ *
+ * <p>If the user-entered password matches a saved password for this
+ * account, the request is considered valid; otherwise the authenticator
+ * verifies the password (usually by contacting the server).
+ *
+ * <p>This method may be called from any thread, but the returned
+ * {@link AccountManagerFuture} must not be used on the main thread.
+ *
+ * <p>This method requires the caller to hold the permission
+ * {@link android.Manifest.permission#MANAGE_ACCOUNTS}.
+ *
+ * @param account The account to confirm password knowledge for
+ * @param options Authenticator-specific options for the request;
+ * if the {@link #KEY_PASSWORD} string field is present, the
+ * authenticator may use it directly rather than prompting the user;
+ * may be null or empty
+ * @param activity The {@link Activity} context to use for launching a new
+ * authenticator-defined sub-Activity to prompt the user to enter a
+ * password; used only to call startActivity(); if null, the prompt
+ * will not be launched directly, but the necessary {@link Intent}
+ * will be returned to the caller instead
+ * @param callback Callback to invoke when the request completes,
+ * null for no callback
+ * @param handler {@link Handler} identifying the callback thread,
+ * null for the main thread
+ * @return An {@link AccountManagerFuture} which resolves to a Bundle
+ * with these fields if activity or password was supplied and
+ * the account was successfully verified:
+ * <ul>
+ * <li> {@link #KEY_ACCOUNT_NAME} - the name of the account created
+ * <li> {@link #KEY_ACCOUNT_TYPE} - the type of the account
+ * <li> {@link #KEY_BOOLEAN_RESULT} - true to indicate success
+ * </ul>
+ *
+ * If no activity or password was specified, the returned Bundle contains
+ * only {@link #KEY_INTENT} with the {@link Intent} needed to launch the
+ * password prompt.
+ *
+ * <p>If an error occurred, {@link AccountManagerFuture#getResult()} throws:
* <ul>
- * <li> {@link #KEY_INTENT}, which is to be used to prompt the user for the credentials
- * <li> {@link #KEY_ACCOUNT_NAME} and {@link #KEY_ACCOUNT_TYPE} if the user enters the correct
- * credentials
+ * <li> {@link AuthenticatorException} if the authenticator failed to respond
+ * <li> {@link OperationCanceledException} if the operation was canceled for
+ * any reason, including the user canceling the password prompt
+ * <li> {@link IOException} if the authenticator experienced an I/O problem
+ * verifying the password, usually because of network trouble
* </ul>
- * If the user presses "back" then the request will be canceled.
*/
public AccountManagerFuture<Bundle> confirmCredentials(final Account account,
final Bundle options,
@@ -914,59 +989,52 @@ public class AccountManager {
}
/**
- * Requests that the authenticator update the the credentials for a user. This is typically
- * done by returning an intent to an activity that will prompt the user to update the stored
- * credentials for the account. This request
- * is processed by the authenticator for the account. If no matching authenticator is
- * registered in the system then {@link AuthenticatorException} is thrown.
- * <p>
- * This call returns immediately but runs asynchronously and the result is accessed via the
- * {@link AccountManagerFuture} that is returned. This future is also passed as the sole
- * parameter to the {@link AccountManagerCallback}. If the caller wished to use this
- * method asynchronously then they will generally pass in a callback object that will get
- * invoked with the {@link AccountManagerFuture}. If they wish to use it synchronously then
- * they will generally pass null for the callback and instead call
- * {@link android.accounts.AccountManagerFuture#getResult()} on this method's return value,
- * which will then block until the request completes.
- * <p>
- * Do not block the main thread waiting this method's result.
- * <p>
- * Not allowed from main thread (but allowed from other threads):
- * <pre>
- * Bundle result = updateCredentials(
- * account, authTokenType, options, activity, callback, handler).getResult();
- * </pre>
- * Allowed from main thread:
- * <pre>
- * updateCredentials(account, authTokenType, options, activity, new AccountManagerCallback<Bundle>() {
- * public void run(AccountManagerFuture<Bundle> future) {
- * Bundle result = future.getResult();
- * // use result
- * }
- * }, handler);
- * </pre>
- * <p>
- * Requires that the caller has permission {@link android.Manifest.permission#MANAGE_ACCOUNTS}.
- *
- * @param account The account whose credentials are to be updated.
- * @param authTokenType the auth token to retrieve as part of updating the credentials.
- * May be null.
- * @param options authenticator specific options for the request
- * @param activity If the authenticator returns a {@link #KEY_INTENT} in the result then
- * the intent will be started with this activity. If activity is null then the result will
- * be returned as-is.
- * @param callback A callback to invoke when the request completes. If null then
- * no callback is invoked.
- * @param handler The {@link Handler} to use to invoke the callback. If null then the
- * main thread's {@link Handler} is used.
- * @return an {@link AccountManagerFuture} that represents the future result of the call.
- * The future result is a {@link Bundle} that contains either:
+ * Asks the user to enter a new password for an account, updating the
+ * saved credentials for the account. Normally this happens automatically
+ * when the server rejects credentials during an auth token fetch, but this
+ * can be invoked directly to ensure we have the correct credentials stored.
+ *
+ * <p>This method may be called from any thread, but the returned
+ * {@link AccountManagerFuture} must not be used on the main thread.
+ *
+ * <p>This method requires the caller to hold the permission
+ * {@link android.Manifest.permission#MANAGE_ACCOUNTS}.
+ *
+ * @param account The account to update credentials for
+ * @param authTokenType The credentials entered must allow an auth token
+ * of this type to be created (but no actual auth token is returned);
+ * may be null
+ * @param options Authenticator-specific options for the request;
+ * may be null or empty
+ * @param activity The {@link Activity} context to use for launching a new
+ * authenticator-defined sub-Activity to prompt the user to enter a
+ * password; used only to call startActivity(); if null, the prompt
+ * will not be launched directly, but the necessary {@link Intent}
+ * will be returned to the caller instead
+ * @param callback Callback to invoke when the request completes,
+ * null for no callback
+ * @param handler {@link Handler} identifying the callback thread,
+ * null for the main thread
+ * @return An {@link AccountManagerFuture} which resolves to a Bundle
+ * with these fields if an activity was supplied and the account
+ * credentials were successfully updated:
* <ul>
- * <li> {@link #KEY_INTENT}, which is to be used to prompt the user for the credentials
- * <li> {@link #KEY_ACCOUNT_NAME} and {@link #KEY_ACCOUNT_TYPE} if the user enters the correct
- * credentials.
+ * <li> {@link #KEY_ACCOUNT_NAME} - the name of the account created
+ * <li> {@link #KEY_ACCOUNT_TYPE} - the type of the account
+ * </ul>
+ *
+ * If no activity was specified, the returned Bundle contains only
+ * {@link #KEY_INTENT} with the {@link Intent} needed to launch the
+ * password prompt.
+ *
+ * <p>If an error occurred, {@link AccountManagerFuture#getResult()} throws:
+ * <ul>
+ * <li> {@link AuthenticatorException} if the authenticator failed to respond
+ * <li> {@link OperationCanceledException} if the operation was canceled for
+ * any reason, including the user canceling the password prompt
+ * <li> {@link IOException} if the authenticator experienced an I/O problem
+ * verifying the password, usually because of network trouble
* </ul>
- * If the user presses "back" then the request will be canceled.
*/
public AccountManagerFuture<Bundle> updateCredentials(final Account account,
final String authTokenType,
@@ -982,53 +1050,41 @@ public class AccountManager {
}
/**
- * Request that the properties for an authenticator be updated. This is typically done by
- * returning an intent to an activity that will allow the user to make changes. This request
- * is processed by the authenticator for the account. If no matching authenticator is
- * registered in the system then {@link AuthenticatorException} is thrown.
- * <p>
- * This call returns immediately but runs asynchronously and the result is accessed via the
- * {@link AccountManagerFuture} that is returned. This future is also passed as the sole
- * parameter to the {@link AccountManagerCallback}. If the caller wished to use this
- * method asynchronously then they will generally pass in a callback object that will get
- * invoked with the {@link AccountManagerFuture}. If they wish to use it synchronously then
- * they will generally pass null for the callback and instead call
- * {@link android.accounts.AccountManagerFuture#getResult()} on this method's return value,
- * which will then block until the request completes.
- * <p>
- * Do not block the main thread waiting this method's result.
- * <p>
- * Not allowed from main thread (but allowed from other threads):
- * <pre>
- * Bundle result = editProperties(accountType, activity, callback, handler).getResult();
- * </pre>
- * Allowed from main thread:
- * <pre>
- * editProperties(accountType, activity, new AccountManagerCallback<Bundle>() {
- * public void run(AccountManagerFuture<Bundle> future) {
- * Bundle result = future.getResult();
- * // use result
- * }
- * }, handler);
- * </pre>
- * <p>
- * Requires that the caller has permission {@link android.Manifest.permission#MANAGE_ACCOUNTS}.
- *
- * @param accountType The account type of the authenticator whose properties are to be edited.
- * @param activity If the authenticator returns a {@link #KEY_INTENT} in the result then
- * the intent will be started with this activity. If activity is null then the result will
- * be returned as-is.
- * @param callback A callback to invoke when the request completes. If null then
- * no callback is invoked.
- * @param handler The {@link Handler} to use to invoke the callback. If null then the
- * main thread's {@link Handler} is used.
- * @return an {@link AccountManagerFuture} that represents the future result of the call.
- * The future result is a {@link Bundle} that contains either:
+ * Offers the user an opportunity to change an authenticator's settings.
+ * These properties are for the authenticator in general, not a particular
+ * account. Not all authenticators support this method.
+ *
+ * <p>This method may be called from any thread, but the returned
+ * {@link AccountManagerFuture} must not be used on the main thread.
+ *
+ * <p>This method requires the caller to hold the permission
+ * {@link android.Manifest.permission#MANAGE_ACCOUNTS}.
+ *
+ * @param accountType The account type associated with the authenticator
+ * to adjust
+ * @param activity The {@link Activity} context to use for launching a new
+ * authenticator-defined sub-Activity to adjust authenticator settings;
+ * used only to call startActivity(); if null, the settings dialog will
+ * not be launched directly, but the necessary {@link Intent} will be
+ * returned to the caller instead
+ * @param callback Callback to invoke when the request completes,
+ * null for no callback
+ * @param handler {@link Handler} identifying the callback thread,
+ * null for the main thread
+ * @return An {@link AccountManagerFuture} which resolves to a Bundle
+ * which is empty if properties were edited successfully, or
+ * if no activity was specified, contains only {@link #KEY_INTENT}
+ * needed to launch the authenticator's settings dialog.
+ *
+ * <p>If an error occurred, {@link AccountManagerFuture#getResult()} throws:
* <ul>
- * <li> {@link #KEY_INTENT}, which is to be used to prompt the user for the credentials
- * <li> nothing, returned if the edit completes successfully
+ * <li> {@link AuthenticatorException} if no authenticator was registered for
+ * this account type or the authenticator failed to respond
+ * <li> {@link OperationCanceledException} if the operation was canceled for
+ * any reason, including the user canceling the settings dialog
+ * <li> {@link IOException} if the authenticator experienced an I/O problem
+ * updating settings, usually because of network trouble
* </ul>
- * If the user presses "back" then the request will be canceled.
*/
public AccountManagerFuture<Bundle> editProperties(final String accountType,
final Activity activity, final AccountManagerCallback<Bundle> callback,
@@ -1475,57 +1531,68 @@ public class AccountManager {
}
/**
- * Convenience method that combines the functionality of {@link #getAccountsByTypeAndFeatures},
- * {@link #getAuthToken(Account, String, Bundle, Activity, AccountManagerCallback, Handler)},
- * and {@link #addAccount}. It first gets the list of accounts that match accountType and the
- * feature set. If there are none then {@link #addAccount} is invoked with the authTokenType
- * feature set, and addAccountOptions. If there is exactly one then
- * {@link #getAuthToken(Account, String, Bundle, Activity, AccountManagerCallback, Handler)} is
- * called with that account. If there are more than one then a chooser activity is launched
- * to prompt the user to select one of them and then the authtoken is retrieved for it,
- * <p>
- * This call returns immediately but runs asynchronously and the result is accessed via the
- * {@link AccountManagerFuture} that is returned. This future is also passed as the sole
- * parameter to the {@link AccountManagerCallback}. If the caller wished to use this
- * method asynchronously then they will generally pass in a callback object that will get
- * invoked with the {@link AccountManagerFuture}. If they wish to use it synchronously then
- * they will generally pass null for the callback and instead call
- * {@link android.accounts.AccountManagerFuture#getResult()} on this method's return value,
- * which will then block until the request completes.
- * <p>
- * Requires that the caller has permission {@link android.Manifest.permission#MANAGE_ACCOUNTS}.
- *
- * @param accountType the accountType to query; this must be non-null
- * @param authTokenType the type of authtoken to retrieve; this must be non-null
- * @param features a filter for the accounts. See {@link #getAccountsByTypeAndFeatures}.
- * @param activityForPrompting The activity used to start any account management
- * activities that are required to fulfill this request. This may be null.
- * @param addAccountOptions authenticator-specific options used if an account needs to be added
- * @param getAuthTokenOptions authenticator-specific options passed to getAuthToken
- * @param callback A callback to invoke when the request completes. If null then
- * no callback is invoked.
- * @param handler The {@link Handler} to use to invoke the callback. If null then the
- * main thread's {@link Handler} is used.
- * @return an {@link AccountManagerFuture} that represents the future result of the call.
- * The future result is a {@link Bundle} that contains either:
+ * This convenience helper combines the functionality of
+ * {@link #getAccountsByTypeAndFeatures}, {@link #getAuthToken}, and
+ * {@link #addAccount}.
+ *
+ * <p>This method gets a list of the accounts matching the
+ * specified type and feature set; if there is exactly one, it is
+ * used; if there are more than one, the user is prompted to pick one;
+ * if there are none, the user is prompted to add one. Finally,
+ * an auth token is acquired for the chosen account.
+ *
+ * <p>This method may be called from any thread, but the returned
+ * {@link AccountManagerFuture} must not be used on the main thread.
+ *
+ * <p>This method requires the caller to hold the permission
+ * {@link android.Manifest.permission#MANAGE_ACCOUNTS}.
+ *
+ * @param accountType The account type required
+ * (see {@link #getAccountsByType}), must not be null
+ * @param authTokenType The desired auth token type
+ * (see {@link #getAuthToken}), must not be null
+ * @param features Required features for the account
+ * (see {@link #getAccountsByTypeAndFeatures}), may be null or empty
+ * @param activity The {@link Activity} context to use for launching new
+ * sub-Activities to prompt to add an account, select an account,
+ * and/or enter a password, as necessary; used only to call
+ * startActivity(); should not be null
+ * @param addAccountOptions Authenticator-specific options to use for
+ * adding new accounts; may be null or empty
+ * @param getAuthTokenOptions Authenticator-specific options to use for
+ * getting auth tokens; may be null or empty
+ * @param callback Callback to invoke when the request completes,
+ * null for no callback
+ * @param handler {@link Handler} identifying the callback thread,
+ * null for the main thread
+ * @return An {@link AccountManagerFuture} which resolves to a Bundle with
+ * at least the following fields:
* <ul>
- * <li> {@link #KEY_INTENT}, if no activity is supplied yet an activity needs to launched to
- * fulfill the request.
- * <li> {@link #KEY_ACCOUNT_NAME}, {@link #KEY_ACCOUNT_TYPE} and {@link #KEY_AUTHTOKEN} if the
- * request completes successfully.
+ * <li> {@link #KEY_ACCOUNT_NAME} - the name of the account
+ * <li> {@link #KEY_ACCOUNT_TYPE} - the type of the account
+ * <li> {@link #KEY_AUTHTOKEN} - the auth token you wanted
+ * </ul>
+ *
+ * <p>If an error occurred, {@link AccountManagerFuture#getResult()} throws:
+ * <ul>
+ * <li> {@link AuthenticatorException} if no authenticator was registered for
+ * this account type or the authenticator failed to respond
+ * <li> {@link OperationCanceledException} if the operation was canceled for
+ * any reason, including the user canceling any operation
+ * <li> {@link IOException} if the authenticator experienced an I/O problem
+ * updating settings, usually because of network trouble
* </ul>
- * If the user presses "back" then the request will be canceled.
*/
public AccountManagerFuture<Bundle> getAuthTokenByFeatures(
final String accountType, final String authTokenType, final String[] features,
- final Activity activityForPrompting, final Bundle addAccountOptions,
+ final Activity activity, final Bundle addAccountOptions,
final Bundle getAuthTokenOptions,
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");
final GetAuthTokenByTypeAndFeaturesTask task =
new GetAuthTokenByTypeAndFeaturesTask(accountType, authTokenType, features,
- activityForPrompting, addAccountOptions, getAuthTokenOptions, callback, handler);
+ activity, addAccountOptions, getAuthTokenOptions, callback, handler);
task.start();
return task;
}
@@ -1552,18 +1619,26 @@ public class AccountManager {
};
/**
- * Add a {@link OnAccountsUpdateListener} 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.
- * <p>
- * You must remove this listener before the context that was used to retrieve this
- * {@link AccountManager} instance goes away. This generally means when the Activity
- * or Service you are running is stopped.
- * @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.
+ * Adds an {@link OnAccountsUpdateListener} to this instance of the
+ * {@link AccountManager}. This listener will be notified whenever the
+ * list of accounts on the device changes.
+ *
+ * <p>As long as this listener is present, the AccountManager instance
+ * will not be garbage-collected, and neither will the {@link Context}
+ * used to retrieve it, which may be a large Activity instance. To avoid
+ * memory leaks, you must remove this listener before then. Normally
+ * listeners are added in an Activity or Service's {@link Activity#onCreate}
+ * and removed in {@link Activity#onDestroy}.
+ *
+ * <p>It is safe to call this method from the main thread.
+ *
+ * <p>No permission is required to call this method.
+ *
+ * @param listener The listener to send notifications to
+ * @param handler {@link Handler} identifying the thread to use
+ * for notifications, null for the main thread
+ * @param updateImmediately If true, the listener will be invoked
+ * (on the handler thread) right away with the current account list
* @throws IllegalArgumentException if listener is null
* @throws IllegalStateException if listener was already added
*/
@@ -1596,9 +1671,15 @@ public class AccountManager {
}
/**
- * Remove an {@link OnAccountsUpdateListener} that was previously registered with
- * {@link #addOnAccountsUpdatedListener}.
- * @param listener the listener to remove
+ * Removes an {@link OnAccountsUpdateListener} previously registered with
+ * {@link #addOnAccountsUpdatedListener}. The listener will no longer
+ * receive notifications of account changes.
+ *
+ * <p>It is safe to call this method from the main thread.
+ *
+ * <p>No permission is required to call this method.
+ *
+ * @param listener The previously added listener to remove
* @throws IllegalArgumentException if listener is null
* @throws IllegalStateException if listener was not already added
*/
diff --git a/core/java/android/accounts/AccountManagerService.java b/core/java/android/accounts/AccountManagerService.java
index 770554e..2aaf5b0 100644
--- a/core/java/android/accounts/AccountManagerService.java
+++ b/core/java/android/accounts/AccountManagerService.java
@@ -565,7 +565,7 @@ public class AccountManagerService
}
public void invalidateAuthToken(String accountType, String authToken) {
- checkManageAccountsPermission();
+ checkManageAccountsOrUseCredentialsPermissions();
long identityToken = clearCallingIdentity();
try {
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
@@ -691,11 +691,21 @@ public class AccountManagerService
if (account == null) {
return;
}
- 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});
+ SQLiteDatabase db = mOpenHelper.getWritableDatabase();
+ db.beginTransaction();
+ try {
+ final ContentValues values = new ContentValues();
+ values.put(ACCOUNTS_PASSWORD, password);
+ final long accountId = getAccountId(db, account);
+ if (accountId >= 0) {
+ final String[] argsAccountId = {String.valueOf(accountId)};
+ db.update(TABLE_ACCOUNTS, values, ACCOUNTS_ID + "=?", argsAccountId);
+ db.delete(TABLE_AUTHTOKENS, AUTHTOKENS_ACCOUNTS_ID + "=?", argsAccountId);
+ db.setTransactionSuccessful();
+ }
+ } finally {
+ db.endTransaction();
+ }
sendAccountsChangedBroadcast();
}
@@ -1134,7 +1144,10 @@ public class AccountManagerService
long identityToken = clearCallingIdentity();
try {
if (features == null || features.length == 0) {
- getAccountsByType(type);
+ Account[] accounts = getAccountsByType(type);
+ Bundle result = new Bundle();
+ result.putParcelableArray(AccountManager.KEY_ACCOUNTS, accounts);
+ onResult(response, result);
return;
}
new GetAccountsByTypeAndFeatureSession(response, type, features).bind();
@@ -1734,17 +1747,22 @@ public class AccountManagerService
}
}
- private void checkBinderPermission(String permission) {
+ /** Succeeds if any of the specified permissions are granted. */
+ private void checkBinderPermission(String... permissions) {
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);
+
+ for (String perm : permissions) {
+ if (mContext.checkCallingOrSelfPermission(perm) == PackageManager.PERMISSION_GRANTED) {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "caller uid " + uid + " has " + perm);
+ }
+ return;
+ }
}
+
+ String msg = "caller uid " + uid + " lacks any of " + TextUtils.join(",", permissions);
+ Log.w(TAG, msg);
+ throw new SecurityException(msg);
}
private boolean inSystemImage(int callerUid) {
@@ -1835,6 +1853,11 @@ public class AccountManagerService
checkBinderPermission(Manifest.permission.MANAGE_ACCOUNTS);
}
+ private void checkManageAccountsOrUseCredentialsPermissions() {
+ checkBinderPermission(Manifest.permission.MANAGE_ACCOUNTS,
+ Manifest.permission.USE_CREDENTIALS);
+ }
+
/**
* Allow callers with the given uid permission to get credentials for account/authTokenType.
* <p>
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 05bbf3b..b38aeda 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -1308,14 +1308,16 @@ public class Activity extends ContextThemeWrapper
}
// close any cursors we are managing.
- int numCursors = mManagedCursors.size();
- for (int i = 0; i < numCursors; i++) {
- ManagedCursor c = mManagedCursors.get(i);
- if (c != null) {
- c.mCursor.close();
+ synchronized (mManagedCursors) {
+ int numCursors = mManagedCursors.size();
+ for (int i = 0; i < numCursors; i++) {
+ ManagedCursor c = mManagedCursors.get(i);
+ if (c != null) {
+ c.mCursor.close();
+ }
}
+ mManagedCursors.clear();
}
- mManagedCursors.clear();
}
/**
@@ -3778,13 +3780,15 @@ public class Activity extends ContextThemeWrapper
}
final void performRestart() {
- final int N = mManagedCursors.size();
- for (int i=0; i<N; i++) {
- ManagedCursor mc = mManagedCursors.get(i);
- if (mc.mReleased || mc.mUpdated) {
- mc.mCursor.requery();
- mc.mReleased = false;
- mc.mUpdated = false;
+ synchronized (mManagedCursors) {
+ final int N = mManagedCursors.size();
+ for (int i=0; i<N; i++) {
+ ManagedCursor mc = mManagedCursors.get(i);
+ if (mc.mReleased || mc.mUpdated) {
+ mc.mCursor.requery();
+ mc.mReleased = false;
+ mc.mUpdated = false;
+ }
}
}
@@ -3850,12 +3854,14 @@ public class Activity extends ContextThemeWrapper
" did not call through to super.onStop()");
}
- final int N = mManagedCursors.size();
- for (int i=0; i<N; i++) {
- ManagedCursor mc = mManagedCursors.get(i);
- if (!mc.mReleased) {
- mc.mCursor.deactivate();
- mc.mReleased = true;
+ synchronized (mManagedCursors) {
+ final int N = mManagedCursors.size();
+ for (int i=0; i<N; i++) {
+ ManagedCursor mc = mManagedCursors.get(i);
+ if (!mc.mReleased) {
+ mc.mCursor.deactivate();
+ mc.mReleased = true;
+ }
}
}
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 13cc3ba..0756c71 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -77,9 +77,12 @@ import java.io.File;
import java.io.FileDescriptor;
import java.io.FileOutputStream;
import java.io.IOException;
+import java.io.InputStream;
import java.io.PrintWriter;
import java.lang.ref.WeakReference;
+import java.net.URL;
import java.util.ArrayList;
+import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
@@ -460,6 +463,7 @@ public final class ActivityThread {
mClassLoader =
ApplicationLoaders.getDefault().getClassLoader(
zip, mDataDir, mBaseClassLoader);
+ initializeJavaContextClassLoader();
} else {
if (mBaseClassLoader == null) {
mClassLoader = ClassLoader.getSystemClassLoader();
@@ -471,6 +475,120 @@ public final class ActivityThread {
}
}
+ /**
+ * Setup value for Thread.getContextClassLoader(). If the
+ * package will not run in in a VM with other packages, we set
+ * the Java context ClassLoader to the
+ * PackageInfo.getClassLoader value. However, if this VM can
+ * contain multiple packages, we intead set the Java context
+ * ClassLoader to a proxy that will warn about the use of Java
+ * context ClassLoaders and then fall through to use the
+ * system ClassLoader.
+ *
+ * <p> Note that this is similar to but not the same as the
+ * android.content.Context.getClassLoader(). While both
+ * context class loaders are typically set to the
+ * PathClassLoader used to load the package archive in the
+ * single application per VM case, a single Android process
+ * may contain several Contexts executing on one thread with
+ * their own logical ClassLoaders while the Java context
+ * ClassLoader is a thread local. This is why in the case when
+ * we have multiple packages per VM we do not set the Java
+ * context ClassLoader to an arbitrary but instead warn the
+ * user to set their own if we detect that they are using a
+ * Java library that expects it to be set.
+ */
+ private void initializeJavaContextClassLoader() {
+ IPackageManager pm = getPackageManager();
+ android.content.pm.PackageInfo pi;
+ try {
+ pi = pm.getPackageInfo(mPackageName, 0);
+ } catch (RemoteException e) {
+ throw new AssertionError(e);
+ }
+ /*
+ * Two possible indications that this package could be
+ * sharing its virtual machine with other packages:
+ *
+ * 1.) the sharedUserId attribute is set in the manifest,
+ * indicating a request to share a VM with other
+ * packages with the same sharedUserId.
+ *
+ * 2.) the application element of the manifest has an
+ * attribute specifying a non-default process name,
+ * indicating the desire to run in another packages VM.
+ */
+ boolean sharedUserIdSet = (pi.sharedUserId != null);
+ boolean processNameNotDefault =
+ (pi.applicationInfo != null &&
+ !mPackageName.equals(pi.applicationInfo.processName));
+ boolean sharable = (sharedUserIdSet || processNameNotDefault);
+ ClassLoader contextClassLoader =
+ (sharable)
+ ? new WarningContextClassLoader()
+ : mClassLoader;
+ Thread.currentThread().setContextClassLoader(contextClassLoader);
+ }
+
+ private static class WarningContextClassLoader extends ClassLoader {
+
+ private static boolean warned = false;
+
+ private void warn(String methodName) {
+ if (warned) {
+ return;
+ }
+ warned = true;
+ Thread.currentThread().setContextClassLoader(getParent());
+ Log.w(TAG, "ClassLoader." + methodName + ": " +
+ "The class loader returned by " +
+ "Thread.getContextClassLoader() may fail for processes " +
+ "that host multiple applications. You should explicitly " +
+ "specify a context class loader. For example: " +
+ "Thread.setContextClassLoader(getClass().getClassLoader());");
+ }
+
+ @Override public URL getResource(String resName) {
+ warn("getResource");
+ return getParent().getResource(resName);
+ }
+
+ @Override public Enumeration<URL> getResources(String resName) throws IOException {
+ warn("getResources");
+ return getParent().getResources(resName);
+ }
+
+ @Override public InputStream getResourceAsStream(String resName) {
+ warn("getResourceAsStream");
+ return getParent().getResourceAsStream(resName);
+ }
+
+ @Override public Class<?> loadClass(String className) throws ClassNotFoundException {
+ warn("loadClass");
+ return getParent().loadClass(className);
+ }
+
+ @Override public void setClassAssertionStatus(String cname, boolean enable) {
+ warn("setClassAssertionStatus");
+ getParent().setClassAssertionStatus(cname, enable);
+ }
+
+ @Override public void setPackageAssertionStatus(String pname, boolean enable) {
+ warn("setPackageAssertionStatus");
+ getParent().setPackageAssertionStatus(pname, enable);
+ }
+
+ @Override public void setDefaultAssertionStatus(boolean enable) {
+ warn("setDefaultAssertionStatus");
+ getParent().setDefaultAssertionStatus(enable);
+ }
+
+ @Override public void clearAssertionStatus() {
+ warn("clearAssertionStatus");
+ getParent().clearAssertionStatus();
+ }
+ }
+
public String getAppDir() {
return mAppDir;
}
@@ -2495,7 +2613,6 @@ public final class ActivityThread {
" did not call through to super.onPostCreate()");
}
}
- r.state = null;
}
r.paused = true;
@@ -2526,6 +2643,7 @@ public final class ActivityThread {
if (a != null) {
r.createdConfig = new Configuration(mConfiguration);
+ Bundle oldState = r.state;
handleResumeActivity(r.token, false, r.isForward);
if (!r.activity.mFinished && r.startsNotResumed) {
@@ -2541,6 +2659,9 @@ public final class ActivityThread {
try {
r.activity.mCalled = false;
mInstrumentation.callActivityOnPause(r.activity);
+ // We need to keep around the original state, in case
+ // we need to be created again.
+ r.state = oldState;
if (!r.activity.mCalled) {
throw new SuperNotCalledException(
"Activity " + r.intent.getComponent().toShortString() +
diff --git a/core/java/android/app/AliasActivity.java b/core/java/android/app/AliasActivity.java
index 7527a5b..3756529 100644
--- a/core/java/android/app/AliasActivity.java
+++ b/core/java/android/app/AliasActivity.java
@@ -26,7 +26,8 @@ import android.content.res.XmlResourceParser;
import android.os.Bundle;
import android.util.AttributeSet;
import android.util.Xml;
-import com.android.common.XmlUtils;
+
+import com.android.internal.util.XmlUtils;
import java.io.IOException;
diff --git a/core/java/android/app/ApplicationErrorReport.java b/core/java/android/app/ApplicationErrorReport.java
index 832f599..fe81056 100644
--- a/core/java/android/app/ApplicationErrorReport.java
+++ b/core/java/android/app/ApplicationErrorReport.java
@@ -16,8 +16,16 @@
package android.app;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
import android.os.Parcel;
import android.os.Parcelable;
+import android.os.SystemProperties;
+import android.provider.Settings;
import android.util.Printer;
import java.io.PrintWriter;
import java.io.StringWriter;
@@ -38,6 +46,13 @@ import java.io.StringWriter;
*/
public class ApplicationErrorReport implements Parcelable {
+ // 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";
+
+
/**
* Uninitialized error report.
*/
@@ -54,8 +69,13 @@ public class ApplicationErrorReport implements Parcelable {
public static final int TYPE_ANR = 2;
/**
+ * An error report about an application that's consuming too much battery.
+ */
+ public static final int TYPE_BATTERY = 3;
+
+ /**
* Type of this report. Can be one of {@link #TYPE_NONE},
- * {@link #TYPE_CRASH} or {@link #TYPE_ANR}.
+ * {@link #TYPE_CRASH}, {@link #TYPE_ANR}, or {@link #TYPE_BATTERY}.
*/
public int type;
@@ -99,6 +119,11 @@ public class ApplicationErrorReport implements Parcelable {
public AnrInfo anrInfo;
/**
+ * Text containing battery usage data.
+ */
+ public String batteryText;
+
+ /**
* Create an uninitialized instance of {@link ApplicationErrorReport}.
*/
public ApplicationErrorReport() {
@@ -112,6 +137,68 @@ public class ApplicationErrorReport implements Parcelable {
readFromParcel(in);
}
+ public static ComponentName getErrorReportReceiver(Context context,
+ String packageName, int appFlags) {
+ // check if error reporting is enabled in secure settings
+ int enabled = Settings.Secure.getInt(context.getContentResolver(),
+ Settings.Secure.SEND_ACTION_APP_ERROR, 0);
+ if (enabled == 0) {
+ return null;
+ }
+
+ PackageManager pm = context.getPackageManager();
+
+ // look for receiver in the installer package
+ String candidate = pm.getInstallerPackageName(packageName);
+ ComponentName result = getErrorReportReceiver(pm, packageName, candidate);
+ if (result != null) {
+ return result;
+ }
+
+ // if the error app is on the system image, look for system apps
+ // error receiver
+ if ((appFlags&ApplicationInfo.FLAG_SYSTEM) != 0) {
+ candidate = SystemProperties.get(SYSTEM_APPS_ERROR_RECEIVER_PROPERTY);
+ result = getErrorReportReceiver(pm, packageName, candidate);
+ if (result != null) {
+ return result;
+ }
+ }
+
+ // if there is a default receiver, try that
+ candidate = SystemProperties.get(DEFAULT_ERROR_RECEIVER_PROPERTY);
+ return getErrorReportReceiver(pm, packageName, candidate);
+ }
+
+ /**
+ * 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
+ */
+ static ComponentName getErrorReportReceiver(PackageManager pm, String errorPackage,
+ String receiverPackage) {
+ 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.resolveActivity(intent, 0);
+ if (info == null || info.activityInfo == null) {
+ return null;
+ }
+ return new ComponentName(receiverPackage, info.activityInfo.name);
+ }
+
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(type);
dest.writeString(packageName);
@@ -127,6 +214,9 @@ public class ApplicationErrorReport implements Parcelable {
case TYPE_ANR:
anrInfo.writeToParcel(dest, flags);
break;
+ case TYPE_BATTERY:
+ dest.writeString(batteryText);
+ break;
}
}
@@ -142,10 +232,17 @@ public class ApplicationErrorReport implements Parcelable {
case TYPE_CRASH:
crashInfo = new CrashInfo(in);
anrInfo = null;
+ batteryText = null;
break;
case TYPE_ANR:
anrInfo = new AnrInfo(in);
crashInfo = null;
+ batteryText = null;
+ break;
+ case TYPE_BATTERY:
+ batteryText = in.readString();
+ anrInfo = null;
+ crashInfo = null;
break;
}
}
@@ -347,6 +444,9 @@ public class ApplicationErrorReport implements Parcelable {
case TYPE_ANR:
anrInfo.dump(pw, prefix);
break;
+ case TYPE_BATTERY:
+ pw.println(batteryText);
+ break;
}
}
}
diff --git a/core/java/android/app/BackupAgent.java b/core/java/android/app/BackupAgent.java
index a2bfc76..4695c21 100644
--- a/core/java/android/app/BackupAgent.java
+++ b/core/java/android/app/BackupAgent.java
@@ -31,10 +31,18 @@ import android.util.Log;
import java.io.IOException;
/**
- * This is the central interface between an application and Android's
- * settings backup mechanism.
- *
- * <p>STOPSHIP write more documentation about the backup process here.
+ * This is the central interface between an application and Android's settings
+ * backup mechanism. Any implementation of a backup agent should perform backup
+ * and restore actions in
+ * {@link #onBackup(ParcelFileDescriptor, BackupDataOutput, ParcelFileDescriptor)}
+ * and {@link #onRestore(BackupDataInput, int, ParcelFileDescriptor)}
+ * respectively.
+ * <p>
+ * A backup agent based on convenient helper classes is available in
+ * {@link android.backup.BackupHelperAgent} for less complex implementation
+ * requirements.
+ * <p>
+ * STOPSHIP write more documentation about the backup process here.
*/
public abstract class BackupAgent extends ContextWrapper {
private static final String TAG = "BackupAgent";
@@ -51,51 +59,58 @@ public abstract class BackupAgent extends ContextWrapper {
}
/**
- * The application is being asked to write any data changed since the
- * last time it performed a backup operation. The state data recorded
- * during the last backup pass is provided in the oldState file descriptor.
- * If oldState is null, no old state is available and the application should perform
- * a full backup. In both cases, a representation of the final backup state after
- * this pass should be written to the file pointed to by the newStateFd file descriptor.
- *
- * @param oldState An open, read-only ParcelFileDescriptor pointing to the last backup
- * state provided by the application. May be null, in which
- * case no prior state is being provided and the application should
- * perform a full backup.
- * @param data A structured wrapper around an open, read/write ParcelFileDescriptor
- * pointing to the backup data destination. Typically the application will use
- * backup helper classes to write to this file.
- * @param newState An open, read/write ParcelFileDescriptor pointing to an empty
- * file. The application should record the final backup state
- * here after writing the requested data to dataFd.
+ * The application is being asked to write any data changed since the last
+ * time it performed a backup operation. The state data recorded during the
+ * last backup pass is provided in the <code>oldState</code> file
+ * descriptor. If <code>oldState</code> is <code>null</code>, no old state
+ * is available and the application should perform a full backup. In both
+ * cases, a representation of the final backup state after this pass should
+ * be written to the file pointed to by the file descriptor wrapped in
+ * <code>newState</code>.
+ *
+ * @param oldState An open, read-only ParcelFileDescriptor pointing to the
+ * last backup state provided by the application. May be
+ * <code>null</code>, in which case no prior state is being
+ * provided and the application should perform a full backup.
+ * @param data A structured wrapper around an open, read/write
+ * ParcelFileDescriptor pointing to the backup data destination.
+ * Typically the application will use backup helper classes to
+ * write to this file.
+ * @param newState An open, read/write ParcelFileDescriptor pointing to an
+ * empty file. The application should record the final backup
+ * state here after writing the requested data to dataFd.
*/
public abstract void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
ParcelFileDescriptor newState) throws IOException;
-
+
/**
- * The application is being restored from backup, and should replace any
- * existing data with the contents of the backup. The backup data is
- * provided in the file pointed to by the dataFd file descriptor. Once
- * the restore is finished, the application should write a representation
- * of the final state to the newStateFd file descriptor,
- *
- * <p>The application is responsible for properly erasing its old data and
- * replacing it with the data supplied to this method. No "clear user data"
- * operation will be performed automatically by the operating system. The
- * exception to this is in the case of a failed restore attempt: if onRestore()
- * throws an exception, the OS will assume that the application's data may now
- * be in an incoherent state, and will clear it before proceeding.
- *
- * @param data A structured wrapper around an open, read-only ParcelFileDescriptor
- * pointing to a full snapshot of the application's data. Typically the
- * application will use helper classes to read this data.
- * @param appVersionCode The android:versionCode value of the application that backed
- * up this particular data set. This makes it easier for an application's
- * agent to distinguish among several possible older data versions when
- * asked to perform the restore operation.
- * @param newState An open, read/write ParcelFileDescriptor pointing to an empty
- * file. The application should record the final backup state
- * here after restoring its data from dataFd.
+ * The application is being restored from backup and should replace any
+ * existing data with the contents of the backup. The backup data is
+ * provided in the file descriptor pointed to by the
+ * {@link android.backup.BackupDataInput} instance <code>data</code>. Once
+ * the restore is finished, the application should write a representation of
+ * the final state to the <code>newState</code> file descriptor.
+ * <p>
+ * The application is responsible for properly erasing its old data and
+ * replacing it with the data supplied to this method. No "clear user data"
+ * operation will be performed automatically by the operating system. The
+ * exception to this is in the case of a failed restore attempt: if
+ * onRestore() throws an exception, the OS will assume that the
+ * application's data may now be in an incoherent state, and will clear it
+ * before proceeding.
+ *
+ * @param data A structured wrapper around an open, read-only
+ * ParcelFileDescriptor pointing to a full snapshot of the
+ * application's data. Typically the application will use helper
+ * classes to read this data.
+ * @param appVersionCode The android:versionCode value of the application
+ * that backed up this particular data set. This makes it easier
+ * for an application's agent to distinguish among several
+ * possible older data versions when asked to perform the restore
+ * operation.
+ * @param newState An open, read/write ParcelFileDescriptor pointing to an
+ * empty file. The application should record the final backup
+ * state here after restoring its data from dataFd.
*/
public abstract void onRestore(BackupDataInput data, int appVersionCode,
ParcelFileDescriptor newState)
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 1d004ee..0e21936 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -17,7 +17,7 @@
package android.app;
import com.android.internal.policy.PolicyManager;
-import com.android.common.XmlUtils;
+import com.android.internal.util.XmlUtils;
import com.google.android.collect.Maps;
import org.xmlpull.v1.XmlPullParserException;
@@ -194,6 +194,7 @@ class ContextImpl extends Context {
private AccountManager mAccountManager; // protected by mSync
private DropBoxManager mDropBoxManager = null;
private DevicePolicyManager mDevicePolicyManager = null;
+ private UiModeManager mUiModeManager = null;
private final Object mSync = new Object();
@@ -960,6 +961,8 @@ class ContextImpl extends Context {
return getDropBoxManager();
} else if (DEVICE_POLICY_SERVICE.equals(name)) {
return getDevicePolicyManager();
+ } else if (UI_MODE_SERVICE.equals(name)) {
+ return getUiModeManager();
}
return null;
@@ -1146,13 +1149,22 @@ class ContextImpl extends Context {
private DevicePolicyManager getDevicePolicyManager() {
synchronized (mSync) {
if (mDevicePolicyManager == null) {
- mDevicePolicyManager = new DevicePolicyManager(this,
+ mDevicePolicyManager = DevicePolicyManager.create(this,
mMainThread.getHandler());
}
}
return mDevicePolicyManager;
}
+ private UiModeManager getUiModeManager() {
+ synchronized (mSync) {
+ if (mUiModeManager == null) {
+ mUiModeManager = new UiModeManager();
+ }
+ }
+ return mUiModeManager;
+ }
+
@Override
public int checkPermission(String permission, int pid, int uid) {
if (permission == null) {
diff --git a/core/java/android/app/DeviceAdminInfo.java b/core/java/android/app/DeviceAdminInfo.java
index bedf4b4..61e1bb3 100644
--- a/core/java/android/app/DeviceAdminInfo.java
+++ b/core/java/android/app/DeviceAdminInfo.java
@@ -18,6 +18,7 @@ package android.app;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
import android.content.ComponentName;
import android.content.Context;
@@ -331,6 +332,19 @@ public final class DeviceAdminInfo implements Parcelable {
return res;
}
+ /** @hide */
+ public void writePoliciesToXml(XmlSerializer out)
+ throws IllegalArgumentException, IllegalStateException, IOException {
+ out.attribute(null, "flags", Integer.toString(mUsesPolicies));
+ }
+
+ /** @hide */
+ public void readPoliciesFromXml(XmlPullParser parser)
+ throws XmlPullParserException, IOException {
+ mUsesPolicies = Integer.parseInt(
+ parser.getAttributeValue(null, "flags"));
+ }
+
public void dump(Printer pw, String prefix) {
pw.println(prefix + "Receiver:");
mReceiver.dump(pw, prefix + " ");
diff --git a/core/java/android/app/DevicePolicyManager.java b/core/java/android/app/DevicePolicyManager.java
index d611807..0e8c1ab 100644
--- a/core/java/android/app/DevicePolicyManager.java
+++ b/core/java/android/app/DevicePolicyManager.java
@@ -49,13 +49,18 @@ public class DevicePolicyManager {
private final Handler mHandler;
- /*package*/ DevicePolicyManager(Context context, Handler handler) {
+ private DevicePolicyManager(Context context, Handler handler) {
mContext = context;
mHandler = handler;
mService = IDevicePolicyManager.Stub.asInterface(
ServiceManager.getService(Context.DEVICE_POLICY_SERVICE));
}
+ /*package*/ static DevicePolicyManager create(Context context, Handler handler) {
+ DevicePolicyManager me = new DevicePolicyManager(context, handler);
+ return me.mService != null ? me : null;
+ }
+
/**
* Activity action: ask the user to add a new device administrator to the system.
* The desired policy is the ComponentName of the policy in the
@@ -133,6 +138,20 @@ public class DevicePolicyManager {
}
/**
+ * @hide
+ */
+ public boolean packageHasActiveAdmins(String packageName) {
+ if (mService != null) {
+ try {
+ return mService.packageHasActiveAdmins(packageName);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed talking with device policy service", e);
+ }
+ }
+ return false;
+ }
+
+ /**
* Remove a current administration component. This can only be called
* by the application that owns the administration component; if you
* try to remove someone else's component, a security exception will be
diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java
index 4598bb5..0ed5eb8 100644
--- a/core/java/android/app/Dialog.java
+++ b/core/java/android/app/Dialog.java
@@ -822,13 +822,15 @@ public class Dialog implements DialogInterface, Window.Callback,
final SearchManager searchManager = (SearchManager) mContext
.getSystemService(Context.SEARCH_SERVICE);
- // associate search with owner activity if possible (otherwise it will default to
- // global search).
+ // associate search with owner activity
final ComponentName appName = getAssociatedActivity();
- final boolean globalSearch = (appName == null);
- searchManager.startSearch(null, false, appName, null, globalSearch);
- dismiss();
- return true;
+ if (appName != null) {
+ searchManager.startSearch(null, false, appName, null, false);
+ dismiss();
+ return true;
+ } else {
+ return false;
+ }
}
/**
diff --git a/core/java/android/app/IDevicePolicyManager.aidl b/core/java/android/app/IDevicePolicyManager.aidl
index ae5c4bf..b138720 100644
--- a/core/java/android/app/IDevicePolicyManager.aidl
+++ b/core/java/android/app/IDevicePolicyManager.aidl
@@ -49,6 +49,7 @@ interface IDevicePolicyManager {
void setActiveAdmin(in ComponentName policyReceiver);
boolean isAdminActive(in ComponentName policyReceiver);
List<ComponentName> getActiveAdmins();
+ boolean packageHasActiveAdmins(String packageName);
void getRemoveWarning(in ComponentName policyReceiver, in RemoteCallback result);
void removeActiveAdmin(in ComponentName policyReceiver);
diff --git a/core/java/android/app/ISearchManager.aidl b/core/java/android/app/ISearchManager.aidl
index 9ba7863..cb03d2c 100644
--- a/core/java/android/app/ISearchManager.aidl
+++ b/core/java/android/app/ISearchManager.aidl
@@ -24,9 +24,8 @@ import android.os.Bundle;
/** @hide */
interface ISearchManager {
- SearchableInfo getSearchableInfo(in ComponentName launchActivity, boolean globalSearch);
+ SearchableInfo getSearchableInfo(in ComponentName launchActivity);
List<SearchableInfo> getSearchablesInGlobalSearch();
- List<SearchableInfo> getSearchablesForWebSearch();
- SearchableInfo getDefaultSearchableForWebSearch();
- void setDefaultWebSearch(in ComponentName component);
+ ComponentName getGlobalSearchActivity();
+ ComponentName getWebSearchActivity();
}
diff --git a/core/java/android/app/SearchDialog.java b/core/java/android/app/SearchDialog.java
index 581b436..af68689 100644
--- a/core/java/android/app/SearchDialog.java
+++ b/core/java/android/app/SearchDialog.java
@@ -16,8 +16,6 @@
package android.app;
-import com.android.common.Patterns;
-import com.android.common.speech.Recognition;
import static android.app.SuggestionsAdapter.getColumnString;
@@ -48,6 +46,7 @@ import android.text.TextWatcher;
import android.util.AndroidRuntimeException;
import android.util.AttributeSet;
import android.util.Log;
+import android.util.Patterns;
import android.view.ContextThemeWrapper;
import android.view.Gravity;
import android.view.KeyEvent;
@@ -274,7 +273,7 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
SearchManager searchManager = (SearchManager)
mContext.getSystemService(Context.SEARCH_SERVICE);
// Try to get the searchable info for the provided component.
- mSearchable = searchManager.getSearchableInfo(componentName, false);
+ mSearchable = searchManager.getSearchableInfo(componentName);
if (mSearchable == null) {
return false;
@@ -313,7 +312,6 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
mLaunchComponent = null;
mAppSearchData = null;
mSearchable = null;
- mActivityContext = null;
mUserQuery = null;
}
@@ -411,7 +409,7 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
updateSearchAppIcon();
updateSearchBadge();
updateQueryHint();
- updateVoiceButton();
+ updateVoiceButton(TextUtils.isEmpty(mUserQuery));
// In order to properly configure the input method (if one is being used), we
// need to let it know if we'll be providing suggestions. Although it would be
@@ -560,10 +558,13 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
/**
* Update the visibility of the voice button. There are actually two voice search modes,
* either of which will activate the button.
+ * @param empty whether the search query text field is empty. If it is, then the other
+ * criteria apply to make the voice button visible. Otherwise the voice button will not
+ * be visible - i.e., if the user has typed a query, remove the voice button.
*/
- private void updateVoiceButton() {
+ private void updateVoiceButton(boolean empty) {
int visibility = View.GONE;
- if (mSearchable.getVoiceSearchEnabled()) {
+ if (mSearchable.getVoiceSearchEnabled() && empty) {
Intent testIntent = null;
if (mSearchable.getVoiceSearchLaunchWebSearch()) {
testIntent = mVoiceWebSearchIntent;
@@ -666,6 +667,7 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
// The user changed the query, remember it.
mUserQuery = s == null ? "" : s.toString();
}
+ updateVoiceButton(TextUtils.isEmpty(s));
}
public void afterTextChanged(Editable s) {
@@ -746,9 +748,6 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
return;
}
SearchableInfo searchable = mSearchable;
- // First stop the existing search before starting voice search, or else we'll end
- // up showing the search dialog again once we return to the app.
- cancel();
try {
if (searchable.getVoiceSearchLaunchWebSearch()) {
getContext().startActivity(mVoiceWebSearchIntent);
@@ -762,6 +761,7 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
// voice search before showing the button. But just in case...
Log.w(LOG_TAG, "Could not find voice search activity");
}
+ dismiss();
}
};
@@ -819,7 +819,7 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
voiceIntent.putExtra(RecognizerIntent.EXTRA_PROMPT, prompt);
voiceIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, language);
voiceIntent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, maxResults);
- voiceIntent.putExtra(Recognition.EXTRA_CALLING_PACKAGE,
+ voiceIntent.putExtra(RecognizerIntent.EXTRA_CALLING_PACKAGE,
searchActivity == null ? null : searchActivity.toShortString());
// Add the values that configure forwarding the results
diff --git a/core/java/android/app/SearchManager.java b/core/java/android/app/SearchManager.java
index ce5f1bf..b54e53d 100644
--- a/core/java/android/app/SearchManager.java
+++ b/core/java/android/app/SearchManager.java
@@ -137,21 +137,11 @@ import java.util.List;
* setDefaultKeyMode(DEFAULT_KEYS_SEARCH_LOCAL); // search within your activity
* setDefaultKeyMode(DEFAULT_KEYS_SEARCH_GLOBAL); // search using platform global search</pre>
*
- * <p><b>How to enable global search with Quick Search Box.</b> In addition to searching within
+ * <p><b>How to start global search.</b> In addition to searching within
* your activity or application, you can also use the Search Manager to invoke a platform-global
- * search, which uses Quick Search Box to search across the device and the web. There are two ways
- * to do this:
- * <ul><li>You can simply define "search" within your application or activity to mean global search.
- * This is described in more detail in the
- * <a href="#SearchabilityMetadata">Searchability Metadata</a> section. Briefly, you will
- * add a single meta-data entry to your manifest, declaring that the default search
- * for your application is "*". This indicates to the system that no application-specific
- * search activity is provided, and that it should launch web-based search instead.</li>
- * <li>Simply do nothing and the default implementation of
- * {@link android.app.Activity#onSearchRequested} will cause global search to be triggered.
- * (You can also always trigger search via a direct call to {@link android.app.Activity#startSearch}.
- * This is most useful if you wish to provide local searchability <i>and</i> access to global
- * search.)</li></ul>
+ * search, which uses Quick Search Box to search across the device and the web.
+ * Override {@link android.app.Activity#onSearchRequested} and call
+ * {@link android.app.Activity#startSearch} with {@code globalSearch} set to {@code true}.
*
* <p><b>How to disable search from your activity.</b> Search is a system-wide feature and users
* will expect it to be available in all contexts. If your UI design absolutely precludes
@@ -871,12 +861,8 @@ import java.util.List;
*
* <p>The simplest way to specify this is to add a <i>search reference</i> element to the
* application entry in the <a href="{@docRoot}guide/topics/manifest/manifest-intro.html">manifest</a> file.
- * The value of this reference can be either of:
- * <ul><li>The name of your searchable activity.
- * It is typically prefixed by '.' to indicate that it's in the same package.</li>
- * <li>A "*" indicates that the system may select a default searchable activity, in which
- * case it will typically select web-based search.</li>
- * </ul>
+ * The value of this reference should be the name of your searchable activity.
+ * It is typically prefixed by '.' to indicate that it's in the same package.
*
* <p>Here is a snippet showing the necessary addition to the manifest entry for your
* non-searchable activities.
@@ -1639,6 +1625,7 @@ public class SearchManager
return;
}
Intent intent = new Intent(INTENT_ACTION_GLOBAL_SEARCH);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setComponent(globalSearchActivity);
// TODO: Always pass name of calling package as an extra?
if (appSearchData != null) {
@@ -1661,32 +1648,15 @@ public class SearchManager
/**
* Gets the name of the global search activity.
*
- * This is currently implemented by returning the first activity that handles
- * the GLOBAL_SEARCH intent and has the GLOBAL_SEARCH permission. If we allow
- * more than one global search acitivity to be installed, this code must be changed.
- *
- * TODO: Doing this every time we start global search is inefficient. Will fix that once
- * we have settled on the right mechanism for finding the global search activity.
- *
* @hide
*/
public ComponentName getGlobalSearchActivity() {
- Intent intent = new Intent(INTENT_ACTION_GLOBAL_SEARCH);
- PackageManager pm = mContext.getPackageManager();
- List<ResolveInfo> activities =
- pm.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
- int count = activities.size();
- for (int i = 0; i < count; i++) {
- ActivityInfo ai = activities.get(i).activityInfo;
- if (pm.checkPermission(Manifest.permission.GLOBAL_SEARCH,
- ai.packageName) == PackageManager.PERMISSION_GRANTED) {
- return new ComponentName(ai.packageName, ai.name);
- } else {
- Log.w(TAG, "Package " + ai.packageName + " wants to handle GLOBAL_SEARCH, "
- + "but does not have the GLOBAL_SEARCH permission.");
- }
+ try {
+ return mService.getGlobalSearchActivity();
+ } catch (RemoteException ex) {
+ Log.e(TAG, "getGlobalSearchActivity() failed: " + ex);
+ return null;
}
- return null;
}
/**
@@ -1699,13 +1669,12 @@ public class SearchManager
* @hide
*/
public ComponentName getWebSearchActivity() {
- ComponentName globalSearch = getGlobalSearchActivity();
- if (globalSearch == null) {
+ try {
+ return mService.getWebSearchActivity();
+ } catch (RemoteException ex) {
+ Log.e(TAG, "getWebSearchActivity() failed: " + ex);
return null;
}
- Intent intent = new Intent(Intent.ACTION_WEB_SEARCH);
- intent.setPackage(globalSearch.getPackageName());
- return intent.resolveActivity(mContext.getPackageManager());
}
/**
@@ -1839,27 +1808,7 @@ public class SearchManager
*/
public SearchableInfo getSearchableInfo(ComponentName componentName) {
try {
- return mService.getSearchableInfo(componentName, false);
- } catch (RemoteException ex) {
- Log.e(TAG, "getSearchableInfo() failed: " + ex);
- return null;
- }
- }
-
- /**
- * Gets information about a searchable activity.
- *
- * @param componentName The activity to get searchable information for.
- * @param globalSearch If <code>false</code>, return information about the given activity.
- * If <code>true</code>, return information about the global search activity.
- * @return Searchable information, or <code>null</code> if the activity is not searchable.
- *
- * @hide because SearchableInfo is not part of the API.
- */
- public SearchableInfo getSearchableInfo(ComponentName componentName,
- boolean globalSearch) {
- try {
- return mService.getSearchableInfo(componentName, globalSearch);
+ return mService.getSearchableInfo(componentName);
} catch (RemoteException ex) {
Log.e(TAG, "getSearchableInfo() failed: " + ex);
return null;
diff --git a/core/java/android/app/UiModeManager.java b/core/java/android/app/UiModeManager.java
new file mode 100644
index 0000000..aca8ab4
--- /dev/null
+++ b/core/java/android/app/UiModeManager.java
@@ -0,0 +1,83 @@
+package android.app;
+
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.Log;
+
+/**
+ * This class provides access to the system uimode services. These services
+ * allow applications to control UI modes of the device.
+ * It provides functionality to disable the car mode and it gives access to the
+ * night mode settings.
+ *
+ * <p>You do not instantiate this class directly; instead, retrieve it through
+ * {@link android.content.Context#getSystemService
+ * Context.getSystemService(Context.UI_MODE_SERVICE)}.
+ */
+public class UiModeManager {
+ private static final String TAG = "UiModeManager";
+
+ public static final int MODE_NOTNIGHT = 1;
+ public static final int MODE_NIGHT = 2;
+ public static final int MODE_AUTO = 3;
+
+ private IUiModeManager mService;
+
+ /*package*/ UiModeManager() {
+ mService = IUiModeManager.Stub.asInterface(
+ ServiceManager.getService("uimode"));
+ }
+
+ /**
+ * Disables the car mode.
+ */
+ public void disableCarMode() {
+ if (mService != null) {
+ try {
+ mService.disableCarMode();
+ } catch (RemoteException e) {
+ Log.e(TAG, "disableCarMode: RemoteException", e);
+ }
+ }
+ }
+
+ /**
+ * Sets the night mode. Changes to the night mode are only effective when
+ * the car mode is enabled on a device.
+ *
+ * <p>The mode can be one of:
+ * <ul>
+ * <li><em>{@link #MODE_NOTNIGHT}<em> - sets the device into notnight
+ * mode.</li>
+ * <li><em>{@link #MODE_NIGHT}</em> - sets the device into night mode.
+ * </li>
+ * <li><em>{@link #MODE_AUTO}</em> - automatic night/notnight switching
+ * depending on the location and certain other sensors.</li>
+ */
+ public void setNightMode(int mode) {
+ if (mService != null) {
+ try {
+ mService.setNightMode(mode);
+ } catch (RemoteException e) {
+ Log.e(TAG, "setNightMode: RemoteException", e);
+ }
+ }
+ }
+
+ /**
+ * Returns the currently configured night mode.
+ *
+ * @return {@link #MODE_NOTNIGHT}, {@link #MODE_NIGHT} or {@link #MODE_AUTO}
+ * When an error occurred -1 is returned.
+ */
+ public int getNightMode() {
+ if (mService != null) {
+ try {
+ return mService.getNightMode();
+ } catch (RemoteException e) {
+ Log.e(TAG, "getNightMode: RemoteException", e);
+ }
+ }
+ return -1;
+ }
+}
diff --git a/core/java/android/backup/AbsoluteFileBackupHelper.java b/core/java/android/backup/AbsoluteFileBackupHelper.java
index 6bf848f..5a8034b 100644
--- a/core/java/android/backup/AbsoluteFileBackupHelper.java
+++ b/core/java/android/backup/AbsoluteFileBackupHelper.java
@@ -21,7 +21,6 @@ import android.os.ParcelFileDescriptor;
import android.util.Log;
import java.io.File;
-import java.io.FileDescriptor;
/**
* Like FileBackupHelper, but takes absolute paths for the files instead of
diff --git a/core/java/android/backup/BackupDataInput.java b/core/java/android/backup/BackupDataInput.java
index 295dc66..a08ee75 100644
--- a/core/java/android/backup/BackupDataInput.java
+++ b/core/java/android/backup/BackupDataInput.java
@@ -16,8 +16,6 @@
package android.backup;
-import android.content.Context;
-
import java.io.FileDescriptor;
import java.io.IOException;
diff --git a/core/java/android/backup/BackupDataOutput.java b/core/java/android/backup/BackupDataOutput.java
index 672d01f..34879d8 100644
--- a/core/java/android/backup/BackupDataOutput.java
+++ b/core/java/android/backup/BackupDataOutput.java
@@ -16,8 +16,6 @@
package android.backup;
-import android.content.Context;
-
import java.io.FileDescriptor;
import java.io.IOException;
diff --git a/core/java/android/backup/BackupHelper.java b/core/java/android/backup/BackupHelper.java
index fc48cf2..7eedd01 100644
--- a/core/java/android/backup/BackupHelper.java
+++ b/core/java/android/backup/BackupHelper.java
@@ -18,16 +18,19 @@ package android.backup;
import android.os.ParcelFileDescriptor;
-import java.io.InputStream;
-
/**
- * STOPSHIP: document!
+ * A convenient interface to be used with the
+ * {@link android.backup.BackupHelperAgent} to implement backup and restore of
+ * arbitrary data types.
+ * <p>
+ * STOPSHOP: document!
*/
public interface BackupHelper {
/**
- * Based on oldState, determine which of the files from the application's data directory
- * need to be backed up, write them to the data stream, and fill in newState with the
- * state as it exists now.
+ * Based on <code>oldState</code>, determine which of the files from the
+ * application's data directory need to be backed up, write them to
+ * <code>data</code>, and fill in <code>newState</code> with the state as it
+ * exists now.
*/
public void performBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
ParcelFileDescriptor newState);
diff --git a/core/java/android/backup/BackupHelperAgent.java b/core/java/android/backup/BackupHelperAgent.java
index dc17154f..7fb44f4 100644
--- a/core/java/android/backup/BackupHelperAgent.java
+++ b/core/java/android/backup/BackupHelperAgent.java
@@ -17,24 +17,19 @@
package android.backup;
import android.app.BackupAgent;
-import android.backup.BackupHelper;
-import android.backup.BackupHelperDispatcher;
-import android.backup.BackupDataInput;
-import android.backup.BackupDataOutput;
import android.os.ParcelFileDescriptor;
-import android.util.Log;
import java.io.IOException;
/**
- * A convenient BackupAgent wrapper class that automatically manages heterogeneous
- * data sets within the backup data, each identified by a unique key prefix. An
- * application will typically extend this class in their own backup agent. Then,
- * within the agent's onBackup() and onRestore() methods, it will call
- * {@link #addHelper(String, BackupHelper)} one or more times to specify the data
- * sets, then invoke super.onBackup() or super.onRestore() to have the BackupHelperAgent
- * implementation process the data.
- *
+ * A convenient BackupAgent wrapper class that automatically manages
+ * heterogeneous data sets within the backup data, each identified by a unique
+ * key prefix. An application will typically extend this class in their own
+ * backup agent. Then, within the agent's onBackup() and onRestore() methods, it
+ * will call {@link #addHelper(String, BackupHelper)} one or more times to
+ * specify the data sets, then invoke super.onBackup() or super.onRestore() to
+ * have the BackupHelperAgent implementation process the data.
+ * <p>
* STOPSHIP: document!
*/
public class BackupHelperAgent extends BackupAgent {
diff --git a/core/java/android/backup/BackupHelperDispatcher.java b/core/java/android/backup/BackupHelperDispatcher.java
index bf2c44d..68076db 100644
--- a/core/java/android/backup/BackupHelperDispatcher.java
+++ b/core/java/android/backup/BackupHelperDispatcher.java
@@ -19,12 +19,10 @@ package android.backup;
import android.os.ParcelFileDescriptor;
import android.util.Log;
-import java.io.DataInputStream;
-import java.io.DataOutputStream;
-import java.io.IOException;
import java.io.FileDescriptor;
-import java.util.TreeMap;
+import java.io.IOException;
import java.util.Map;
+import java.util.TreeMap;
/** @hide */
public class BackupHelperDispatcher {
diff --git a/core/java/android/backup/BackupManager.java b/core/java/android/backup/BackupManager.java
index 4bf59eb..2dff975 100644
--- a/core/java/android/backup/BackupManager.java
+++ b/core/java/android/backup/BackupManager.java
@@ -23,33 +23,40 @@ import android.os.ServiceManager;
import android.util.Log;
/**
- * BackupManager is the interface to the system's backup service.
- * Applications simply instantiate one, and then use that instance
- * to communicate with the backup infrastructure.
- *
- * <p>When your application has made changes to data it wishes to have
- * backed up, call {@link #dataChanged()} to notify the backup service.
- * The system will then schedule a backup operation to occur in the near
- * future. Repeated calls to {@link #dataChanged()} have no further effect
- * until the backup operation actually occurs.
- *
- * <p>The backup operation itself begins with the system launching the
- * {@link android.app.BackupAgent} subclass declared in your manifest. See the
+ * BackupManager is the interface to the system's backup service. Applications
+ * simply instantiate one, and then use that instance to communicate with the
+ * backup infrastructure.
+ * <p>
+ * When an application has made changes to data which should be backed up, a
+ * call to {@link #dataChanged()} will notify the backup service. The system
+ * will then schedule a backup operation to occur in the near future. Repeated
+ * calls to {@link #dataChanged()} have no further effect until the backup
+ * operation actually occurs.
+ * <p>
+ * The backup operation itself begins with the system launching the
+ * {@link android.app.BackupAgent} subclass declared in your manifest. See the
* documentation for {@link android.app.BackupAgent} for a detailed description
* of how the backup then proceeds.
- *
- * <p>STOPSHIP more documentation here! Include the attributes:
- * android:backupAgent
- * android:allowBackup
- * android:restoreNeedsApplication
- * android:killAfterRestore
+ * <p>
+ * A simple implementation of a BackupAgent useful for backing up Preferences
+ * and files is available by using {@link android.backup.BackupHelperAgent}.
+ * <p>
+ * STOPSHIP: more documentation!
+ * <p>
+ * <b>XML attributes</b>
+ * <p>
+ * See {@link android.R.styleable#AndroidManifestApplication
+ * AndroidManifest.xml's application attributes}
+ *
+ * @attr ref android.R.styleable#AndroidManifestApplication_allowBackup
+ * @attr ref android.R.styleable#AndroidManifestApplication_backupAgent
+ * @attr ref
+ * android.R.styleable#AndroidManifestApplication_restoreNeedsApplication
+ * @attr ref android.R.styleable#AndroidManifestApplication_killAfterRestore
*/
public class BackupManager {
private static final String TAG = "BackupManager";
- /** @hide TODO: REMOVE THIS */
- public static final boolean EVEN_THINK_ABOUT_DOING_RESTORE = true;
-
private Context mContext;
private static IBackupManager sService;
@@ -78,9 +85,6 @@ public class BackupManager {
* {@link android.app.BackupAgent} subclass will be scheduled when you call this method.
*/
public void dataChanged() {
- if (!EVEN_THINK_ABOUT_DOING_RESTORE) {
- return;
- }
checkServiceBinder();
if (sService != null) {
try {
@@ -100,9 +104,6 @@ public class BackupManager {
* permission if the package named in the argument is not the caller's own.
*/
public static void dataChanged(String packageName) {
- if (!EVEN_THINK_ABOUT_DOING_RESTORE) {
- return;
- }
checkServiceBinder();
if (sService != null) {
try {
@@ -118,9 +119,6 @@ public class BackupManager {
* {@link android.backup.RestoreSession} class for documentation on that process.
*/
public RestoreSession beginRestoreSession() {
- if (!EVEN_THINK_ABOUT_DOING_RESTORE) {
- return null;
- }
RestoreSession session = null;
checkServiceBinder();
if (sService != null) {
diff --git a/core/java/android/backup/FileBackupHelper.java b/core/java/android/backup/FileBackupHelper.java
index 68b4d42..cc859e2 100644
--- a/core/java/android/backup/FileBackupHelper.java
+++ b/core/java/android/backup/FileBackupHelper.java
@@ -21,10 +21,23 @@ import android.os.ParcelFileDescriptor;
import android.util.Log;
import java.io.File;
-import java.io.FileDescriptor;
/**
- * STOPSHIP: document! [manages backup of a set of files; restore is totally opaque]
+ * A helper class which can be used in conjunction with
+ * {@link android.backup.BackupHelperAgent} to manage the backup of a set of
+ * files. Whenever backup is performed, all files changed since the last backup
+ * will be saved in their entirety. During the first time the backup happens,
+ * all the files in the list will be backed up. Note that this should only be
+ * used with small configuration files and not with large binary files.
+ * <p>
+ * Any files not present in the list of files during the restore procedure will
+ * be ignored. If files present in a previous version of an application are
+ * removed in subsequent versions, it is the responsibility of the developer to
+ * design a mechanism to remove those files. Otherwise files no longer needed
+ * will linger and consume space on the device.
+ * <p>
+ * STOPSHIP: document! [manages backup of a set of files; restore is totally
+ * opaque]
*/
public class FileBackupHelper extends FileBackupHelperBase implements BackupHelper {
private static final String TAG = "FileBackupHelper";
@@ -50,9 +63,16 @@ public class FileBackupHelper extends FileBackupHelperBase implements BackupHelp
}
/**
- * Based on oldState, determine which of the files from the application's data directory
- * need to be backed up, write them to the data stream, and fill in newState with the
- * state as it exists now.
+ * Based on <code>oldState</code>, determine which of the files from the
+ * application's data directory need to be backed up, write them to the data
+ * stream, and fill in <code>newState</code> with the state as it exists
+ * now. When <code>oldState</code> is <code>null</code>, all the files will
+ * be backed up.
+ * <p>
+ * This should be called from {@link android.backup.BackupHelperAgent}
+ * directly. See
+ * {@link android.app.BackupAgent#onBackup(ParcelFileDescriptor, BackupDataOutput, ParcelFileDescriptor)}
+ * for a description of parameter meanings.
*/
public void performBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
ParcelFileDescriptor newState) {
diff --git a/core/java/android/backup/FileBackupHelperBase.java b/core/java/android/backup/FileBackupHelperBase.java
index a0ff38b..7cb1ccc 100644
--- a/core/java/android/backup/FileBackupHelperBase.java
+++ b/core/java/android/backup/FileBackupHelperBase.java
@@ -22,10 +22,12 @@ import android.util.Log;
import java.io.File;
import java.io.FileDescriptor;
-import java.io.FileOutputStream;
+/**
+ * Base class for the {@link android.backup.FileBackupHelper} implementation.
+ */
class FileBackupHelperBase {
- private static final String TAG = "RestoreHelperBase";
+ private static final String TAG = "FileBackupHelperBase";
int mPtr;
Context mContext;
@@ -45,8 +47,8 @@ class FileBackupHelperBase {
}
/**
- * Check the parameters so the native code doens't have to throw all the exceptions
- * since it's easier to do that from java.
+ * Check the parameters so the native code doesn't have to throw all the exceptions
+ * since it's easier to do that from Java.
*/
static void performBackup_checked(ParcelFileDescriptor oldState, BackupDataOutput data,
ParcelFileDescriptor newState, String[] files, String[] keys) {
diff --git a/core/java/android/backup/SharedPreferencesBackupHelper.java b/core/java/android/backup/SharedPreferencesBackupHelper.java
index f9c97a3..7ba80db 100644
--- a/core/java/android/backup/SharedPreferencesBackupHelper.java
+++ b/core/java/android/backup/SharedPreferencesBackupHelper.java
@@ -17,13 +17,19 @@
package android.backup;
import android.content.Context;
+import android.content.SharedPreferences;
import android.os.ParcelFileDescriptor;
import android.util.Log;
import java.io.File;
-import java.io.FileDescriptor;
/**
+ * A helper class which can be used in conjunction with
+ * {@link android.backup.BackupHelperAgent} to manage the backup of
+ * {@link android.content.SharedPreferences}. Whenever backup is performed it
+ * will back up all named shared preferences which have changed since the last
+ * backup.
+ * <p>
* STOPSHIP: document!
*/
public class SharedPreferencesBackupHelper extends FileBackupHelperBase implements BackupHelper {
diff --git a/core/java/android/backup/package.html b/core/java/android/backup/package.html
new file mode 100644
index 0000000..13c0eb8
--- /dev/null
+++ b/core/java/android/backup/package.html
@@ -0,0 +1,22 @@
+<HTML>
+<BODY>
+<p>Package containing the backup and restore functionality available to
+applications. All backup management is controlled through
+{@link android.backup.BackupManager}. Individual backup functionality is
+implemented through a subclass {@link android.app.BackupAgent} and a
+simple and easy-to-use implementation is provided in
+{@link android.backup.BackupHelperAgent}.</p>
+
+<p>STOPSHIP: add more documenation and remove Dev Guide link if not written!</p>
+
+<p>The backup APIs let applications:</p>
+<ul>
+ <li>Perform backup of arbitrary data</li>
+ <li>Easily perform backup of Preferences and files</li>
+ <li>Handle restore of data</li>
+</ul>
+
+<p>For a detailed guide to using the backup APIs, see the <a
+href="{@docRoot}guide/topics/backup.html">Backup Dev Guide topic</a>.</p>
+</BODY>
+</HTML>
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index cf9c58f..e77e76f 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -664,6 +664,10 @@ public final class BluetoothDevice implements Parcelable {
* determine which channel to connect to.
* <p>The remote device will be authenticated and communication on this
* socket will be encrypted.
+ * <p>Hint: If you are connecting to a Bluetooth serial board then try
+ * using the well-known SPP UUID 00001101-0000-1000-8000-00805F9B34FB.
+ * However if you are connecting to an Android peer then please generate
+ * your own unique UUID.
* <p>Requires {@link android.Manifest.permission#BLUETOOTH}
*
* @param uuid service record uuid to lookup RFCOMM channel
diff --git a/core/java/android/content/ComponentName.java b/core/java/android/content/ComponentName.java
index c4ba05d..7ca0f01 100644
--- a/core/java/android/content/ComponentName.java
+++ b/core/java/android/content/ComponentName.java
@@ -126,7 +126,7 @@ public final class ComponentName implements Parcelable, Cloneable, Comparable<Co
}
/**
- * The samee as {@link #flattenToString()}, but abbreviates the class
+ * The same as {@link #flattenToString()}, but abbreviates the class
* name if it is a suffix of the package. The result can still be used
* with {@link #unflattenFromString(String)}.
*
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index 45f361e..29f388a 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -167,9 +167,9 @@ public abstract class ContentResolver {
/** @hide */
public static final int SYNC_OBSERVER_TYPE_ALL = 0x7fffffff;
- // Always log queries which take 100ms+; shorter queries are
+ // Always log queries which take 500ms+; shorter queries are
// sampled accordingly.
- private static final int SLOW_THRESHOLD_MILLIS = 100;
+ private static final int SLOW_THRESHOLD_MILLIS = 500;
private final Random mRandom = new Random(); // guarded by itself
public ContentResolver(Context context) {
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 672e5f7..897d702 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -1204,6 +1204,8 @@ public abstract class Context {
* <dt> {@link #INPUT_METHOD_SERVICE} ("input_method")
* <dd> An {@link android.view.inputmethod.InputMethodManager InputMethodManager}
* for management of input methods.
+ * <dt> {@link #UI_MODE_SERVICE} ("uimode")
+ * <dd> An {@link android.app.UiModeManager} for controlling UI modes.
* </dl>
*
* <p>Note: System services obtained via this API may be closely associated with
@@ -1249,6 +1251,8 @@ public abstract class Context {
* @see android.telephony.TelephonyManager
* @see #INPUT_METHOD_SERVICE
* @see android.view.inputmethod.InputMethodManager
+ * @see #UI_MODE_SERVICE
+ * @see android.app.UiModeManager
*/
public abstract Object getSystemService(String name);
@@ -1511,6 +1515,14 @@ public abstract class Context {
public static final String DEVICE_POLICY_SERVICE = "device_policy";
/**
+ * Use with {@link #getSystemService} to retrieve a
+ * {@link android.app.UiModeManager} for controlling UI modes.
+ *
+ * @see #getSystemService
+ */
+ public static final String UI_MODE_SERVICE = "uimode";
+
+ /**
* Determine whether the given permission is allowed for a particular
* process and user ID running in the system.
*
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 1b0437c..fb3f646 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -34,7 +34,8 @@ import android.os.Parcel;
import android.os.Parcelable;
import android.util.AttributeSet;
import android.util.Log;
-import com.android.common.XmlUtils;
+
+import com.android.internal.util.XmlUtils;
import java.io.IOException;
import java.io.Serializable;
@@ -1316,6 +1317,21 @@ public class Intent implements Parcelable, Cloneable {
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_PACKAGE_CHANGED = "android.intent.action.PACKAGE_CHANGED";
/**
+ * @hide
+ * Broadcast Action: Ask system services if there is any reason to
+ * restart the given package. The data contains the name of the
+ * package.
+ * <ul>
+ * <li> {@link #EXTRA_UID} containing the integer uid assigned to the package.
+ * <li> {@link #EXTRA_PACKAGES} String array of all packages to check.
+ * </ul>
+ *
+ * <p class="note">This is a protected intent that can only be sent
+ * by the system.
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_QUERY_PACKAGE_RESTART = "android.intent.action.QUERY_PACKAGE_RESTART";
+ /**
* Broadcast Action: The user has restarted a package, and all of its
* processes have been killed. All runtime state
* associated with it (processes, alarms, notifications, etc) should
@@ -2098,6 +2114,7 @@ public class Intent implements Parcelable, Cloneable {
* number to call in a {@link android.content.Intent#ACTION_CALL}.
*/
public static final String EXTRA_PHONE_NUMBER = "android.intent.extra.PHONE_NUMBER";
+
/**
* Used as an int extra field in {@link android.content.Intent#ACTION_UID_REMOVED}
* intents to supply the uid the package had been assigned. Also an optional
@@ -2108,6 +2125,11 @@ public class Intent implements Parcelable, Cloneable {
public static final String EXTRA_UID = "android.intent.extra.UID";
/**
+ * @hide String array of package names.
+ */
+ public static final String EXTRA_PACKAGES = "android.intent.extra.PACKAGES";
+
+ /**
* Used as a boolean extra field in {@link android.content.Intent#ACTION_PACKAGE_REMOVED}
* intents to indicate whether this represents a full uninstall (removing
* both the code and its data) or a partial uninstall (leaving its data,
diff --git a/core/java/android/content/IntentFilter.java b/core/java/android/content/IntentFilter.java
index 023c024..452fd8a 100644
--- a/core/java/android/content/IntentFilter.java
+++ b/core/java/android/content/IntentFilter.java
@@ -34,7 +34,8 @@ import android.util.AndroidException;
import android.util.Config;
import android.util.Log;
import android.util.Printer;
-import com.android.common.XmlUtils;
+
+import com.android.internal.util.XmlUtils;
/**
* Structured description of Intent values to be matched. An IntentFilter can
diff --git a/core/java/android/content/SyncStorageEngine.java b/core/java/android/content/SyncStorageEngine.java
index fcb910d..5aad3af 100644
--- a/core/java/android/content/SyncStorageEngine.java
+++ b/core/java/android/content/SyncStorageEngine.java
@@ -18,7 +18,7 @@ package android.content;
import com.android.internal.os.AtomicFile;
import com.android.internal.util.ArrayUtils;
-import com.android.common.FastXmlSerializer;
+import com.android.internal.util.FastXmlSerializer;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 2e405c1..8773f59 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -248,6 +248,19 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
public static final int FLAG_NATIVE_DEBUGGABLE = 1<<21;
/**
+ * Value for {@link #flags}: Set to true if the application's backup
+ * agent claims to be able to handle restore data even "from the future,"
+ * i.e. from versions of the application with a versionCode greater than
+ * the one currently installed on the device.
+ *
+ * <p>If android:allowBackup is set to false or no android:backupAgent
+ * is specified, this flag will be ignored.
+ *
+ * {@hide}
+ */
+ public static final int FLAG_RESTORE_ANY_VERSION = 1<<22;
+
+ /**
* Flags associated with the application. Any combination of
* {@link #FLAG_SYSTEM}, {@link #FLAG_DEBUGGABLE}, {@link #FLAG_HAS_CODE},
* {@link #FLAG_PERSISTENT}, {@link #FLAG_FACTORY_TEST}, and
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index f793a00..399a87d 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -309,7 +309,7 @@ interface IPackageManager {
* MountService uses this to call into the package manager to update
* status of sdcard.
*/
- void updateExternalMediaStatus(boolean mounted);
+ boolean updateExternalMediaStatus(boolean mounted);
String nextPackageToClean(String lastPackage);
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 5823560..b07bafc 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -30,12 +30,14 @@ import android.content.res.XmlResourceParser;
import android.os.Build;
import android.os.Bundle;
import android.os.PatternMatcher;
+import android.provider.Settings;
import android.util.AttributeSet;
import android.util.Config;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.TypedValue;
-import com.android.common.XmlUtils;
+
+import com.android.internal.util.XmlUtils;
import java.io.File;
import java.io.IOException;
@@ -710,9 +712,10 @@ public class PackageParser {
com.android.internal.R.styleable.AndroidManifest_sharedUserLabel, 0);
}
sa.recycle();
+
pkg.installLocation = sa.getInteger(
com.android.internal.R.styleable.AndroidManifest_installLocation,
- PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY);
+ PackageInfo.INSTALL_LOCATION_AUTO);
// Resource boolean are -1, so 1 means we don't know the value.
int supportsSmallScreens = 1;
@@ -1369,8 +1372,8 @@ public class PackageParser {
if (allowBackup) {
ai.flags |= ApplicationInfo.FLAG_ALLOW_BACKUP;
- // backupAgent, killAfterRestore, and restoreNeedsApplication are only relevant
- // if backup is possible for the given application.
+ // backupAgent, killAfterRestore, restoreNeedsApplication, and restoreAnyVersion
+ // are only relevant if backup is possible for the given application.
String backupAgent = sa.getNonResourceString(
com.android.internal.R.styleable.AndroidManifestApplication_backupAgent);
if (backupAgent != null) {
@@ -1390,6 +1393,11 @@ public class PackageParser {
false)) {
ai.flags |= ApplicationInfo.FLAG_RESTORE_NEEDS_APPLICATION;
}
+ if (sa.getBoolean(
+ com.android.internal.R.styleable.AndroidManifestApplication_restoreAnyVersion,
+ false)) {
+ ai.flags |= ApplicationInfo.FLAG_RESTORE_ANY_VERSION;
+ }
}
}
diff --git a/core/java/android/content/pm/RegisteredServicesCache.java b/core/java/android/content/pm/RegisteredServicesCache.java
index a885820..b74c073 100644
--- a/core/java/android/content/pm/RegisteredServicesCache.java
+++ b/core/java/android/content/pm/RegisteredServicesCache.java
@@ -43,7 +43,7 @@ import java.io.IOException;
import java.io.FileInputStream;
import com.android.internal.os.AtomicFile;
-import com.android.common.FastXmlSerializer;
+import com.android.internal.util.FastXmlSerializer;
import com.google.android.collect.Maps;
import com.google.android.collect.Lists;
diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java
index 7f9a5c6..1070f08 100644
--- a/core/java/android/content/res/AssetManager.java
+++ b/core/java/android/content/res/AssetManager.java
@@ -24,6 +24,7 @@ import android.util.TypedValue;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
+import java.util.HashMap;
/**
* Provides access to an application's raw asset files; see {@link Resources}
@@ -59,6 +60,8 @@ public final class AssetManager {
private static final String TAG = "AssetManager";
private static final boolean localLOGV = Config.LOGV || false;
+ private static final boolean DEBUG_REFS = false;
+
private static final Object sSync = new Object();
private static AssetManager sSystem = null;
@@ -72,6 +75,7 @@ public final class AssetManager {
private int mNumRefs = 1;
private boolean mOpen = true;
+ private HashMap<Integer, RuntimeException> mRefStacks;
/**
* Create a new AssetManager containing only the basic system assets.
@@ -82,6 +86,10 @@ public final class AssetManager {
*/
public AssetManager() {
synchronized (this) {
+ if (DEBUG_REFS) {
+ mNumRefs = 0;
+ incRefsLocked(this.hashCode());
+ }
init();
if (localLOGV) Log.v(TAG, "New asset manager: " + this);
ensureSystemAssets();
@@ -99,6 +107,12 @@ public final class AssetManager {
}
private AssetManager(boolean isSystem) {
+ if (DEBUG_REFS) {
+ synchronized (this) {
+ mNumRefs = 0;
+ incRefsLocked(this.hashCode());
+ }
+ }
init();
if (localLOGV) Log.v(TAG, "New asset manager: " + this);
}
@@ -122,7 +136,7 @@ public final class AssetManager {
// + ", released=" + mReleased);
if (mOpen) {
mOpen = false;
- decRefsLocked();
+ decRefsLocked(this.hashCode());
}
}
}
@@ -298,8 +312,9 @@ public final class AssetManager {
}
int asset = openAsset(fileName, accessMode);
if (asset != 0) {
- mNumRefs++;
- return new AssetInputStream(asset);
+ AssetInputStream res = new AssetInputStream(asset);
+ incRefsLocked(res.hashCode());
+ return res;
}
}
throw new FileNotFoundException("Asset file: " + fileName);
@@ -389,8 +404,9 @@ public final class AssetManager {
}
int asset = openNonAssetNative(cookie, fileName, accessMode);
if (asset != 0) {
- mNumRefs++;
- return new AssetInputStream(asset);
+ AssetInputStream res = new AssetInputStream(asset);
+ incRefsLocked(res.hashCode());
+ return res;
}
}
throw new FileNotFoundException("Asset absolute file: " + fileName);
@@ -468,16 +484,17 @@ public final class AssetManager {
}
int xmlBlock = openXmlAssetNative(cookie, fileName);
if (xmlBlock != 0) {
- mNumRefs++;
- return new XmlBlock(this, xmlBlock);
+ XmlBlock res = new XmlBlock(this, xmlBlock);
+ incRefsLocked(res.hashCode());
+ return res;
}
}
throw new FileNotFoundException("Asset XML file: " + fileName);
}
- /*package*/ void xmlBlockGone() {
+ /*package*/ void xmlBlockGone(int id) {
synchronized (this) {
- decRefsLocked();
+ decRefsLocked(id);
}
}
@@ -486,20 +503,34 @@ public final class AssetManager {
if (!mOpen) {
throw new RuntimeException("Assetmanager has been closed");
}
- mNumRefs++;
- return newTheme();
+ int res = newTheme();
+ incRefsLocked(res);
+ return res;
}
}
/*package*/ final void releaseTheme(int theme) {
synchronized (this) {
deleteTheme(theme);
- decRefsLocked();
+ decRefsLocked(theme);
}
}
protected void finalize() throws Throwable {
- destroy();
+ try {
+ if (DEBUG_REFS && mNumRefs != 0) {
+ Log.w(TAG, "AssetManager " + this
+ + " finalized with non-zero refs: " + mNumRefs);
+ if (mRefStacks != null) {
+ for (RuntimeException e : mRefStacks.values()) {
+ Log.w(TAG, "Reference from here", e);
+ }
+ }
+ }
+ destroy();
+ } finally {
+ super.finalize();
+ }
}
public final class AssetInputStream extends InputStream {
@@ -526,7 +557,7 @@ public final class AssetManager {
if (mAsset != 0) {
destroyAsset(mAsset);
mAsset = 0;
- decRefsLocked();
+ decRefsLocked(hashCode());
}
}
}
@@ -710,7 +741,22 @@ public final class AssetManager {
private native final void init();
private native final void destroy();
- private final void decRefsLocked() {
+ private final void incRefsLocked(int id) {
+ if (DEBUG_REFS) {
+ if (mRefStacks == null) {
+ mRefStacks = new HashMap<Integer, RuntimeException>();
+ RuntimeException ex = new RuntimeException();
+ ex.fillInStackTrace();
+ mRefStacks.put(this.hashCode(), ex);
+ }
+ }
+ mNumRefs++;
+ }
+
+ private final void decRefsLocked(int id) {
+ if (DEBUG_REFS && mRefStacks != null) {
+ mRefStacks.remove(id);
+ }
mNumRefs--;
//System.out.println("Dec streams: mNumRefs=" + mNumRefs
// + " mReleased=" + mReleased);
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index a5e39d4..0608cc0 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -17,7 +17,7 @@
package android.content.res;
-import com.android.common.XmlUtils;
+import com.android.internal.util.XmlUtils;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
diff --git a/core/java/android/content/res/StringBlock.java b/core/java/android/content/res/StringBlock.java
index 2411177..5e90b91 100644
--- a/core/java/android/content/res/StringBlock.java
+++ b/core/java/android/content/res/StringBlock.java
@@ -24,7 +24,8 @@ import android.util.SparseArray;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.Typeface;
-import com.android.common.XmlUtils;
+
+import com.android.internal.util.XmlUtils;
/**
* Conveniences for retrieving data out of a compiled string resource.
diff --git a/core/java/android/content/res/TypedArray.java b/core/java/android/content/res/TypedArray.java
index 8f0003b..a7fb31d 100644
--- a/core/java/android/content/res/TypedArray.java
+++ b/core/java/android/content/res/TypedArray.java
@@ -5,7 +5,8 @@ import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.TypedValue;
-import com.android.common.XmlUtils;
+
+import com.android.internal.util.XmlUtils;
import java.util.Arrays;
diff --git a/core/java/android/content/res/XmlBlock.java b/core/java/android/content/res/XmlBlock.java
index f800232..ad1bfb2 100644
--- a/core/java/android/content/res/XmlBlock.java
+++ b/core/java/android/content/res/XmlBlock.java
@@ -17,7 +17,8 @@
package android.content.res;
import android.util.TypedValue;
-import com.android.common.XmlUtils;
+
+import com.android.internal.util.XmlUtils;
import org.xmlpull.v1.XmlPullParserException;
@@ -59,7 +60,7 @@ final class XmlBlock {
if (mOpenCount == 0) {
nativeDestroy(mNative);
if (mAssets != null) {
- mAssets.xmlBlockGone();
+ mAssets.xmlBlockGone(hashCode());
}
}
}
diff --git a/core/java/android/database/sqlite/SQLiteCompiledSql.java b/core/java/android/database/sqlite/SQLiteCompiledSql.java
index eb85822..a7a1d9a 100644
--- a/core/java/android/database/sqlite/SQLiteCompiledSql.java
+++ b/core/java/android/database/sqlite/SQLiteCompiledSql.java
@@ -95,12 +95,16 @@ import android.util.Log;
}
}
- /* package */ synchronized boolean isInUse() {
- return mInUse;
- }
-
- /* package */ synchronized void acquire() {
+ /**
+ * returns true if acquire() succeeds. false otherwise.
+ */
+ /* package */ synchronized boolean acquire() {
+ if (mInUse) {
+ // someone already has acquired it.
+ return false;
+ }
mInUse = true;
+ return true;
}
/* package */ synchronized void release() {
diff --git a/core/java/android/database/sqlite/SQLiteDatabase.java b/core/java/android/database/sqlite/SQLiteDatabase.java
index 8fd8e28..c13dd23 100644
--- a/core/java/android/database/sqlite/SQLiteDatabase.java
+++ b/core/java/android/database/sqlite/SQLiteDatabase.java
@@ -208,11 +208,11 @@ public class SQLiteDatabase extends SQLiteClosable {
// Things related to query logging/sampling for debugging
// slow/frequent queries during development. Always log queries
- // which take 100ms+; shorter queries are sampled accordingly.
+ // which take 500ms+; shorter queries are sampled accordingly.
// Commit statements, which are typically slow, are logged
// together with the most recently executed SQL statement, for
// disambiguation.
- private static final int QUERY_LOG_TIME_IN_MILLIS = 100;
+ private static final int QUERY_LOG_TIME_IN_MILLIS = 500;
private static final int QUERY_LOG_SQL_LENGTH = 64;
private static final String COMMIT_SQL = "COMMIT;";
private final Random mRandom = new Random();
diff --git a/core/java/android/database/sqlite/SQLiteProgram.java b/core/java/android/database/sqlite/SQLiteProgram.java
index 2bb2f5d..7a29cb4 100644
--- a/core/java/android/database/sqlite/SQLiteProgram.java
+++ b/core/java/android/database/sqlite/SQLiteProgram.java
@@ -57,20 +57,19 @@ public abstract class SQLiteProgram extends SQLiteClosable {
mCompiledSql = new SQLiteCompiledSql(db, sql);
// add it to the cache of compiled-sqls
- db.addToCompiledQueries(sql, mCompiledSql);
+ // but before adding it and thus making it available for anyone else to use it,
+ // make sure it is acquired by me.
mCompiledSql.acquire();
+ db.addToCompiledQueries(sql, mCompiledSql);
} else {
// it is already in compiled-sql cache.
- if (mCompiledSql.isInUse()) {
- // but the CompiledSql in cache is in use by some other SQLiteProgram object.
+ // try to acquire the object.
+ if (!mCompiledSql.acquire()) {
+ // the SQLiteCompiledSql in cache is in use by some other SQLiteProgram object.
// we can't have two different SQLiteProgam objects can't share the same
// CompiledSql object. create a new one.
// finalize it when I am done with it in "this" object.
mCompiledSql = new SQLiteCompiledSql(db, sql);
- } else {
- // the CompiledSql in cache is NOT in use by any other SQLiteProgram object.
- // it is safe to give it to this SQLIteProgram Object.
- mCompiledSql.acquire();
}
}
nStatement = mCompiledSql.nStatement;
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index badb767..c76aca1 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -332,10 +332,10 @@ public class ConnectivityManager
/**
* Sets the value of the setting for background data usage.
- *
+ *
* @param allowBackgroundData Whether an application should use data while
* it is in the background.
- *
+ *
* @attr ref android.Manifest.permission#CHANGE_BACKGROUND_DATA_SETTING
* @see #getBackgroundDataSetting()
* @hide
@@ -346,7 +346,35 @@ public class ConnectivityManager
} catch (RemoteException e) {
}
}
-
+
+ /**
+ * Gets the value of the setting for enabling Mobile data.
+ *
+ * @return Whether mobile data is enabled.
+ * @hide
+ */
+ public boolean getMobileDataEnabled() {
+ try {
+ return mService.getMobileDataEnabled();
+ } catch (RemoteException e) {
+ return true;
+ }
+ }
+
+ /**
+ * Sets the persisted value for enabling/disabling Mobile data.
+ *
+ * @param allowMobileData Whether the mobile data connection should be
+ * used or not.
+ * @hide
+ */
+ public void setMobileDataEnabled(boolean enabled) {
+ try {
+ mService.setMobileDataEnabled(enabled);
+ } catch (RemoteException e) {
+ }
+ }
+
/**
* Don't allow use of default constructor.
*/
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index 508e9c3..2514693 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -51,6 +51,10 @@ interface IConnectivityManager
void setBackgroundDataSetting(boolean allowBackgroundData);
+ boolean getMobileDataEnabled();
+
+ void setMobileDataEnabled(boolean enabled);
+
boolean tether(String iface);
boolean untether(String iface);
diff --git a/core/java/android/net/InterfaceConfiguration.java b/core/java/android/net/InterfaceConfiguration.java
index 9aa23fe..915c5d7 100644
--- a/core/java/android/net/InterfaceConfiguration.java
+++ b/core/java/android/net/InterfaceConfiguration.java
@@ -45,10 +45,10 @@ public class InterfaceConfiguration implements Parcelable {
}
private static void putAddress(StringBuffer buf, int addr) {
- buf.append(addr & 0xff).append('.').
- append((addr >>>= 8) & 0xff).append('.').
- append((addr >>>= 8) & 0xff).append('.').
- append((addr >>>= 8) & 0xff);
+ buf.append((addr >> 24) & 0xff).append('.').
+ append((addr >> 16) & 0xff).append('.').
+ append((addr >> 8) & 0xff).append('.').
+ append(addr & 0xff);
}
/** Implement the Parcelable interface {@hide} */
diff --git a/core/java/android/net/SSLCertificateSocketFactory.java b/core/java/android/net/SSLCertificateSocketFactory.java
index f959fee..6941e57 100644
--- a/core/java/android/net/SSLCertificateSocketFactory.java
+++ b/core/java/android/net/SSLCertificateSocketFactory.java
@@ -16,11 +16,12 @@
package android.net;
+import com.android.internal.net.DomainNameValidator;
+
import android.os.SystemProperties;
import android.util.Config;
import android.util.Log;
-import com.android.common.DomainNameValidator;
import java.io.IOException;
import java.net.InetAddress;
diff --git a/core/java/android/net/WebAddress.java b/core/java/android/net/WebAddress.java
index fa13894..a572f60 100644
--- a/core/java/android/net/WebAddress.java
+++ b/core/java/android/net/WebAddress.java
@@ -16,7 +16,7 @@
package android.net;
-import static com.android.common.Patterns.GOOD_IRI_CHAR;
+import static android.util.Patterns.GOOD_IRI_CHAR;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
diff --git a/common/java/com/android/common/AndroidHttpClient.java b/core/java/android/net/http/AndroidHttpClient.java
index 4c65eb0..3517737 100644
--- a/common/java/com/android/common/AndroidHttpClient.java
+++ b/core/java/android/net/http/AndroidHttpClient.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.common;
+package android.net.http;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
@@ -36,7 +36,6 @@ import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
-import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.client.RequestWrapper;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
@@ -55,7 +54,6 @@ import java.io.OutputStream;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
import java.net.URI;
-import java.security.KeyManagementException;
import android.content.Context;
import android.content.ContentResolver;
diff --git a/core/java/android/net/http/CertificateChainValidator.java b/core/java/android/net/http/CertificateChainValidator.java
index e1327dd..c527fe4 100644
--- a/core/java/android/net/http/CertificateChainValidator.java
+++ b/core/java/android/net/http/CertificateChainValidator.java
@@ -16,7 +16,8 @@
package android.net.http;
-import com.android.common.DomainNameValidator;
+
+import com.android.internal.net.DomainNameValidator;
import org.apache.harmony.xnet.provider.jsse.SSLParameters;
diff --git a/common/java/com/android/common/HttpDateTime.java b/core/java/android/net/http/HttpDateTime.java
index f4052cc..c7a31ee 100644
--- a/common/java/com/android/common/HttpDateTime.java
+++ b/core/java/android/net/http/HttpDateTime.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.common;
+package android.net.http;
import android.text.format.Time;
@@ -22,8 +22,9 @@ import java.util.Calendar;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-
-/** {@hide} */
+/**
+ * Helper for parsing an HTTP date.
+ */
public final class HttpDateTime {
/*
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index b706c5c..56a05ee 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -750,11 +750,8 @@ public abstract class BatteryStats implements Parcelable {
* Checkin server version of dump to produce more compact, computer-readable log.
*
* NOTE: all times are expressed in 'ms'.
- * @param fd
- * @param pw
- * @param which
*/
- private final void dumpCheckinLocked(PrintWriter pw, int which) {
+ public final void dumpCheckinLocked(PrintWriter pw, int which, int reqUid) {
final long rawUptime = SystemClock.uptimeMillis() * 1000;
final long rawRealtime = SystemClock.elapsedRealtime() * 1000;
final long batteryUptime = getBatteryUptime(rawUptime);
@@ -856,19 +853,24 @@ public abstract class BatteryStats implements Parcelable {
getDischargeCurrentLevel());
}
- Map<String, ? extends BatteryStats.Timer> kernelWakelocks = getKernelWakelockStats();
- if (kernelWakelocks.size() > 0) {
- for (Map.Entry<String, ? extends BatteryStats.Timer> ent : kernelWakelocks.entrySet()) {
- sb.setLength(0);
- printWakeLockCheckin(sb, ent.getValue(), batteryRealtime, null, which, "");
-
- dumpLine(pw, 0 /* uid */, category, KERNEL_WAKELOCK_DATA, ent.getKey(),
- sb.toString());
+ if (reqUid < 0) {
+ Map<String, ? extends BatteryStats.Timer> kernelWakelocks = getKernelWakelockStats();
+ if (kernelWakelocks.size() > 0) {
+ for (Map.Entry<String, ? extends BatteryStats.Timer> ent : kernelWakelocks.entrySet()) {
+ sb.setLength(0);
+ printWakeLockCheckin(sb, ent.getValue(), batteryRealtime, null, which, "");
+
+ dumpLine(pw, 0 /* uid */, category, KERNEL_WAKELOCK_DATA, ent.getKey(),
+ sb.toString());
+ }
}
}
for (int iu = 0; iu < NU; iu++) {
final int uid = uidStats.keyAt(iu);
+ if (reqUid >= 0 && uid != reqUid) {
+ continue;
+ }
Uid u = uidStats.valueAt(iu);
// Dump Network stats per uid, if any
long rx = u.getTcpBytesReceived(which);
@@ -987,7 +989,7 @@ public abstract class BatteryStats implements Parcelable {
}
@SuppressWarnings("unused")
- private final void dumpLocked(PrintWriter pw, String prefix, int which) {
+ public final void dumpLocked(PrintWriter pw, String prefix, int which, int reqUid) {
final long rawUptime = SystemClock.uptimeMillis() * 1000;
final long rawRealtime = SystemClock.elapsedRealtime() * 1000;
final long batteryUptime = getBatteryUptime(rawUptime);
@@ -1063,23 +1065,25 @@ public abstract class BatteryStats implements Parcelable {
long fullWakeLockTimeTotalMicros = 0;
long partialWakeLockTimeTotalMicros = 0;
- Map<String, ? extends BatteryStats.Timer> kernelWakelocks = getKernelWakelockStats();
- if (kernelWakelocks.size() > 0) {
- for (Map.Entry<String, ? extends BatteryStats.Timer> ent : kernelWakelocks.entrySet()) {
-
- String linePrefix = ": ";
- sb.setLength(0);
- sb.append(prefix);
- sb.append(" Kernel Wake lock ");
- sb.append(ent.getKey());
- linePrefix = printWakeLock(sb, ent.getValue(), batteryRealtime, null, which,
- linePrefix);
- if (!linePrefix.equals(": ")) {
- sb.append(" realtime");
- } else {
- sb.append(": (nothing executed)");
+ if (reqUid < 0) {
+ Map<String, ? extends BatteryStats.Timer> kernelWakelocks = getKernelWakelockStats();
+ if (kernelWakelocks.size() > 0) {
+ for (Map.Entry<String, ? extends BatteryStats.Timer> ent : kernelWakelocks.entrySet()) {
+
+ String linePrefix = ": ";
+ sb.setLength(0);
+ sb.append(prefix);
+ sb.append(" Kernel Wake lock ");
+ sb.append(ent.getKey());
+ linePrefix = printWakeLock(sb, ent.getValue(), batteryRealtime, null, which,
+ linePrefix);
+ if (!linePrefix.equals(": ")) {
+ sb.append(" realtime");
+ } else {
+ sb.append(": (nothing executed)");
+ }
+ pw.println(sb.toString());
}
- pw.println(sb.toString());
}
}
@@ -1212,7 +1216,12 @@ public abstract class BatteryStats implements Parcelable {
for (int iu=0; iu<NU; iu++) {
final int uid = uidStats.keyAt(iu);
+ if (reqUid >= 0 && uid != reqUid) {
+ continue;
+ }
+
Uid u = uidStats.valueAt(iu);
+
pw.println(prefix + " #" + uid + ":");
boolean uidActivity = false;
@@ -1421,16 +1430,16 @@ public abstract class BatteryStats implements Parcelable {
pw.println("Total Statistics (Current and Historic):");
pw.println(" System starts: " + getStartCount()
+ ", currently on battery: " + getIsOnBattery());
- dumpLocked(pw, "", STATS_TOTAL);
+ dumpLocked(pw, "", STATS_TOTAL, -1);
pw.println("");
pw.println("Last Run Statistics (Previous run of system):");
- dumpLocked(pw, "", STATS_LAST);
+ dumpLocked(pw, "", STATS_LAST, -1);
pw.println("");
pw.println("Current Battery Statistics (Currently running system):");
- dumpLocked(pw, "", STATS_CURRENT);
+ dumpLocked(pw, "", STATS_CURRENT, -1);
pw.println("");
pw.println("Unplugged Statistics (Since last unplugged from power):");
- dumpLocked(pw, "", STATS_UNPLUGGED);
+ dumpLocked(pw, "", STATS_UNPLUGGED, -1);
}
@SuppressWarnings("unused")
@@ -1445,13 +1454,13 @@ public abstract class BatteryStats implements Parcelable {
}
if (isUnpluggedOnly) {
- dumpCheckinLocked(pw, STATS_UNPLUGGED);
+ dumpCheckinLocked(pw, STATS_UNPLUGGED, -1);
}
else {
- dumpCheckinLocked(pw, STATS_TOTAL);
- dumpCheckinLocked(pw, STATS_LAST);
- dumpCheckinLocked(pw, STATS_UNPLUGGED);
- dumpCheckinLocked(pw, STATS_CURRENT);
+ dumpCheckinLocked(pw, STATS_TOTAL, -1);
+ dumpCheckinLocked(pw, STATS_LAST, -1);
+ dumpCheckinLocked(pw, STATS_UNPLUGGED, -1);
+ dumpCheckinLocked(pw, STATS_CURRENT, -1);
}
}
diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java
index 9ee251e..a4c595d 100644
--- a/core/java/android/os/Debug.java
+++ b/core/java/android/os/Debug.java
@@ -541,6 +541,14 @@ href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Lo
public static int getGlobalFreedSize() {
return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_FREED_BYTES);
}
+ public static int getGlobalClassInitCount() {
+ /* number of classes that have been successfully initialized */
+ return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_CLASS_INIT_COUNT);
+ }
+ public static int getGlobalClassInitTime() {
+ /* cumulative elapsed time for class initialization, in usec */
+ return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_CLASS_INIT_TIME);
+ }
public static int getGlobalExternalAllocCount() {
return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_EXT_ALLOCATED_OBJECTS);
}
@@ -584,6 +592,12 @@ href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Lo
public static void resetGlobalFreedSize() {
VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_FREED_BYTES);
}
+ public static void resetGlobalClassInitCount() {
+ VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_CLASS_INIT_COUNT);
+ }
+ public static void resetGlobalClassInitTime() {
+ VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_CLASS_INIT_TIME);
+ }
public static void resetGlobalExternalAllocCount() {
VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_EXT_ALLOCATED_OBJECTS);
}
diff --git a/core/java/android/os/storage/IMountService.aidl b/core/java/android/os/storage/IMountService.aidl
index 79a6cfe..2b2dcf4 100644
--- a/core/java/android/os/storage/IMountService.aidl
+++ b/core/java/android/os/storage/IMountService.aidl
@@ -61,9 +61,12 @@ interface IMountService
/**
* Safely unmount external storage at given mount point.
- * Returns an int consistent with MountServiceResultCode
+ * The unmount is an asynchronous operation. Applications
+ * should register StorageEventListener for storage related
+ * status changes.
+ *
*/
- int unmountVolume(String mountPoint, boolean force);
+ void unmountVolume(String mountPoint, boolean force);
/**
* Format external storage given a mount point.
diff --git a/core/java/android/pim/RecurrenceSet.java b/core/java/android/pim/RecurrenceSet.java
index 5d09fb5..635323e 100644
--- a/core/java/android/pim/RecurrenceSet.java
+++ b/core/java/android/pim/RecurrenceSet.java
@@ -18,7 +18,6 @@ package android.pim;
import android.content.ContentValues;
import android.database.Cursor;
-import android.os.Bundle;
import android.provider.Calendar;
import android.text.TextUtils;
import android.text.format.Time;
@@ -26,6 +25,7 @@ import android.util.Config;
import android.util.Log;
import java.util.List;
+import java.util.regex.Pattern;
/**
* Basic information about a recurrence, following RFC 2445 Section 4.8.5.
@@ -36,6 +36,7 @@ public class RecurrenceSet {
private final static String TAG = "CalendarProvider";
private final static String RULE_SEPARATOR = "\n";
+ private final static String FOLDING_SEPARATOR = "\n ";
// TODO: make these final?
public EventRecurrence[] rrules = null;
@@ -309,7 +310,8 @@ public static boolean populateComponent(ContentValues values,
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;
+ Integer allDayInteger = values.getAsInteger(Calendar.Events.ALL_DAY);
+ boolean allDay = (null != allDayInteger) ? (allDayInteger == 1) : false;
if ((dtstart == -1) ||
(TextUtils.isEmpty(duration))||
@@ -361,7 +363,7 @@ public static boolean populateComponent(ContentValues values,
if (TextUtils.isEmpty(ruleStr)) {
return;
}
- String[] rrules = ruleStr.split(RULE_SEPARATOR);
+ String[] rrules = getRuleStrings(ruleStr);
for (String rrule : rrules) {
ICalendar.Property prop = new ICalendar.Property(propertyName);
prop.setValue(rrule);
@@ -369,6 +371,52 @@ public static boolean populateComponent(ContentValues values,
}
}
+ private static String[] getRuleStrings(String ruleStr) {
+ if (null == ruleStr) {
+ return new String[0];
+ }
+ String unfoldedRuleStr = unfold(ruleStr);
+ String[] split = unfoldedRuleStr.split(RULE_SEPARATOR);
+ int count = split.length;
+ for (int n = 0; n < count; n++) {
+ split[n] = fold(split[n]);
+ }
+ return split;
+ }
+
+
+ private static final Pattern IGNORABLE_ICAL_WHITESPACE_RE =
+ Pattern.compile("(?:\\r\\n?|\\n)[ \t]");
+
+ private static final Pattern FOLD_RE = Pattern.compile(".{75}");
+
+ /**
+ * fold and unfolds ical content lines as per RFC 2445 section 4.1.
+ *
+ * <h3>4.1 Content Lines</h3>
+ *
+ * <p>The iCalendar object is organized into individual lines of text, called
+ * content lines. Content lines are delimited by a line break, which is a CRLF
+ * sequence (US-ASCII decimal 13, followed by US-ASCII decimal 10).
+ *
+ * <p>Lines of text SHOULD NOT be longer than 75 octets, excluding the line
+ * break. Long content lines SHOULD be split into a multiple line
+ * representations using a line "folding" technique. That is, a long line can
+ * be split between any two characters by inserting a CRLF immediately
+ * followed by a single linear white space character (i.e., SPACE, US-ASCII
+ * decimal 32 or HTAB, US-ASCII decimal 9). Any sequence of CRLF followed
+ * immediately by a single linear white space character is ignored (i.e.,
+ * removed) when processing the content type.
+ */
+ public static String fold(String unfoldedIcalContent) {
+ return FOLD_RE.matcher(unfoldedIcalContent).replaceAll("$0\r\n ");
+ }
+
+ public static String unfold(String foldedIcalContent) {
+ return IGNORABLE_ICAL_WHITESPACE_RE.matcher(
+ foldedIcalContent).replaceAll("");
+ }
+
private static void addPropertyForDateStr(ICalendar.Component component,
String propertyName,
String dateStr) {
diff --git a/core/java/android/pim/vcard/VCardComposer.java b/core/java/android/pim/vcard/VCardComposer.java
index 2eb25954..194fe33 100644
--- a/core/java/android/pim/vcard/VCardComposer.java
+++ b/core/java/android/pim/vcard/VCardComposer.java
@@ -26,8 +26,6 @@ import android.database.sqlite.SQLiteException;
import android.net.Uri;
import android.os.RemoteException;
import android.pim.vcard.exception.VCardException;
-import android.provider.CallLog;
-import android.provider.CallLog.Calls;
import android.provider.ContactsContract.Contacts;
import android.provider.ContactsContract.Data;
import android.provider.ContactsContract.RawContacts;
@@ -44,8 +42,6 @@ import android.provider.ContactsContract.CommonDataKinds.Relation;
import android.provider.ContactsContract.CommonDataKinds.StructuredName;
import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
import android.provider.ContactsContract.CommonDataKinds.Website;
-import android.text.TextUtils;
-import android.text.format.Time;
import android.util.CharsetUtils;
import android.util.Log;
@@ -60,7 +56,6 @@ import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.nio.charset.UnsupportedCharsetException;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -125,12 +120,6 @@ public class VCardComposer {
public static final String VCARD_TYPE_STRING_DOCOMO = "docomo";
- // Property for call log entry
- private static final String VCARD_PROPERTY_X_TIMESTAMP = "X-IRMC-CALL-DATETIME";
- private static final String VCARD_PROPERTY_CALLTYPE_INCOMING = "INCOMING";
- private static final String VCARD_PROPERTY_CALLTYPE_OUTGOING = "OUTGOING";
- private static final String VCARD_PROPERTY_CALLTYPE_MISSED = "MISSED";
-
private static final String SHIFT_JIS = "SHIFT_JIS";
private static final String UTF_8 = "UTF-8";
@@ -275,30 +264,14 @@ public class VCardComposer {
private final String mCharsetString;
private boolean mTerminateIsCalled;
- final private List<OneEntryHandler> mHandlerList;
+ private final List<OneEntryHandler> mHandlerList;
private String mErrorReason = NO_ERROR;
- private boolean mIsCallLogComposer;
-
private static final String[] sContactsProjection = new String[] {
Contacts._ID,
};
- /** The projection to use when querying the call log table */
- private static final String[] sCallLogProjection = new String[] {
- Calls.NUMBER, Calls.DATE, Calls.TYPE, Calls.CACHED_NAME, Calls.CACHED_NUMBER_TYPE,
- Calls.CACHED_NUMBER_LABEL
- };
- private static final int NUMBER_COLUMN_INDEX = 0;
- private static final int DATE_COLUMN_INDEX = 1;
- private static final int CALL_TYPE_COLUMN_INDEX = 2;
- private static final int CALLER_NAME_COLUMN_INDEX = 3;
- private static final int CALLER_NUMBERTYPE_COLUMN_INDEX = 4;
- private static final int CALLER_NUMBERLABEL_COLUMN_INDEX = 5;
-
- private static final String FLAG_TIMEZONE_UTC = "Z";
-
public VCardComposer(Context context) {
this(context, VCardConfig.VCARD_TYPE_DEFAULT, true);
}
@@ -377,6 +350,7 @@ public class VCardComposer {
if (contentUri == null) {
return false;
}
+
if (mCareHandlerErrors) {
List<OneEntryHandler> finishedList = new ArrayList<OneEntryHandler>(
mHandlerList.size());
@@ -396,10 +370,7 @@ public class VCardComposer {
}
final String[] projection;
- if (CallLog.Calls.CONTENT_URI.equals(contentUri)) {
- projection = sCallLogProjection;
- mIsCallLogComposer = true;
- } else if (Contacts.CONTENT_URI.equals(contentUri) ||
+ if (Contacts.CONTENT_URI.equals(contentUri) ||
CONTACTS_TEST_CONTENT_URI.equals(contentUri)) {
projection = sContactsProjection;
} else {
@@ -426,11 +397,7 @@ public class VCardComposer {
return false;
}
- if (mIsCallLogComposer) {
- mIdColumn = -1;
- } else {
- mIdColumn = mCursor.getColumnIndex(Contacts._ID);
- }
+ mIdColumn = mCursor.getColumnIndex(Contacts._ID);
return true;
}
@@ -448,19 +415,14 @@ public class VCardComposer {
mErrorReason = FAILURE_REASON_NOT_INITIALIZED;
return false;
}
- String name = null;
String vcard;
try {
- if (mIsCallLogComposer) {
- vcard = createOneCallLogEntryInternal();
+ if (mIdColumn >= 0) {
+ vcard = createOneEntryInternal(mCursor.getString(mIdColumn),
+ getEntityIteratorMethod);
} else {
- if (mIdColumn >= 0) {
- vcard = createOneEntryInternal(mCursor.getString(mIdColumn),
- getEntityIteratorMethod);
- } else {
- Log.e(LOG_TAG, "Incorrect mIdColumn: " + mIdColumn);
- return true;
- }
+ Log.e(LOG_TAG, "Incorrect mIdColumn: " + mIdColumn);
+ return true;
}
} catch (VCardException e) {
Log.e(LOG_TAG, "VCardException has been thrown: " + e.getMessage());
@@ -468,7 +430,7 @@ public class VCardComposer {
} 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);
+ Log.e(LOG_TAG, "OutOfMemoryError occured. Ignore the entry.");
System.gc();
// TODO: should tell users what happened?
return true;
@@ -630,99 +592,4 @@ public class VCardComposer {
public String getErrorReason() {
return mErrorReason;
}
-
- /**
- * This static function is to compose vCard for phone own number
- */
- public String composeVCardForPhoneOwnNumber(int phonetype, String phoneName,
- String phoneNumber, boolean vcardVer21) {
- final int vcardType = (vcardVer21 ?
- VCardConfig.VCARD_TYPE_V21_GENERIC_UTF8 :
- VCardConfig.VCARD_TYPE_V30_GENERIC_UTF8);
- final VCardBuilder builder = new VCardBuilder(vcardType);
- boolean needCharset = false;
- if (!(VCardUtils.containsOnlyPrintableAscii(phoneName))) {
- needCharset = true;
- }
- builder.appendLine(VCardConstants.PROPERTY_FN, phoneName, needCharset, false);
- builder.appendLine(VCardConstants.PROPERTY_N, phoneName, needCharset, false);
-
- if (!TextUtils.isEmpty(phoneNumber)) {
- String label = Integer.toString(phonetype);
- builder.appendTelLine(phonetype, label, phoneNumber, false);
- }
-
- return builder.toString();
- }
-
- /**
- * Format according to RFC 2445 DATETIME type.
- * The format is: ("%Y%m%dT%H%M%SZ").
- */
- private final String toRfc2455Format(final long millSecs) {
- Time startDate = new Time();
- startDate.set(millSecs);
- String date = startDate.format2445();
- return date + FLAG_TIMEZONE_UTC;
- }
-
- /**
- * Try to append the property line for a call history time stamp field if possible.
- * Do nothing if the call log type gotton from the database is invalid.
- */
- private void tryAppendCallHistoryTimeStampField(final VCardBuilder builder) {
- // Extension for call history as defined in
- // in the Specification for Ic Mobile Communcation - ver 1.1,
- // Oct 2000. This is used to send the details of the call
- // history - missed, incoming, outgoing along with date and time
- // to the requesting device (For example, transferring phone book
- // when connected over bluetooth)
- //
- // e.g. "X-IRMC-CALL-DATETIME;MISSED:20050320T100000Z"
- final int callLogType = mCursor.getInt(CALL_TYPE_COLUMN_INDEX);
- final String callLogTypeStr;
- switch (callLogType) {
- case Calls.INCOMING_TYPE: {
- callLogTypeStr = VCARD_PROPERTY_CALLTYPE_INCOMING;
- break;
- }
- case Calls.OUTGOING_TYPE: {
- callLogTypeStr = VCARD_PROPERTY_CALLTYPE_OUTGOING;
- break;
- }
- case Calls.MISSED_TYPE: {
- callLogTypeStr = VCARD_PROPERTY_CALLTYPE_MISSED;
- break;
- }
- default: {
- Log.w(LOG_TAG, "Call log type not correct.");
- return;
- }
- }
-
- final long dateAsLong = mCursor.getLong(DATE_COLUMN_INDEX);
- builder.appendLine(VCARD_PROPERTY_X_TIMESTAMP,
- Arrays.asList(callLogTypeStr), toRfc2455Format(dateAsLong));
- }
-
- private String createOneCallLogEntryInternal() {
- final VCardBuilder builder = new VCardBuilder(VCardConfig.VCARD_TYPE_V21_GENERIC_UTF8);
- String name = mCursor.getString(CALLER_NAME_COLUMN_INDEX);
- if (TextUtils.isEmpty(name)) {
- name = mCursor.getString(NUMBER_COLUMN_INDEX);
- }
- final boolean needCharset = !(VCardUtils.containsOnlyPrintableAscii(name));
- builder.appendLine(VCardConstants.PROPERTY_FN, name, needCharset, false);
- builder.appendLine(VCardConstants.PROPERTY_N, name, needCharset, false);
-
- final String number = mCursor.getString(NUMBER_COLUMN_INDEX);
- final int type = mCursor.getInt(CALLER_NUMBERTYPE_COLUMN_INDEX);
- String label = mCursor.getString(CALLER_NUMBERLABEL_COLUMN_INDEX);
- if (TextUtils.isEmpty(label)) {
- label = Integer.toString(type);
- }
- builder.appendTelLine(type, label, number, false);
- tryAppendCallHistoryTimeStampField(builder);
- return builder.toString();
- }
}
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index acb8473..1163106 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -3176,6 +3176,56 @@ public final class ContactsContract {
}
/**
+ * Additional columns returned by the {@link Contacts#CONTENT_FILTER_URI} providing the
+ * explanation of why the filter matched the contact. Specifically, they contain the
+ * data type and element that was used for matching.
+ * <p>
+ * This is temporary API, it will need to change when we move to FTS.
+ *
+ * @hide
+ */
+ public static class SearchSnippetColumns {
+
+ /**
+ * The ID of the data row that was matched by the filter.
+ *
+ * @hide
+ */
+ public static final String SNIPPET_DATA_ID = "snippet_data_id";
+
+ /**
+ * The type of data that was matched by the filter.
+ *
+ * @hide
+ */
+ public static final String SNIPPET_MIMETYPE = "snippet_mimetype";
+
+ /**
+ * The {@link CommonDataKinds.CommonColumns#DATA} field of the data row
+ * that was matched by the filter.
+ *
+ * @hide
+ */
+ public static final String SNIPPET_DATA = "snippet_data";
+
+ /**
+ * The {@link CommonDataKinds.CommonColumns#TYPE} field of the data row
+ * that was matched by the filter.
+ *
+ * @hide
+ */
+ public static final String SNIPPET_TYPE = "snippet_type";
+
+ /**
+ * The {@link CommonDataKinds.CommonColumns#LABEL} field of the data row
+ * that was matched by the filter.
+ *
+ * @hide
+ */
+ public static final String SNIPPET_LABEL = "snippet_label";
+ }
+
+ /**
* Container for definitions of common data types stored in the {@link ContactsContract.Data}
* table.
*/
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 14e27eb..b75a8cc 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -374,6 +374,11 @@ public final class Settings {
* In some cases, a matching Activity may not exist, so ensure you
* safeguard against this.
* <p>
+ * The account types available to add via the add account button may be restricted by adding an
+ * {@link #EXTRA_AUTHORITIES} extra to this Intent with one or more syncable content provider's
+ * authorities. Only account types which can sync with that content provider will be offered to
+ * the user.
+ * <p>
* Input: Nothing.
* <p>
* Output: Nothing.
@@ -383,6 +388,24 @@ public final class Settings {
"android.settings.SYNC_SETTINGS";
/**
+ * Activity Action: Show add account screen for creating a new account.
+ * <p>
+ * In some cases, a matching Activity may not exist, so ensure you
+ * safeguard against this.
+ * <p>
+ * The account types available to add may be restricted by adding an {@link #EXTRA_AUTHORITIES}
+ * extra to the Intent with one or more syncable content provider's authorities. Only account
+ * types which can sync with that content provider will be offered to the user.
+ * <p>
+ * Input: Nothing.
+ * <p>
+ * Output: Nothing.
+ */
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_ADD_ACCOUNT =
+ "android.settings.ADD_ACCOUNT_SETTINGS";
+
+ /**
* Activity Action: Show settings for selecting the network operator.
* <p>
* In some cases, a matching Activity may not exist, so ensure you
@@ -468,6 +491,19 @@ public final class Settings {
// End of Intent actions for Settings
+ /**
+ * Activity Extra: Limit available options in launched activity based on the given authority.
+ * <p>
+ * This can be passed as an extra field in an Activity Intent with one or more syncable content
+ * provider's authorities as a String[]. This field is used by some intents to alter the
+ * behavior of the called activity.
+ * <p>
+ * Example: The {@link #ACTION_ADD_ACCOUNT} intent restricts the account types available based
+ * on the authority given.
+ */
+ public static final String EXTRA_AUTHORITIES =
+ "authorities";
+
private static final String JID_RESOURCE_PREFIX = "android";
public static final String AUTHORITY = "settings";
@@ -2430,6 +2466,13 @@ public final class Settings {
public static final String BACKGROUND_DATA = "background_data";
/**
+ * Whether mobile data connections are allowed by the user. See
+ * ConnectivityManager for more info.
+ * @hide
+ */
+ public static final String MOBILE_DATA = "mobile_data";
+
+ /**
* The CDMA roaming mode 0 = Home Networks, CDMA default
* 1 = Roaming on Affiliated networks
* 2 = Roaming on any networks
@@ -3033,11 +3076,11 @@ public final class Settings {
* @hide
*/
public static final String ANR_SHOW_BACKGROUND = "anr_show_background";
-
+
/**
* The {@link ComponentName} string of the service to be used as the voice recognition
* service.
- *
+ *
* @hide
*/
public static final String VOICE_RECOGNITION_SERVICE = "voice_recognition_service";
diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java
index adeef54..d965962 100644
--- a/core/java/android/provider/Telephony.java
+++ b/core/java/android/provider/Telephony.java
@@ -29,8 +29,8 @@ import android.telephony.SmsMessage;
import android.text.TextUtils;
import android.util.Config;
import android.util.Log;
+import android.util.Patterns;
-import com.android.common.Patterns;
import java.util.HashSet;
import java.util.Set;
diff --git a/core/java/android/server/search/SearchManagerService.java b/core/java/android/server/search/SearchManagerService.java
index fbc4a81..caa3144 100644
--- a/core/java/android/server/search/SearchManagerService.java
+++ b/core/java/android/server/search/SearchManagerService.java
@@ -16,20 +16,14 @@
package android.server.search;
-import android.app.ActivityManagerNative;
-import android.app.IActivityWatcher;
+import com.android.internal.content.PackageMonitor;
+
import android.app.ISearchManager;
-import android.app.ISearchManagerCallback;
import android.app.SearchManager;
import android.app.SearchableInfo;
-import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
-import android.content.IntentFilter;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.RemoteException;
import android.util.Log;
import java.util.List;
@@ -42,13 +36,11 @@ public class SearchManagerService extends ISearchManager.Stub {
// general debugging support
private static final String TAG = "SearchManagerService";
- private static final boolean DBG = false;
// Context that the service is running in.
private final Context mContext;
- // This field is initialized in ensureSearchablesCreated(), and then never modified.
- // Only accessed by ensureSearchablesCreated() and getSearchables()
+ // This field is initialized lazily in getSearchables(), and then never modified.
private Searchables mSearchables;
/**
@@ -61,58 +53,28 @@ public class SearchManagerService extends ISearchManager.Stub {
mContext = context;
}
- private synchronized void ensureSearchablesCreated() {
- if (mSearchables != null) return; // already created
-
- mSearchables = new Searchables(mContext);
- mSearchables.buildSearchableList();
-
- IntentFilter packageFilter = new IntentFilter();
- packageFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
- packageFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
- packageFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
- packageFilter.addDataScheme("package");
- mContext.registerReceiver(mPackageChangedReceiver, packageFilter);
- // Register for events related to sdcard installation.
- IntentFilter sdFilter = new IntentFilter();
- sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
- sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
- mContext.registerReceiver(mPackageChangedReceiver, sdFilter);
- }
-
private synchronized Searchables getSearchables() {
- ensureSearchablesCreated();
+ if (mSearchables == null) {
+ mSearchables = new Searchables(mContext);
+ mSearchables.buildSearchableList();
+ new MyPackageMonitor().register(mContext, true);
+ }
return mSearchables;
}
/**
* Refreshes the "searchables" list when packages are added/removed.
*/
- private BroadcastReceiver mPackageChangedReceiver = new BroadcastReceiver() {
+ class MyPackageMonitor extends PackageMonitor {
@Override
- public void onReceive(Context context, Intent intent) {
- String action = intent.getAction();
-
- if (Intent.ACTION_PACKAGE_ADDED.equals(action) ||
- Intent.ACTION_PACKAGE_REMOVED.equals(action) ||
- Intent.ACTION_PACKAGE_CHANGED.equals(action) ||
- Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(action) ||
- Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) {
- if (DBG) Log.d(TAG, "Got " + action);
- // Update list of searchable activities
- getSearchables().buildSearchableList();
- broadcastSearchablesChanged();
- }
+ public void onSomePackagesChanged() {
+ // Update list of searchable activities
+ getSearchables().buildSearchableList();
+ // Inform all listeners that the list of searchables has been updated.
+ Intent intent = new Intent(SearchManager.INTENT_ACTION_SEARCHABLES_CHANGED);
+ intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
+ mContext.sendBroadcast(intent);
}
- };
-
- /**
- * Informs all listeners that the list of searchables has been updated.
- */
- void broadcastSearchablesChanged() {
- Intent intent = new Intent(SearchManager.INTENT_ACTION_SEARCHABLES_CHANGED);
- intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
- mContext.sendBroadcast(intent);
}
//
@@ -123,24 +85,15 @@ public class SearchManagerService extends ISearchManager.Stub {
* Returns the SearchableInfo for a given activity.
*
* @param launchActivity The activity from which we're launching this search.
- * @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.
* @return Returns a SearchableInfo record describing the parameters of the search,
* or null if no searchable metadata was available.
*/
- public SearchableInfo getSearchableInfo(final ComponentName launchActivity,
- final boolean globalSearch) {
- if (globalSearch) {
- return getSearchables().getDefaultSearchable();
- } else {
- if (launchActivity == null) {
- Log.e(TAG, "getSearchableInfo(), activity == null");
- return null;
- }
- return getSearchables().getSearchableInfo(launchActivity);
+ public SearchableInfo getSearchableInfo(final ComponentName launchActivity) {
+ if (launchActivity == null) {
+ Log.e(TAG, "getSearchableInfo(), activity == null");
+ return null;
}
+ return getSearchables().getSearchableInfo(launchActivity);
}
/**
@@ -151,27 +104,17 @@ public class SearchManagerService extends ISearchManager.Stub {
}
/**
- * Returns a list of the searchable activities that handle web searches.
- * Can be called from any thread.
+ * Gets the name of the global search activity.
*/
- public List<SearchableInfo> getSearchablesForWebSearch() {
- return getSearchables().getSearchablesForWebSearchList();
+ public ComponentName getGlobalSearchActivity() {
+ return getSearchables().getGlobalSearchActivity();
}
/**
- * Returns the default searchable activity for web searches.
- * Can be called from any thread.
+ * Gets the name of the web search activity.
*/
- public SearchableInfo getDefaultSearchableForWebSearch() {
- return getSearchables().getDefaultSearchableForWebSearch();
+ public ComponentName getWebSearchActivity() {
+ return getSearchables().getWebSearchActivity();
}
- /**
- * Sets the default searchable activity for web searches.
- * Can be called from any thread.
- */
- public void setDefaultWebSearch(final ComponentName component) {
- getSearchables().setDefaultWebSearch(component);
- broadcastSearchablesChanged();
- }
}
diff --git a/core/java/android/server/search/Searchables.java b/core/java/android/server/search/Searchables.java
index cbb63a5..279c17d 100644
--- a/core/java/android/server/search/Searchables.java
+++ b/core/java/android/server/search/Searchables.java
@@ -16,14 +16,12 @@
package android.server.search;
-import com.android.internal.app.ResolverActivity;
-
+import android.Manifest;
import android.app.SearchManager;
import android.app.SearchableInfo;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
-import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
@@ -52,9 +50,8 @@ public class Searchables {
private HashMap<ComponentName, SearchableInfo> mSearchablesMap = null;
private ArrayList<SearchableInfo> mSearchablesList = null;
private ArrayList<SearchableInfo> mSearchablesInGlobalSearchList = null;
- private ArrayList<SearchableInfo> mSearchablesForWebSearchList = null;
- private SearchableInfo mDefaultSearchable = null;
- private SearchableInfo mDefaultSearchableForWebSearch = null;
+ private ComponentName mGlobalSearchActivity = null;
+ private ComponentName mWebSearchActivity = null;
public static String GOOGLE_SEARCH_COMPONENT_NAME =
"com.android.googlesearch/.GoogleSearch";
@@ -131,10 +128,9 @@ public class Searchables {
// Irrespective of source, if a reference was found, follow it.
if (refActivityName != null)
{
- // An app or activity can declare that we should simply launch
- // "system default search" if search is invoked.
+ // This value is deprecated, return null
if (refActivityName.equals(MD_SEARCHABLE_SYSTEM_SEARCH)) {
- return getDefaultSearchable();
+ return null;
}
String pkg = activity.getPackageName();
ComponentName referredActivity;
@@ -164,20 +160,6 @@ public class Searchables {
}
/**
- * Provides the system-default search activity, which you can use
- * whenever getSearchableInfo() returns null;
- *
- * @return Returns the system-default search activity, null if never defined
- */
- public synchronized SearchableInfo getDefaultSearchable() {
- return mDefaultSearchable;
- }
-
- public synchronized boolean isDefaultSearchable(SearchableInfo searchable) {
- return searchable == mDefaultSearchable;
- }
-
- /**
* Builds an entire list (suitable for display) of
* activities that are searchable, by iterating the entire set of
* ACTION_SEARCH & ACTION_WEB_SEARCH intents.
@@ -205,8 +187,6 @@ public class Searchables {
= new ArrayList<SearchableInfo>();
ArrayList<SearchableInfo> newSearchablesInGlobalSearchList
= new ArrayList<SearchableInfo>();
- ArrayList<SearchableInfo> newSearchablesForWebSearchList
- = new ArrayList<SearchableInfo>();
final PackageManager pm = mContext.getPackageManager();
@@ -244,127 +224,71 @@ public class Searchables {
}
}
- if (webSearchInfoList != null) {
- for (int i = 0; i < webSearchInfoList.size(); ++i) {
- ActivityInfo ai = webSearchInfoList.get(i).activityInfo;
- ComponentName component = new ComponentName(ai.packageName, ai.name);
- SearchableInfo searchable = newSearchablesMap.get(component);
- if (searchable == null) {
- Log.w(LOG_TAG, "did not find component in searchables: " + component);
- } else {
- newSearchablesForWebSearchList.add(searchable);
- }
- }
- }
-
- // Find the global search provider
- Intent globalSearchIntent = new Intent(SearchManager.INTENT_ACTION_GLOBAL_SEARCH);
- ComponentName globalSearchActivity = globalSearchIntent.resolveActivity(pm);
- SearchableInfo newDefaultSearchable = newSearchablesMap.get(globalSearchActivity);
-
- if (newDefaultSearchable == null) {
- Log.w(LOG_TAG, "No searchable info found for new default searchable activity "
- + globalSearchActivity);
- }
+ // Find the global search activity
+ ComponentName newGlobalSearchActivity = findGlobalSearchActivity();
- // Find the default web search provider.
- ComponentName webSearchActivity = getPreferredWebSearchActivity(mContext);
- SearchableInfo newDefaultSearchableForWebSearch = null;
- if (webSearchActivity != null) {
- newDefaultSearchableForWebSearch = newSearchablesMap.get(webSearchActivity);
- }
- if (newDefaultSearchableForWebSearch == null) {
- Log.w(LOG_TAG, "No searchable info found for new default web search activity "
- + webSearchActivity);
- }
+ // Find the web search activity
+ ComponentName newWebSearchActivity = findWebSearchActivity(newGlobalSearchActivity);
// Store a consistent set of new values
synchronized (this) {
mSearchablesMap = newSearchablesMap;
mSearchablesList = newSearchablesList;
mSearchablesInGlobalSearchList = newSearchablesInGlobalSearchList;
- mSearchablesForWebSearchList = newSearchablesForWebSearchList;
- mDefaultSearchable = newDefaultSearchable;
- mDefaultSearchableForWebSearch = newDefaultSearchableForWebSearch;
+ mGlobalSearchActivity = newGlobalSearchActivity;
+ mWebSearchActivity = newWebSearchActivity;
}
}
/**
- * Checks if the given activity component is present in the system and if so makes it the
- * preferred activity for handling ACTION_WEB_SEARCH.
- * @param component Name of the component to check and set as preferred.
- * @param action Intent action for which this activity is to be set as preferred.
- * @return true if component was detected and set as preferred activity, false if not.
+ * Finds the global search activity.
+ *
+ * This is currently implemented by returning the first activity that handles
+ * the GLOBAL_SEARCH intent and has the GLOBAL_SEARCH permission. If we allow
+ * more than one global search activity to be installed, this code must be changed.
*/
- private static boolean setPreferredActivity(Context context,
- ComponentName component, String action) {
- Log.d(LOG_TAG, "Checking component " + component);
- PackageManager pm = context.getPackageManager();
- ActivityInfo ai;
- try {
- ai = pm.getActivityInfo(component, 0);
- } catch (PackageManager.NameNotFoundException e) {
- return false;
- }
-
- // The code here to find the value for bestMatch is heavily inspired by the code
- // in ResolverActivity where the preferred activity is set.
- Intent intent = new Intent(action);
- intent.addCategory(Intent.CATEGORY_DEFAULT);
- List<ResolveInfo> webSearchActivities = pm.queryIntentActivities(intent, 0);
- ComponentName set[] = new ComponentName[webSearchActivities.size()];
- int bestMatch = 0;
- for (int i = 0; i < webSearchActivities.size(); ++i) {
- ResolveInfo ri = webSearchActivities.get(i);
- set[i] = new ComponentName(ri.activityInfo.packageName,
- ri.activityInfo.name);
- if (ri.match > bestMatch) bestMatch = ri.match;
+ private ComponentName findGlobalSearchActivity() {
+ Intent intent = new Intent(SearchManager.INTENT_ACTION_GLOBAL_SEARCH);
+ PackageManager pm = mContext.getPackageManager();
+ List<ResolveInfo> activities =
+ pm.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
+ int count = activities == null ? 0 : activities.size();
+ for (int i = 0; i < count; i++) {
+ ActivityInfo ai = activities.get(i).activityInfo;
+ if (pm.checkPermission(Manifest.permission.GLOBAL_SEARCH,
+ ai.packageName) == PackageManager.PERMISSION_GRANTED) {
+ return new ComponentName(ai.packageName, ai.name);
+ } else {
+ Log.w(LOG_TAG, "Package " + ai.packageName + " wants to handle GLOBAL_SEARCH, "
+ + "but does not have the GLOBAL_SEARCH permission.");
+ }
}
-
- Log.d(LOG_TAG, "Setting preferred web search activity to " + component);
- IntentFilter filter = new IntentFilter(action);
- filter.addCategory(Intent.CATEGORY_DEFAULT);
- pm.replacePreferredActivity(filter, bestMatch, set, component);
- return true;
+ Log.w(LOG_TAG, "No global search activity found");
+ return null;
}
- private static ComponentName getPreferredWebSearchActivity(Context context) {
- // Check if we have a preferred web search activity.
+ /**
+ * Finds the web search activity.
+ *
+ * Only looks in the package of the global search activity.
+ */
+ private ComponentName findWebSearchActivity(ComponentName globalSearchActivity) {
+ if (globalSearchActivity == null) {
+ return null;
+ }
Intent intent = new Intent(Intent.ACTION_WEB_SEARCH);
- PackageManager pm = context.getPackageManager();
- ResolveInfo ri = pm.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY);
-
- if (ri == null || ri.activityInfo.name.equals(ResolverActivity.class.getName())) {
- Log.d(LOG_TAG, "No preferred activity set for action web search.");
-
- // The components in the providers array are checked in the order of declaration so the
- // first one has the highest priority. If the component exists in the system it is set
- // as the preferred activity to handle intent action web search.
- String[] preferredActivities = context.getResources().getStringArray(
- com.android.internal.R.array.default_web_search_providers);
- for (String componentName : preferredActivities) {
- ComponentName component = ComponentName.unflattenFromString(componentName);
- if (setPreferredActivity(context, component, Intent.ACTION_WEB_SEARCH)) {
- return component;
- }
- }
- } else {
- // If the current preferred activity is GoogleSearch, and we detect
- // EnhancedGoogleSearch installed as well, set the latter as preferred since that
- // is a superset and provides more functionality.
- ComponentName cn = new ComponentName(ri.activityInfo.packageName, ri.activityInfo.name);
- if (cn.flattenToShortString().equals(GOOGLE_SEARCH_COMPONENT_NAME)) {
- ComponentName enhancedGoogleSearch = ComponentName.unflattenFromString(
- ENHANCED_GOOGLE_SEARCH_COMPONENT_NAME);
- if (setPreferredActivity(context, enhancedGoogleSearch,
- Intent.ACTION_WEB_SEARCH)) {
- return enhancedGoogleSearch;
- }
- }
+ intent.setPackage(globalSearchActivity.getPackageName());
+ PackageManager pm = mContext.getPackageManager();
+ List<ResolveInfo> activities =
+ pm.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
+ int count = activities == null ? 0 : activities.size();
+ for (int i = 0; i < count; i++) {
+ ActivityInfo ai = activities.get(i).activityInfo;
+ // TODO: do some sanity checks here?
+ return new ComponentName(ai.packageName, ai.name);
}
-
- if (ri == null) return null;
- return new ComponentName(ri.activityInfo.packageName, ri.activityInfo.name);
+ Log.w(LOG_TAG, "No web search activity found");
+ return null;
}
/**
@@ -383,24 +307,16 @@ public class Searchables {
}
/**
- * Returns a list of the searchable activities that handle web searches.
- */
- public synchronized ArrayList<SearchableInfo> getSearchablesForWebSearchList() {
- return new ArrayList<SearchableInfo>(mSearchablesForWebSearchList);
- }
-
- /**
- * Returns the default searchable activity for web searches.
+ * Gets the name of the global search activity.
*/
- public synchronized SearchableInfo getDefaultSearchableForWebSearch() {
- return mDefaultSearchableForWebSearch;
+ public synchronized ComponentName getGlobalSearchActivity() {
+ return mGlobalSearchActivity;
}
/**
- * Sets the default searchable activity for web searches.
+ * Gets the name of the web search activity.
*/
- public synchronized void setDefaultWebSearch(ComponentName component) {
- setPreferredActivity(mContext, component, Intent.ACTION_WEB_SEARCH);
- buildSearchableList();
+ public synchronized ComponentName getWebSearchActivity() {
+ return mWebSearchActivity;
}
}
diff --git a/core/java/android/speech/RecognizerIntent.java b/core/java/android/speech/RecognizerIntent.java
index 7c15cec..bf411e1 100644
--- a/core/java/android/speech/RecognizerIntent.java
+++ b/core/java/android/speech/RecognizerIntent.java
@@ -32,6 +32,15 @@ import android.os.Bundle;
* Constants for supporting speech recognition through starting an {@link Intent}
*/
public class RecognizerIntent {
+ /**
+ * The extra key used in an intent to the speech recognizer for voice search. Not
+ * generally to be used by developers. The system search dialog uses this, for example,
+ * to set a calling package for identification by a voice search API. If this extra
+ * is set by anyone but the system process, it should be overridden by the voice search
+ * implementation.
+ */
+ public final static String EXTRA_CALLING_PACKAGE = "calling_package";
+
private RecognizerIntent() {
// Not for instantiating.
}
diff --git a/core/java/android/test/InstrumentationTestCase.java b/core/java/android/test/InstrumentationTestCase.java
index 22d95d1..cd33d8a 100644
--- a/core/java/android/test/InstrumentationTestCase.java
+++ b/core/java/android/test/InstrumentationTestCase.java
@@ -16,8 +16,6 @@
package android.test;
-import junit.framework.TestCase;
-
import android.app.Activity;
import android.app.Instrumentation;
import android.content.Intent;
@@ -26,9 +24,11 @@ import android.util.Log;
import android.view.KeyEvent;
import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
-import java.lang.reflect.InvocationTargetException;
+
+import junit.framework.TestCase;
/**
* A test case that has access to {@link Instrumentation}.
@@ -86,7 +86,6 @@ public class InstrumentationTestCase extends TestCase {
* @param extras Optional extra stuff to pass to the activity.
* @return The activity, or null if non launched.
*/
- @SuppressWarnings("unchecked")
public final <T extends Activity> T launchActivity(
String pkg,
Class<T> activityCls,
@@ -338,6 +337,7 @@ public class InstrumentationTestCase extends TestCase {
*
* @throws Exception
*/
+ @Override
protected void tearDown() throws Exception {
Runtime.getRuntime().gc();
Runtime.getRuntime().runFinalization();
diff --git a/core/java/android/text/AndroidBidi.java b/core/java/android/text/AndroidBidi.java
new file mode 100644
index 0000000..e4f934e
--- /dev/null
+++ b/core/java/android/text/AndroidBidi.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.text;
+
+/**
+ * Access the ICU bidi implementation.
+ * @hide
+ */
+/* package */ class AndroidBidi {
+
+ public static int bidi(int dir, char[] chs, byte[] chInfo, int n, boolean haveInfo) {
+ if (chs == null || chInfo == null) {
+ throw new NullPointerException();
+ }
+
+ if (n < 0 || chs.length < n || chInfo.length < n) {
+ throw new IndexOutOfBoundsException();
+ }
+
+ switch(dir) {
+ case Layout.DIR_REQUEST_LTR: dir = 0; break;
+ case Layout.DIR_REQUEST_RTL: dir = 1; break;
+ case Layout.DIR_REQUEST_DEFAULT_LTR: dir = -2; break;
+ case Layout.DIR_REQUEST_DEFAULT_RTL: dir = -1; break;
+ default: dir = 0; break;
+ }
+
+ int result = runBidi(dir, chs, chInfo, n, haveInfo);
+ result = (result & 0x1) == 0 ? Layout.DIR_LEFT_TO_RIGHT : Layout.DIR_RIGHT_TO_LEFT;
+ return result;
+ }
+
+ private native static int runBidi(int dir, char[] chs, byte[] chInfo, int n, boolean haveInfo);
+} \ No newline at end of file
diff --git a/core/java/android/text/AutoText.java b/core/java/android/text/AutoText.java
index 862305b..04730ec 100644
--- a/core/java/android/text/AutoText.java
+++ b/core/java/android/text/AutoText.java
@@ -18,7 +18,9 @@ package android.text;
import android.content.res.Resources;
import android.content.res.XmlResourceParser;
-import com.android.common.XmlUtils;
+
+import com.android.internal.util.XmlUtils;
+
import android.view.View;
import org.xmlpull.v1.XmlPullParser;
diff --git a/core/java/android/text/Html.java b/core/java/android/text/Html.java
index 33ecc01..07e71f9 100644
--- a/core/java/android/text/Html.java
+++ b/core/java/android/text/Html.java
@@ -46,7 +46,8 @@ import android.text.style.TypefaceSpan;
import android.text.style.URLSpan;
import android.text.style.UnderlineSpan;
import android.util.Log;
-import com.android.common.XmlUtils;
+
+import com.android.internal.util.XmlUtils;
import java.io.IOException;
import java.io.StringReader;
diff --git a/core/java/android/text/Layout.java b/core/java/android/text/Layout.java
index 1023036..38ac9b7 100644
--- a/core/java/android/text/Layout.java
+++ b/core/java/android/text/Layout.java
@@ -1936,6 +1936,11 @@ public abstract class Layout {
public static final int DIR_LEFT_TO_RIGHT = 1;
public static final int DIR_RIGHT_TO_LEFT = -1;
+
+ /* package */ static final int DIR_REQUEST_LTR = 1;
+ /* package */ static final int DIR_REQUEST_RTL = -1;
+ /* package */ static final int DIR_REQUEST_DEFAULT_LTR = 2;
+ /* package */ static final int DIR_REQUEST_DEFAULT_RTL = -2;
public enum Alignment {
ALIGN_NORMAL,
diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java
index 6c89f92..600ec7e 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -234,215 +234,9 @@ extends Layout
}
if (!easy) {
- AndroidCharacter.getDirectionalities(chs, chdirs, end - start);
-
- /*
- * Determine primary paragraph direction
- */
-
- for (int j = start; j < end; j++) {
- int d = chdirs[j - start];
-
- if (d == Character.DIRECTIONALITY_LEFT_TO_RIGHT) {
- dir = DIR_LEFT_TO_RIGHT;
- break;
- }
- if (d == Character.DIRECTIONALITY_RIGHT_TO_LEFT) {
- dir = DIR_RIGHT_TO_LEFT;
- break;
- }
- }
-
- /*
- * XXX Explicit overrides should go here
- */
-
- /*
- * Weak type resolution
- */
-
- final byte SOR = dir == DIR_LEFT_TO_RIGHT ?
- Character.DIRECTIONALITY_LEFT_TO_RIGHT :
- Character.DIRECTIONALITY_RIGHT_TO_LEFT;
-
- // dump(chdirs, n, "initial");
-
- // W1 non spacing marks
- for (int j = 0; j < n; j++) {
- if (chdirs[j] == Character.NON_SPACING_MARK) {
- if (j == 0)
- chdirs[j] = SOR;
- else
- chdirs[j] = chdirs[j - 1];
- }
- }
-
- // dump(chdirs, n, "W1");
-
- // W2 european numbers
- byte cur = SOR;
- for (int j = 0; j < n; j++) {
- byte d = chdirs[j];
-
- if (d == Character.DIRECTIONALITY_LEFT_TO_RIGHT ||
- d == Character.DIRECTIONALITY_RIGHT_TO_LEFT ||
- d == Character.DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC)
- cur = d;
- else if (d == Character.DIRECTIONALITY_EUROPEAN_NUMBER) {
- if (cur ==
- Character.DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC)
- chdirs[j] = Character.DIRECTIONALITY_ARABIC_NUMBER;
- }
- }
-
- // dump(chdirs, n, "W2");
-
- // W3 arabic letters
- for (int j = 0; j < n; j++) {
- if (chdirs[j] == Character.DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC)
- chdirs[j] = Character.DIRECTIONALITY_RIGHT_TO_LEFT;
- }
-
- // dump(chdirs, n, "W3");
-
- // W4 single separator between numbers
- for (int j = 1; j < n - 1; j++) {
- byte d = chdirs[j];
- byte prev = chdirs[j - 1];
- byte next = chdirs[j + 1];
-
- if (d == Character.DIRECTIONALITY_EUROPEAN_NUMBER_SEPARATOR) {
- if (prev == Character.DIRECTIONALITY_EUROPEAN_NUMBER &&
- next == Character.DIRECTIONALITY_EUROPEAN_NUMBER)
- chdirs[j] = Character.DIRECTIONALITY_EUROPEAN_NUMBER;
- } else if (d == Character.DIRECTIONALITY_COMMON_NUMBER_SEPARATOR) {
- if (prev == Character.DIRECTIONALITY_EUROPEAN_NUMBER &&
- next == Character.DIRECTIONALITY_EUROPEAN_NUMBER)
- chdirs[j] = Character.DIRECTIONALITY_EUROPEAN_NUMBER;
- if (prev == Character.DIRECTIONALITY_ARABIC_NUMBER &&
- next == Character.DIRECTIONALITY_ARABIC_NUMBER)
- chdirs[j] = Character.DIRECTIONALITY_ARABIC_NUMBER;
- }
- }
-
- // dump(chdirs, n, "W4");
-
- // W5 european number terminators
- boolean adjacent = false;
- for (int j = 0; j < n; j++) {
- byte d = chdirs[j];
-
- if (d == Character.DIRECTIONALITY_EUROPEAN_NUMBER)
- adjacent = true;
- else if (d == Character.DIRECTIONALITY_EUROPEAN_NUMBER_TERMINATOR && adjacent)
- chdirs[j] = Character.DIRECTIONALITY_EUROPEAN_NUMBER;
- else
- adjacent = false;
- }
-
- //dump(chdirs, n, "W5");
-
- // W5 european number terminators part 2,
- // W6 separators and terminators
- adjacent = false;
- for (int j = n - 1; j >= 0; j--) {
- byte d = chdirs[j];
-
- if (d == Character.DIRECTIONALITY_EUROPEAN_NUMBER)
- adjacent = true;
- else if (d == Character.DIRECTIONALITY_EUROPEAN_NUMBER_TERMINATOR) {
- if (adjacent)
- chdirs[j] = Character.DIRECTIONALITY_EUROPEAN_NUMBER;
- else
- chdirs[j] = Character.DIRECTIONALITY_OTHER_NEUTRALS;
- }
- else {
- adjacent = false;
-
- if (d == Character.DIRECTIONALITY_EUROPEAN_NUMBER_SEPARATOR ||
- d == Character.DIRECTIONALITY_COMMON_NUMBER_SEPARATOR ||
- d == Character.DIRECTIONALITY_PARAGRAPH_SEPARATOR ||
- d == Character.DIRECTIONALITY_SEGMENT_SEPARATOR)
- chdirs[j] = Character.DIRECTIONALITY_OTHER_NEUTRALS;
- }
- }
-
- // dump(chdirs, n, "W6");
-
- // W7 strong direction of european numbers
- cur = SOR;
- for (int j = 0; j < n; j++) {
- byte d = chdirs[j];
-
- if (d == SOR ||
- d == Character.DIRECTIONALITY_LEFT_TO_RIGHT ||
- d == Character.DIRECTIONALITY_RIGHT_TO_LEFT)
- cur = d;
-
- if (d == Character.DIRECTIONALITY_EUROPEAN_NUMBER)
- chdirs[j] = cur;
- }
-
- // dump(chdirs, n, "W7");
-
- // N1, N2 neutrals
- cur = SOR;
- for (int j = 0; j < n; j++) {
- byte d = chdirs[j];
-
- if (d == Character.DIRECTIONALITY_LEFT_TO_RIGHT ||
- d == Character.DIRECTIONALITY_RIGHT_TO_LEFT) {
- cur = d;
- } else if (d == Character.DIRECTIONALITY_EUROPEAN_NUMBER ||
- d == Character.DIRECTIONALITY_ARABIC_NUMBER) {
- cur = Character.DIRECTIONALITY_RIGHT_TO_LEFT;
- } else {
- byte dd = SOR;
- int k;
-
- for (k = j + 1; k < n; k++) {
- dd = chdirs[k];
-
- if (dd == Character.DIRECTIONALITY_LEFT_TO_RIGHT ||
- dd == Character.DIRECTIONALITY_RIGHT_TO_LEFT) {
- break;
- }
- if (dd == Character.DIRECTIONALITY_EUROPEAN_NUMBER ||
- dd == Character.DIRECTIONALITY_ARABIC_NUMBER) {
- dd = Character.DIRECTIONALITY_RIGHT_TO_LEFT;
- break;
- }
- }
-
- for (int y = j; y < k; y++) {
- if (dd == cur)
- chdirs[y] = cur;
- else
- chdirs[y] = SOR;
- }
-
- j = k - 1;
- }
- }
-
- // dump(chdirs, n, "final");
-
- // extra: enforce that all tabs and surrogate characters go the
- // primary direction
- // TODO: actually do directions right for surrogates
-
- for (int j = 0; j < n; j++) {
- char c = chs[j];
-
- if (c == '\t' || (c >= 0xD800 && c <= 0xDFFF)) {
- chdirs[j] = SOR;
- }
- }
-
- // extra: enforce that object replacements go to the
- // primary direction
- // and that none of the underlying characters are treated
- // as viable breakpoints
+ // Ensure that none of the underlying characters are treated
+ // as viable breakpoints, and that the entire run gets the
+ // same bidi direction.
if (source instanceof Spanned) {
Spanned sp = (Spanned) source;
@@ -453,12 +247,14 @@ extends Layout
int b = sp.getSpanEnd(spans[y]);
for (int x = a; x < b; x++) {
- chdirs[x - start] = SOR;
chs[x - start] = '\uFFFC';
}
}
}
+ // XXX put override flags, etc. into chdirs
+ dir = bidi(dir, chs, chdirs, n, false);
+
// Do mirroring for right-to-left segments
for (int i = 0; i < n; i++) {
@@ -810,6 +606,239 @@ extends Layout
}
}
+ /**
+ * Runs the unicode bidi algorithm on the first n chars in chs, returning
+ * the char dirs in chInfo and the base line direction of the first
+ * paragraph.
+ *
+ * XXX change result from dirs to levels
+ *
+ * @param dir the direction flag, either DIR_REQUEST_LTR,
+ * DIR_REQUEST_RTL, DIR_REQUEST_DEFAULT_LTR, or DIR_REQUEST_DEFAULT_RTL.
+ * @param chs the text to examine
+ * @param chInfo on input, if hasInfo is true, override and other flags
+ * representing out-of-band embedding information. On output, the generated
+ * dirs of the text.
+ * @param n the length of the text/information in chs and chInfo
+ * @param hasInfo true if chInfo has input information, otherwise the
+ * input data in chInfo is ignored.
+ * @return the resolved direction level of the first paragraph, either
+ * DIR_LEFT_TO_RIGHT or DIR_RIGHT_TO_LEFT.
+ */
+ /* package */ static int bidi(int dir, char[] chs, byte[] chInfo, int n,
+ boolean hasInfo) {
+
+ AndroidCharacter.getDirectionalities(chs, chInfo, n);
+
+ /*
+ * Determine primary paragraph direction if not specified
+ */
+ if (dir != DIR_REQUEST_LTR && dir != DIR_REQUEST_RTL) {
+ // set up default
+ dir = dir >= 0 ? DIR_LEFT_TO_RIGHT : DIR_RIGHT_TO_LEFT;
+ for (int j = 0; j < n; j++) {
+ int d = chInfo[j];
+
+ if (d == Character.DIRECTIONALITY_LEFT_TO_RIGHT) {
+ dir = DIR_LEFT_TO_RIGHT;
+ break;
+ }
+ if (d == Character.DIRECTIONALITY_RIGHT_TO_LEFT) {
+ dir = DIR_RIGHT_TO_LEFT;
+ break;
+ }
+ }
+ }
+
+ final byte SOR = dir == DIR_LEFT_TO_RIGHT ?
+ Character.DIRECTIONALITY_LEFT_TO_RIGHT :
+ Character.DIRECTIONALITY_RIGHT_TO_LEFT;
+
+ /*
+ * XXX Explicit overrides should go here
+ */
+
+ /*
+ * Weak type resolution
+ */
+
+ // dump(chdirs, n, "initial");
+
+ // W1 non spacing marks
+ for (int j = 0; j < n; j++) {
+ if (chInfo[j] == Character.NON_SPACING_MARK) {
+ if (j == 0)
+ chInfo[j] = SOR;
+ else
+ chInfo[j] = chInfo[j - 1];
+ }
+ }
+
+ // dump(chdirs, n, "W1");
+
+ // W2 european numbers
+ byte cur = SOR;
+ for (int j = 0; j < n; j++) {
+ byte d = chInfo[j];
+
+ if (d == Character.DIRECTIONALITY_LEFT_TO_RIGHT ||
+ d == Character.DIRECTIONALITY_RIGHT_TO_LEFT ||
+ d == Character.DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC)
+ cur = d;
+ else if (d == Character.DIRECTIONALITY_EUROPEAN_NUMBER) {
+ if (cur ==
+ Character.DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC)
+ chInfo[j] = Character.DIRECTIONALITY_ARABIC_NUMBER;
+ }
+ }
+
+ // dump(chdirs, n, "W2");
+
+ // W3 arabic letters
+ for (int j = 0; j < n; j++) {
+ if (chInfo[j] == Character.DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC)
+ chInfo[j] = Character.DIRECTIONALITY_RIGHT_TO_LEFT;
+ }
+
+ // dump(chdirs, n, "W3");
+
+ // W4 single separator between numbers
+ for (int j = 1; j < n - 1; j++) {
+ byte d = chInfo[j];
+ byte prev = chInfo[j - 1];
+ byte next = chInfo[j + 1];
+
+ if (d == Character.DIRECTIONALITY_EUROPEAN_NUMBER_SEPARATOR) {
+ if (prev == Character.DIRECTIONALITY_EUROPEAN_NUMBER &&
+ next == Character.DIRECTIONALITY_EUROPEAN_NUMBER)
+ chInfo[j] = Character.DIRECTIONALITY_EUROPEAN_NUMBER;
+ } else if (d == Character.DIRECTIONALITY_COMMON_NUMBER_SEPARATOR) {
+ if (prev == Character.DIRECTIONALITY_EUROPEAN_NUMBER &&
+ next == Character.DIRECTIONALITY_EUROPEAN_NUMBER)
+ chInfo[j] = Character.DIRECTIONALITY_EUROPEAN_NUMBER;
+ if (prev == Character.DIRECTIONALITY_ARABIC_NUMBER &&
+ next == Character.DIRECTIONALITY_ARABIC_NUMBER)
+ chInfo[j] = Character.DIRECTIONALITY_ARABIC_NUMBER;
+ }
+ }
+
+ // dump(chdirs, n, "W4");
+
+ // W5 european number terminators
+ boolean adjacent = false;
+ for (int j = 0; j < n; j++) {
+ byte d = chInfo[j];
+
+ if (d == Character.DIRECTIONALITY_EUROPEAN_NUMBER)
+ adjacent = true;
+ else if (d == Character.DIRECTIONALITY_EUROPEAN_NUMBER_TERMINATOR && adjacent)
+ chInfo[j] = Character.DIRECTIONALITY_EUROPEAN_NUMBER;
+ else
+ adjacent = false;
+ }
+
+ //dump(chdirs, n, "W5");
+
+ // W5 european number terminators part 2,
+ // W6 separators and terminators
+ adjacent = false;
+ for (int j = n - 1; j >= 0; j--) {
+ byte d = chInfo[j];
+
+ if (d == Character.DIRECTIONALITY_EUROPEAN_NUMBER)
+ adjacent = true;
+ else if (d == Character.DIRECTIONALITY_EUROPEAN_NUMBER_TERMINATOR) {
+ if (adjacent)
+ chInfo[j] = Character.DIRECTIONALITY_EUROPEAN_NUMBER;
+ else
+ chInfo[j] = Character.DIRECTIONALITY_OTHER_NEUTRALS;
+ }
+ else {
+ adjacent = false;
+
+ if (d == Character.DIRECTIONALITY_EUROPEAN_NUMBER_SEPARATOR ||
+ d == Character.DIRECTIONALITY_COMMON_NUMBER_SEPARATOR ||
+ d == Character.DIRECTIONALITY_PARAGRAPH_SEPARATOR ||
+ d == Character.DIRECTIONALITY_SEGMENT_SEPARATOR)
+ chInfo[j] = Character.DIRECTIONALITY_OTHER_NEUTRALS;
+ }
+ }
+
+ // dump(chdirs, n, "W6");
+
+ // W7 strong direction of european numbers
+ cur = SOR;
+ for (int j = 0; j < n; j++) {
+ byte d = chInfo[j];
+
+ if (d == SOR ||
+ d == Character.DIRECTIONALITY_LEFT_TO_RIGHT ||
+ d == Character.DIRECTIONALITY_RIGHT_TO_LEFT)
+ cur = d;
+
+ if (d == Character.DIRECTIONALITY_EUROPEAN_NUMBER)
+ chInfo[j] = cur;
+ }
+
+ // dump(chdirs, n, "W7");
+
+ // N1, N2 neutrals
+ cur = SOR;
+ for (int j = 0; j < n; j++) {
+ byte d = chInfo[j];
+
+ if (d == Character.DIRECTIONALITY_LEFT_TO_RIGHT ||
+ d == Character.DIRECTIONALITY_RIGHT_TO_LEFT) {
+ cur = d;
+ } else if (d == Character.DIRECTIONALITY_EUROPEAN_NUMBER ||
+ d == Character.DIRECTIONALITY_ARABIC_NUMBER) {
+ cur = Character.DIRECTIONALITY_RIGHT_TO_LEFT;
+ } else {
+ byte dd = SOR;
+ int k;
+
+ for (k = j + 1; k < n; k++) {
+ dd = chInfo[k];
+
+ if (dd == Character.DIRECTIONALITY_LEFT_TO_RIGHT ||
+ dd == Character.DIRECTIONALITY_RIGHT_TO_LEFT) {
+ break;
+ }
+ if (dd == Character.DIRECTIONALITY_EUROPEAN_NUMBER ||
+ dd == Character.DIRECTIONALITY_ARABIC_NUMBER) {
+ dd = Character.DIRECTIONALITY_RIGHT_TO_LEFT;
+ break;
+ }
+ }
+
+ for (int y = j; y < k; y++) {
+ if (dd == cur)
+ chInfo[y] = cur;
+ else
+ chInfo[y] = SOR;
+ }
+
+ j = k - 1;
+ }
+ }
+
+ // dump(chdirs, n, "final");
+
+ // extra: enforce that all tabs and surrogate characters go the
+ // primary direction
+ // TODO: actually do directions right for surrogates
+
+ for (int j = 0; j < n; j++) {
+ char c = chs[j];
+
+ if (c == '\t' || (c >= 0xD800 && c <= 0xDFFF)) {
+ chInfo[j] = SOR;
+ }
+ }
+
+ return dir;
+ }
+
private static final char FIRST_CJK = '\u2E80';
/**
* Returns true if the specified character is one of those specified
@@ -1012,12 +1041,12 @@ extends Layout
int extra;
if (needMultiply) {
- // XXX: this looks like it is using the +0.5 and the cast to int
- // to do rounding, but this I expect this isn't doing the intended
- // thing when spacingmult < 1. An intended extra of, say, -1.2
- // will get 'rounded' to -.7 and then truncated to 0.
- extra = (int) ((below - above) * (spacingmult - 1)
- + spacingadd + 0.5);
+ double ex = (below - above) * (spacingmult - 1) + spacingadd;
+ if (ex >= 0) {
+ extra = (int)(ex + 0.5);
+ } else {
+ extra = -(int)(-ex + 0.5);
+ }
} else {
extra = 0;
}
diff --git a/core/java/android/text/util/Linkify.java b/core/java/android/text/util/Linkify.java
index 7f87365..9860588 100644
--- a/core/java/android/text/util/Linkify.java
+++ b/core/java/android/text/util/Linkify.java
@@ -22,10 +22,10 @@ import android.text.style.URLSpan;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.Spanned;
+import android.util.Patterns;
import android.webkit.WebView;
import android.widget.TextView;
-import com.android.common.Patterns;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
diff --git a/common/java/com/android/common/Patterns.java b/core/java/android/util/Patterns.java
index 3b3b038..2ee6e8a 100644
--- a/common/java/com/android/common/Patterns.java
+++ b/core/java/android/util/Patterns.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.common;
+package android.util;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
diff --git a/core/java/android/util/TimeUtils.java b/core/java/android/util/TimeUtils.java
index 4f496d7..0fc70d5 100644
--- a/core/java/android/util/TimeUtils.java
+++ b/core/java/android/util/TimeUtils.java
@@ -27,7 +27,7 @@ import java.io.IOException;
import java.util.TimeZone;
import java.util.Date;
-import com.android.common.XmlUtils;
+import com.android.internal.util.XmlUtils;
/**
* A class containing utility methods related to time zones.
diff --git a/core/java/android/util/XmlPullAttributes.java b/core/java/android/util/XmlPullAttributes.java
index 8f855cd..ecedbe1 100644
--- a/core/java/android/util/XmlPullAttributes.java
+++ b/core/java/android/util/XmlPullAttributes.java
@@ -19,7 +19,8 @@ package android.util;
import org.xmlpull.v1.XmlPullParser;
import android.util.AttributeSet;
-import com.android.common.XmlUtils;
+
+import com.android.internal.util.XmlUtils;
/**
* Provides an implementation of AttributeSet on top of an XmlPullParser.
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 2eb633f..679206d 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -3650,14 +3650,27 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
}
/**
- * This is called when a container is going to temporarily detach a child
- * that currently has focus, with
+ * @hide
+ */
+ public void dispatchStartTemporaryDetach() {
+ onStartTemporaryDetach();
+ }
+
+ /**
+ * This is called when a container is going to temporarily detach a child, with
* {@link ViewGroup#detachViewFromParent(View) ViewGroup.detachViewFromParent}.
* It will either be followed by {@link #onFinishTemporaryDetach()} or
- * {@link #onDetachedFromWindow()} when the container is done. Generally
- * this is currently only done ListView for a view with focus.
+ * {@link #onDetachedFromWindow()} when the container is done.
*/
public void onStartTemporaryDetach() {
+ removeUnsetPressCallback();
+ }
+
+ /**
+ * @hide
+ */
+ public void dispatchFinishTemporaryDetach() {
+ onFinishTemporaryDetach();
}
/**
@@ -4362,6 +4375,16 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
}
/**
+ * Remove the prepress detection timer.
+ */
+ private void removeUnsetPressCallback() {
+ if ((mPrivateFlags & PRESSED) != 0 && mUnsetPressedState != null) {
+ setPressed(false);
+ removeCallbacks(mUnsetPressedState);
+ }
+ }
+
+ /**
* Remove the tap detection timer.
*/
private void removeTapCallback() {
@@ -5886,6 +5909,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
* @see #onAttachedToWindow()
*/
protected void onDetachedFromWindow() {
+ removeUnsetPressCallback();
removeLongPressCallback();
destroyDrawingCache();
}
@@ -7312,6 +7336,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
* Sets the background color for this view.
* @param color the color of the background
*/
+ @RemotableViewMethod
public void setBackgroundColor(int color) {
setBackgroundDrawable(new ColorDrawable(color));
}
@@ -7322,6 +7347,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
* @param resid The identifier of the resource.
* @attr ref android.R.styleable#View_background
*/
+ @RemotableViewMethod
public void setBackgroundResource(int resid) {
if (resid != 0 && resid == mBackgroundResource) {
return;
@@ -8731,7 +8757,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
boolean clampedX, boolean clampedY) {
// Intentionally empty.
}
-
+
/**
* A MeasureSpec encapsulates the layout requirements passed from parent to child.
* Each MeasureSpec represents a requirement for either the width or the height.
@@ -9182,12 +9208,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
boolean mRecomputeGlobalAttributes;
/**
- * Set to true when attributes (like mKeepScreenOn) need to be
- * recomputed.
- */
- boolean mAttributesChanged;
-
- /**
* Set during a traveral if any views want to keep the screen on.
*/
boolean mKeepScreenOn;
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 0663215..d05416d 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -1065,6 +1065,36 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
}
return false;
}
+
+ /**
+ * {@inheritDoc}
+ *
+ * @hide
+ */
+ @Override
+ public void dispatchStartTemporaryDetach() {
+ super.dispatchStartTemporaryDetach();
+ final int count = mChildrenCount;
+ final View[] children = mChildren;
+ for (int i = 0; i < count; i++) {
+ children[i].dispatchStartTemporaryDetach();
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @hide
+ */
+ @Override
+ public void dispatchFinishTemporaryDetach() {
+ super.dispatchFinishTemporaryDetach();
+ final int count = mChildrenCount;
+ final View[] children = mChildren;
+ for (int i = 0; i < count; i++) {
+ children[i].dispatchFinishTemporaryDetach();
+ }
+ }
/**
* {@inheritDoc}
diff --git a/core/java/android/view/WindowOrientationListener.java b/core/java/android/view/WindowOrientationListener.java
index 2aba60b..6c58461 100755
--- a/core/java/android/view/WindowOrientationListener.java
+++ b/core/java/android/view/WindowOrientationListener.java
@@ -57,8 +57,12 @@ public abstract class WindowOrientationListener {
* {@link android.hardware.SensorManager SensorManager}). Use the default
* value of {@link android.hardware.SensorManager#SENSOR_DELAY_NORMAL
* SENSOR_DELAY_NORMAL} for simple screen orientation change detection.
+ *
+ * This constructor is private since no one uses it and making it public would complicate
+ * things, since the lowpass filtering code depends on the actual sampling period, and there's
+ * no way to get the period from SensorManager based on the rate constant.
*/
- public WindowOrientationListener(Context context, int rate) {
+ private WindowOrientationListener(Context context, int rate) {
mSensorManager = (SensorManager)context.getSystemService(Context.SENSOR_SERVICE);
mRate = rate;
mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
@@ -107,94 +111,179 @@ public abstract class WindowOrientationListener {
}
class SensorEventListenerImpl implements SensorEventListener {
+ // We work with all angles in degrees in this class.
+ private static final float RADIANS_TO_DEGREES = (float) (180 / Math.PI);
+
+ // Indices into SensorEvent.values
private static final int _DATA_X = 0;
private static final int _DATA_Y = 1;
private static final int _DATA_Z = 2;
- // Angle around x-asis that's considered almost too vertical. Beyond
- // this angle will not result in any orientation changes. f phone faces uses,
- // the device is leaning backward.
- private static final int PIVOT_UPPER = 65;
- // Angle about x-axis that's considered negative vertical. Beyond this
- // angle will not result in any orientation changes. If phone faces uses,
- // the device is leaning forward.
- private static final int PIVOT_LOWER = -10;
- static final int ROTATION_0 = 0;
- static final int ROTATION_90 = 1;
- static final int ROTATION_180 = 2;
- static final int ROTATION_270 = 3;
- int mRotation = ROTATION_0;
-
- // Threshold values defined for device rotation positions
- // follow order ROTATION_0 .. ROTATION_270
- final int THRESHOLDS[][][] = new int[][][] {
- {{60, 135}, {135, 225}, {225, 300}},
- {{0, 45}, {45, 135}, {135, 210}, {330, 360}},
- {{0, 45}, {45, 120}, {240, 315}, {315, 360}},
- {{0, 30}, {150, 225}, {225, 315}, {315, 360}}
+
+ // Internal aliases for the four orientation states. ROTATION_0 = default portrait mode,
+ // ROTATION_90 = left side of device facing the sky, etc.
+ private static final int ROTATION_0 = 0;
+ private static final int ROTATION_90 = 1;
+ private static final int ROTATION_180 = 2;
+ private static final int ROTATION_270 = 3;
+
+ // Current orientation state
+ private int mRotation = ROTATION_0;
+
+ // Mapping our internal aliases into actual Surface rotation values
+ private final int[] SURFACE_ROTATIONS = new int[] {Surface.ROTATION_0, Surface.ROTATION_90,
+ Surface.ROTATION_180, Surface.ROTATION_270};
+
+ // Threshold ranges of orientation angle to transition into other orientation states.
+ // The first list is for transitions from ROTATION_0, the next for ROTATION_90, etc.
+ // ROTATE_TO defines the orientation each threshold range transitions to, and must be kept
+ // in sync with this.
+ // The thresholds are nearly regular -- we generally transition about the halfway point
+ // between two states with a swing of 30 degreees for hysteresis. For ROTATION_180,
+ // however, we enforce stricter thresholds, pushing the thresholds 15 degrees closer to 180.
+ private final int[][][] THRESHOLDS = new int[][][] {
+ {{60, 165}, {165, 195}, {195, 300}},
+ {{0, 45}, {45, 165}, {165, 195}, {330, 360}},
+ {{0, 45}, {45, 135}, {225, 315}, {315, 360}},
+ {{0, 30}, {165, 195}, {195, 315}, {315, 360}}
};
- // Transform rotation ranges based on THRESHOLDS. This
- // has to be in step with THESHOLDS
- final int ROTATE_TO[][] = new int[][] {
- {ROTATION_270, ROTATION_180, ROTATION_90},
- {ROTATION_0, ROTATION_270, ROTATION_180, ROTATION_0},
- {ROTATION_0, ROTATION_270, ROTATION_90, ROTATION_0},
- {ROTATION_0, ROTATION_180, ROTATION_90, ROTATION_0}
+ // See THRESHOLDS
+ private final int[][] ROTATE_TO = new int[][] {
+ {ROTATION_270, ROTATION_180, ROTATION_90},
+ {ROTATION_0, ROTATION_270, ROTATION_180, ROTATION_0},
+ {ROTATION_0, ROTATION_270, ROTATION_90, ROTATION_0},
+ {ROTATION_0, ROTATION_180, ROTATION_90, ROTATION_0}
};
- // Mapping into actual Surface rotation values
- final int TRANSFORM_ROTATIONS[] = new int[]{Surface.ROTATION_0,
- Surface.ROTATION_90, Surface.ROTATION_180, Surface.ROTATION_270};
+ // Maximum absolute tilt angle at which to consider orientation changes. Beyond this (i.e.
+ // when screen is facing the sky or ground), we refuse to make any orientation changes.
+ private static final int MAX_TILT = 65;
+
+ // Additional limits on tilt angle to transition to each new orientation. We ignore all
+ // vectors with tilt beyond MAX_TILT, but we can set stricter limits on transition to a
+ // particular orientation here.
+ private final int[] MAX_TRANSITION_TILT = new int[] {MAX_TILT, MAX_TILT, 40, MAX_TILT};
+
+ // Between this tilt angle and MAX_TILT, we'll allow orientation changes, but we'll filter
+ // with a higher time constant, making us less sensitive to change. This primarily helps
+ // prevent momentary orientation changes when placing a device on a table from the side (or
+ // picking one up).
+ private static final int PARTIAL_TILT = 45;
+
+ // Maximum allowable deviation of the magnitude of the sensor vector from that of gravity,
+ // in m/s^2. Beyond this, we assume the phone is under external forces and we can't trust
+ // the sensor data. However, under constantly vibrating conditions (think car mount), we
+ // still want to pick up changes, so rather than ignore the data, we filter it with a very
+ // high time constant.
+ private static final int MAX_DEVIATION_FROM_GRAVITY = 1;
+
+ // Actual sampling period corresponding to SensorManager.SENSOR_DELAY_NORMAL. There's no
+ // way to get this information from SensorManager.
+ // Note the actual period is generally 3-30ms larger than this depending on the device, but
+ // that's not enough to significantly skew our results.
+ private static final int SAMPLING_PERIOD_MS = 200;
+
+ // The following time constants are all used in low-pass filtering the accelerometer output.
+ // See http://en.wikipedia.org/wiki/Low-pass_filter#Discrete-time_realization for
+ // background.
+
+ // When device is near-vertical (screen approximately facing the horizon)
+ private static final int DEFAULT_TIME_CONSTANT_MS = 200;
+ // When device is partially tilted towards the sky or ground
+ private static final int TILTED_TIME_CONSTANT_MS = 600;
+ // When device is under external acceleration, i.e. not just gravity. We heavily distrust
+ // such readings.
+ private static final int ACCELERATING_TIME_CONSTANT_MS = 5000;
+
+ private static final float DEFAULT_LOWPASS_ALPHA =
+ (float) SAMPLING_PERIOD_MS / (DEFAULT_TIME_CONSTANT_MS + SAMPLING_PERIOD_MS);
+ private static final float TILTED_LOWPASS_ALPHA =
+ (float) SAMPLING_PERIOD_MS / (TILTED_TIME_CONSTANT_MS + SAMPLING_PERIOD_MS);
+ private static final float ACCELERATING_LOWPASS_ALPHA =
+ (float) SAMPLING_PERIOD_MS / (ACCELERATING_TIME_CONSTANT_MS + SAMPLING_PERIOD_MS);
+
+ // The low-pass filtered accelerometer data
+ private float[] mFilteredVector = new float[] {0, 0, 0};
int getCurrentRotation() {
- return TRANSFORM_ROTATIONS[mRotation];
+ return SURFACE_ROTATIONS[mRotation];
}
-
- private void calculateNewRotation(int orientation, int zyangle) {
- if (localLOGV) Log.i(TAG, orientation + ", " + zyangle + ", " + mRotation);
- int rangeArr[][] = THRESHOLDS[mRotation];
+
+ private void calculateNewRotation(int orientation, int tiltAngle) {
+ if (localLOGV) Log.i(TAG, orientation + ", " + tiltAngle + ", " + mRotation);
+ int thresholdRanges[][] = THRESHOLDS[mRotation];
int row = -1;
- for (int i = 0; i < rangeArr.length; i++) {
- if ((orientation >= rangeArr[i][0]) && (orientation < rangeArr[i][1])) {
+ for (int i = 0; i < thresholdRanges.length; i++) {
+ if (orientation >= thresholdRanges[i][0] && orientation < thresholdRanges[i][1]) {
row = i;
break;
}
}
- if (row != -1) {
- // Find new rotation based on current rotation value.
- // This also takes care of irregular rotations as well.
- int rotation = ROTATE_TO[mRotation][row];
- if (localLOGV) Log.i(TAG, " new rotation = " + rotation);
- if (rotation != mRotation) {
- mRotation = rotation;
- // Trigger orientation change
- onOrientationChanged(TRANSFORM_ROTATIONS[rotation]);
- }
+ if (row == -1) return; // no matching transition
+
+ int rotation = ROTATE_TO[mRotation][row];
+ if (tiltAngle > MAX_TRANSITION_TILT[rotation]) {
+ // tilted too far flat to go to this rotation
+ return;
}
+
+ if (localLOGV) Log.i(TAG, " new rotation = " + rotation);
+ mRotation = rotation;
+ onOrientationChanged(SURFACE_ROTATIONS[rotation]);
+ }
+
+ private float lowpassFilter(float newValue, float oldValue, float alpha) {
+ return alpha * newValue + (1 - alpha) * oldValue;
+ }
+
+ private float vectorMagnitude(float x, float y, float z) {
+ return (float) Math.sqrt(x*x + y*y + z*z);
+ }
+
+ /**
+ * Absolute angle between upVector and the x-y plane (the plane of the screen), in [0, 90].
+ * 90 degrees = screen facing the sky or ground.
+ */
+ private float tiltAngle(float z, float magnitude) {
+ return Math.abs((float) Math.asin(z / magnitude) * RADIANS_TO_DEGREES);
}
public void onSensorChanged(SensorEvent event) {
- float[] values = event.values;
- float X = values[_DATA_X];
- float Y = values[_DATA_Y];
- float Z = values[_DATA_Z];
- float OneEightyOverPi = 57.29577957855f;
- float gravity = (float) Math.sqrt(X*X+Y*Y+Z*Z);
- float zyangle = (float)Math.asin(Z/gravity)*OneEightyOverPi;
- if ((zyangle <= PIVOT_UPPER) && (zyangle >= PIVOT_LOWER)) {
- // Check orientation only if the phone is flat enough
- // Don't trust the angle if the magnitude is small compared to the y value
- float angle = (float)Math.atan2(Y, -X) * OneEightyOverPi;
- int orientation = 90 - Math.round(angle);
- // normalize to 0 - 359 range
- while (orientation >= 360) {
- orientation -= 360;
- }
- while (orientation < 0) {
- orientation += 360;
- }
- calculateNewRotation(orientation, Math.round(zyangle));
+ // the vector given in the SensorEvent points straight up (towards the sky) under ideal
+ // conditions (the phone is not accelerating). i'll call this upVector elsewhere.
+ float x = event.values[_DATA_X];
+ float y = event.values[_DATA_Y];
+ float z = event.values[_DATA_Z];
+ float magnitude = vectorMagnitude(x, y, z);
+ float deviation = Math.abs(magnitude - SensorManager.STANDARD_GRAVITY);
+ float tiltAngle = tiltAngle(z, magnitude);
+
+ float alpha = DEFAULT_LOWPASS_ALPHA;
+ if (tiltAngle > MAX_TILT) {
+ return;
+ } else if (deviation > MAX_DEVIATION_FROM_GRAVITY) {
+ alpha = ACCELERATING_LOWPASS_ALPHA;
+ } else if (tiltAngle > PARTIAL_TILT) {
+ alpha = TILTED_LOWPASS_ALPHA;
+ }
+
+ x = mFilteredVector[0] = lowpassFilter(x, mFilteredVector[0], alpha);
+ y = mFilteredVector[1] = lowpassFilter(y, mFilteredVector[1], alpha);
+ z = mFilteredVector[2] = lowpassFilter(z, mFilteredVector[2], alpha);
+ magnitude = vectorMagnitude(x, y, z);
+ tiltAngle = tiltAngle(z, magnitude);
+
+ // Angle between the x-y projection of upVector and the +y-axis, increasing
+ // counter-clockwise.
+ // 0 degrees = speaker end towards the sky
+ // 90 degrees = left edge of device towards the sky
+ float orientationAngle = (float) Math.atan2(-x, y) * RADIANS_TO_DEGREES;
+ int orientation = Math.round(orientationAngle);
+ // atan2 returns (-180, 180]; normalize to [0, 360)
+ if (orientation < 0) {
+ orientation += 360;
}
+ calculateNewRotation(orientation, Math.round(tiltAngle));
}
public void onAccuracyChanged(Sensor sensor, int accuracy) {
@@ -208,13 +297,12 @@ public abstract class WindowOrientationListener {
public boolean canDetectOrientation() {
return mSensor != null;
}
-
+
/**
* Called when the rotation view of the device has changed.
- * Can be either Surface.ROTATION_90 or Surface.ROTATION_0.
- * @param rotation The new orientation of the device.
*
- * @see #ORIENTATION_UNKNOWN
+ * @param rotation The new orientation of the device, one of the Surface.ROTATION_* constants.
+ * @see Surface
*/
abstract public void onOrientationChanged(int rotation);
}
diff --git a/core/java/android/webkit/CacheManager.java b/core/java/android/webkit/CacheManager.java
index 87cab3c..647556b 100644
--- a/core/java/android/webkit/CacheManager.java
+++ b/core/java/android/webkit/CacheManager.java
@@ -18,6 +18,7 @@ package android.webkit;
import android.content.Context;
import android.net.http.Headers;
+import android.net.http.HttpDateTime;
import android.os.FileUtils;
import android.util.Log;
import java.io.File;
@@ -30,7 +31,6 @@ import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Map;
-import com.android.common.HttpDateTime;
import org.bouncycastle.crypto.Digest;
import org.bouncycastle.crypto.digests.SHA1Digest;
diff --git a/core/java/android/webkit/CookieManager.java b/core/java/android/webkit/CookieManager.java
index 94bedde..1d28731 100644
--- a/core/java/android/webkit/CookieManager.java
+++ b/core/java/android/webkit/CookieManager.java
@@ -18,9 +18,9 @@ package android.webkit;
import android.net.ParseException;
import android.net.WebAddress;
+import android.net.http.HttpDateTime;
import android.util.Log;
-import com.android.common.HttpDateTime;
import java.util.ArrayList;
import java.util.Arrays;
@@ -150,8 +150,13 @@ public final class CookieManager {
}
boolean exactMatch(Cookie in) {
+ // An exact match means that domain, path, and name are equal. If
+ // both values are null, the cookies match. If both values are
+ // non-null, the cookies match. If one value is null and the other
+ // is non-null, the cookies do not match (i.e. "foo=;" and "foo;")
+ boolean valuesMatch = !((value == null) ^ (in.value == null));
return domain.equals(in.domain) && path.equals(in.path) &&
- name.equals(in.name);
+ name.equals(in.name) && valuesMatch;
}
boolean domainMatch(String urlHost) {
@@ -206,17 +211,29 @@ public final class CookieManager {
// 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);
- }
- }
+ if (diff != 0) return diff;
+
+ diff = cookie2.domain.length() - cookie1.domain.length();
+ if (diff != 0) return diff;
+
+ diff = cookie2.name.hashCode() - cookie1.name.hashCode();
+ if (diff != 0) return diff;
+
+ // If cookie2 has a null value, it should come later in
+ // the list.
+ if (cookie2.value == null) {
+ return -1;
+ } else if (cookie1.value == null) {
+ // Now we know that cookie2 does not have a null value, if
+ // cookie1 has a null value, place it later in the list.
+ return 1;
}
- return diff;
+
+ // cookie1 and cookie2 both have non-null values so we emit a
+ // warning and treat them as the same.
+ Log.w(LOGTAG, "Found two cookies with the same value."
+ + "cookie1=" + cookie1 + " , cookie2=" + cookie2);
+ return 0;
}
}
@@ -459,8 +476,10 @@ public final class CookieManager {
}
ret.append(cookie.name);
- ret.append(EQUAL);
- ret.append(cookie.value);
+ if (cookie.value != null) {
+ ret.append(EQUAL);
+ ret.append(cookie.value);
+ }
}
if (ret.length() > 0) {
@@ -634,7 +653,10 @@ public final class CookieManager {
byteCount += cookie.domain.length()
+ cookie.path.length()
+ cookie.name.length()
- + cookie.value.length() + 14;
+ + (cookie.value != null
+ ? cookie.value.length()
+ : 0)
+ + 14;
count++;
}
} else {
@@ -779,38 +801,45 @@ public final class CookieManager {
*/
int semicolonIndex = cookieString.indexOf(SEMICOLON, index);
int equalIndex = cookieString.indexOf(EQUAL, index);
- if (equalIndex == -1) {
- // bad format, force return
- break;
- }
- if (semicolonIndex > -1 && semicolonIndex < equalIndex) {
- // empty cookie, like "; path=/", return
- break;
- }
cookie = new Cookie(host, path);
- cookie.name = cookieString.substring(index, equalIndex);
- if (cookieString.charAt(equalIndex + 1) == QUOTATION) {
- index = cookieString.indexOf(QUOTATION, equalIndex + 2);
- if (index == -1) {
- // bad format, force return
- break;
+
+ // Cookies like "testcookie; path=/;" are valid and used
+ // (lovefilm.se). Check for equal as in the string "testcookie"
+ // Check for equalIndex == -1 as in the string "testcookie;"
+ if (semicolonIndex <= equalIndex || equalIndex == -1) {
+ // Fix up the index in case we have a string like "testcookie"
+ if (semicolonIndex == -1) {
+ semicolonIndex = length;
}
- }
- semicolonIndex = cookieString.indexOf(SEMICOLON, index);
- if (semicolonIndex == -1) {
- semicolonIndex = length;
- }
- if (semicolonIndex - equalIndex > MAX_COOKIE_LENGTH) {
- // cookie is too big, trim it
- cookie.value = cookieString.substring(equalIndex + 1,
- equalIndex + MAX_COOKIE_LENGTH);
- } else if (equalIndex + 1 == semicolonIndex
- || semicolonIndex < equalIndex) {
- // these are unusual case like foo=; and foo; path=/
- cookie.value = "";
+ cookie.name = cookieString.substring(index, semicolonIndex);
+ cookie.value = null;
} else {
- cookie.value = cookieString.substring(equalIndex + 1,
- semicolonIndex);
+ cookie.name = cookieString.substring(index, equalIndex);
+ if (cookieString.charAt(equalIndex + 1) == QUOTATION) {
+ index = cookieString.indexOf(QUOTATION, equalIndex + 2);
+ if (index == -1) {
+ // bad format, force return
+ break;
+ }
+ }
+ // Get the semicolon index again in case it was contained within
+ // the quotations.
+ semicolonIndex = cookieString.indexOf(SEMICOLON, index);
+ if (semicolonIndex == -1) {
+ semicolonIndex = length;
+ }
+ if (semicolonIndex - equalIndex > MAX_COOKIE_LENGTH) {
+ // cookie is too big, trim it
+ cookie.value = cookieString.substring(equalIndex + 1,
+ equalIndex + 1 + MAX_COOKIE_LENGTH);
+ } else if (equalIndex + 1 == semicolonIndex
+ || semicolonIndex < equalIndex) {
+ // this is an unusual case like foo=;
+ cookie.value = "";
+ } else {
+ cookie.value = cookieString.substring(equalIndex + 1,
+ semicolonIndex);
+ }
}
// get attributes
index = semicolonIndex;
diff --git a/core/java/android/webkit/PluginManager.java b/core/java/android/webkit/PluginManager.java
index cdcb662..df7d0c4 100644
--- a/core/java/android/webkit/PluginManager.java
+++ b/core/java/android/webkit/PluginManager.java
@@ -165,6 +165,7 @@ public class PluginManager {
continue;
}
+/* temporarily disable signatures checking
// check to ensure the plugin is properly signed
Signature signatures[] = pkgInfo.signatures;
if (signatures == null) {
@@ -184,7 +185,7 @@ public class PluginManager {
continue;
}
}
-
+*/
// determine the type of plugin from the manifest
if (serviceInfo.metaData == null) {
Log.e(LOGTAG, "The plugin '" + serviceInfo.name + "' has no type defined");
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index adae0cb..d29d6f3 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -213,7 +213,6 @@ public class WebView extends AbsoluteLayout
static private final boolean AUTO_REDRAW_HACK = false;
// true means redraw the screen all-the-time. Only with AUTO_REDRAW_HACK
private boolean mAutoRedraw;
- private int mRootLayer; // C++ pointer to the root layer
static final String LOGTAG = "webview";
@@ -375,6 +374,7 @@ public class WebView extends AbsoluteLayout
private static final int PREVENT_DRAG_NO = 0;
private static final int PREVENT_DRAG_MAYBE_YES = 1;
private static final int PREVENT_DRAG_YES = 2;
+ private static final int PREVENT_DRAG_CANCEL = 3;
private int mPreventDrag = PREVENT_DRAG_NO;
// by default mPreventLongPress is false. If it is true, long press event
@@ -617,6 +617,12 @@ public class WebView extends AbsoluteLayout
private static final int SNAP_Y = 4; // may be combined with SNAP_LOCK
private boolean mSnapPositive;
+ // keep these in sync with their counterparts in WebView.cpp
+ private static final int DRAW_EXTRAS_NONE = 0;
+ private static final int DRAW_EXTRAS_FIND = 1;
+ private static final int DRAW_EXTRAS_SELECTION = 2;
+ private static final int DRAW_EXTRAS_CURSOR_RING = 3;
+
// Used to match key downs and key ups
private boolean mGotKeyDown;
@@ -1305,6 +1311,7 @@ public class WebView extends AbsoluteLayout
// onSizeChanged() is called, the rest will be set
// correctly
mActualScale = scale;
+ mInvActualScale = 1 / scale;
mTextWrapScale = b.getFloat("textwrapScale", scale);
mInZoomOverview = b.getBoolean("overview");
invalidate();
@@ -3115,7 +3122,7 @@ public class WebView extends AbsoluteLayout
int mScrollY;
int mWidth;
int mHeight;
- float mScale;
+ float mInvScale;
}
private Metrics getViewMetrics() {
@@ -3124,23 +3131,22 @@ public class WebView extends AbsoluteLayout
metrics.mScrollY = computeVerticalScrollOffset();
metrics.mWidth = getWidth();
metrics.mHeight = getHeight() - getVisibleTitleHeight();
- metrics.mScale = mActualScale;
+ metrics.mInvScale = mInvActualScale;
return metrics;
}
- private void drawLayers(Canvas canvas) {
- if (mRootLayer != 0) {
- // Currently for each draw we compute the animation values;
- // We may in the future decide to do that independently.
- if (nativeEvaluateLayersAnimations(mRootLayer)) {
- // If we have unfinished (or unstarted) animations,
- // we ask for a repaint.
- invalidate();
- }
-
- // We can now draw the layers.
- nativeDrawLayers(mRootLayer, canvas);
+ private void drawExtras(Canvas canvas, int extras) {
+ // If mNativeClass is 0, we should not reach here, so we do not
+ // need to check it again.
+ // Currently for each draw we compute the animation values;
+ // We may in the future decide to do that independently.
+ if (nativeEvaluateLayersAnimations()) {
+ // If we have unfinished (or unstarted) animations,
+ // we ask for a repaint.
+ invalidate();
}
+
+ nativeDrawExtras(canvas, extras);
}
private void drawCoreAndCursorRing(Canvas canvas, int color,
@@ -3148,7 +3154,6 @@ public class WebView extends AbsoluteLayout
if (mDrawHistory) {
canvas.scale(mActualScale, mActualScale);
canvas.drawPicture(mHistoryPicture);
- drawLayers(canvas);
return;
}
@@ -3227,27 +3232,29 @@ public class WebView extends AbsoluteLayout
mWebViewCore.drawContentPicture(canvas, color,
(animateZoom || mPreviewZoomOnly), animateScroll);
- boolean cursorIsInLayer = nativeCursorIsInLayer();
- if (drawCursorRing && !cursorIsInLayer) {
- nativeDrawCursorRing(canvas);
- }
- // When the FindDialog is up, only draw the matches if we are not in
- // the process of scrolling them into view.
- if (mFindIsUp && !animateScroll) {
- nativeDrawMatches(canvas);
- }
- drawLayers(canvas);
-
if (mNativeClass == 0) return;
- if (mShiftIsPressed && !(animateZoom || mPreviewZoomOnly)) {
- if (mTouchSelection || mExtendSelection) {
- nativeDrawSelectionRegion(canvas);
- }
- if (!mTouchSelection) {
- nativeDrawSelectionPointer(canvas, mInvActualScale, mSelectX,
- mSelectY - getTitleHeight(), mExtendSelection);
+ // decide which adornments to draw
+ int extras = DRAW_EXTRAS_NONE;
+ if (mFindIsUp) {
+ // When the FindDialog is up, only draw the matches if we are not in
+ // the process of scrolling them into view.
+ if (!animateScroll) {
+ extras = DRAW_EXTRAS_FIND;
+ }
+ } else if (mShiftIsPressed) {
+ if (!animateZoom && !mPreviewZoomOnly) {
+ extras = DRAW_EXTRAS_SELECTION;
+ nativeSetSelectionRegion(mTouchSelection || mExtendSelection);
+ nativeSetSelectionPointer(!mTouchSelection, mInvActualScale,
+ mSelectX, mSelectY - getTitleHeight(),
+ mExtendSelection);
}
} else if (drawCursorRing) {
+ extras = DRAW_EXTRAS_CURSOR_RING;
+ }
+ drawExtras(canvas, extras);
+
+ if (extras == DRAW_EXTRAS_CURSOR_RING) {
if (mTouchMode == TOUCH_SHORTPRESS_START_MODE) {
mTouchMode = TOUCH_SHORTPRESS_MODE;
HitTestResult hitTest = getHitTestResult();
@@ -3258,7 +3265,6 @@ public class WebView extends AbsoluteLayout
LONG_PRESS_TIMEOUT);
}
}
- if (cursorIsInLayer) nativeDrawCursorRing(canvas);
}
if (mFocusSizeChanged) {
mFocusSizeChanged = false;
@@ -3351,23 +3357,32 @@ public class WebView extends AbsoluteLayout
InputMethodManager imm = (InputMethodManager)
getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
+ // bring it back to the default scale so that user can enter text
+ boolean zoom = mActualScale < mDefaultScale;
+ if (zoom) {
+ mInZoomOverview = false;
+ mZoomCenterX = mLastTouchX;
+ mZoomCenterY = mLastTouchY;
+ // do not change text wrap scale so that there is no reflow
+ setNewZoomScale(mDefaultScale, false, false);
+ }
if (isTextView) {
rebuildWebTextView();
- if (!inEditingMode()) return;
- imm.showSoftInput(mWebTextView, 0);
- // bring it back to the default scale so that user can enter text
- if (mActualScale < mDefaultScale) {
- mInZoomOverview = false;
- mZoomCenterX = mLastTouchX;
- mZoomCenterY = mLastTouchY;
- // do not change text wrap scale so that there is no reflow
- setNewZoomScale(mDefaultScale, false, false);
- didUpdateTextViewBounds(true);
+ if (inEditingMode()) {
+ mWebTextView.setDefaultSelection();
+ imm.showSoftInput(mWebTextView, 0);
+ if (zoom) {
+ didUpdateTextViewBounds(true);
+ }
+ return;
}
}
- else { // used by plugins
- imm.showSoftInput(this, 0);
- }
+ // Used by plugins.
+ // Also used if the navigation cache is out of date, and
+ // does not recognize that a textfield is in focus. In that
+ // case, use WebView as the targeted view.
+ // see http://b/issue?id=2457459
+ imm.showSoftInput(this, 0);
}
// Called by WebKit to instruct the UI to hide the keyboard
@@ -3672,6 +3687,7 @@ public class WebView extends AbsoluteLayout
// might be. Check it, and if so, hand over to the WebTextView.
rebuildWebTextView();
if (inEditingMode()) {
+ mWebTextView.setDefaultSelection();
return mWebTextView.dispatchKeyEvent(event);
}
}
@@ -4429,8 +4445,11 @@ public class WebView extends AbsoluteLayout
}
// pass the touch events from UI thread to WebCore thread
- if (mForwardTouchEvents && (action != MotionEvent.ACTION_MOVE
- || eventTime - mLastSentTouchTime > mCurrentTouchInterval)) {
+ if (mForwardTouchEvents
+ && (action != MotionEvent.ACTION_MOVE || eventTime
+ - mLastSentTouchTime > mCurrentTouchInterval)
+ && (action == MotionEvent.ACTION_DOWN
+ || mPreventDrag != PREVENT_DRAG_CANCEL)) {
WebViewCore.TouchEventData ted = new WebViewCore.TouchEventData();
ted.mAction = action;
ted.mX = viewToContentX((int) x + mScrollX);
@@ -5711,12 +5730,17 @@ public class WebView extends AbsoluteLayout
break;
}
case SWITCH_TO_SHORTPRESS: {
- // if mPreventDrag is not confirmed, treat it as no so that
- // it won't block panning the page.
+ // if mPreventDrag is not confirmed, cancel it so that it
+ // won't block panning the page.
if (mPreventDrag == PREVENT_DRAG_MAYBE_YES) {
- mPreventDrag = PREVENT_DRAG_NO;
+ mPreventDrag = PREVENT_DRAG_CANCEL;
mPreventLongPress = false;
mPreventDoubleTap = false;
+ // remove the pending TOUCH_EVENT and send a cancel
+ mWebViewCore.removeMessages(EventHub.TOUCH_EVENT);
+ WebViewCore.TouchEventData ted = new WebViewCore.TouchEventData();
+ ted.mAction = MotionEvent.ACTION_CANCEL;
+ mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
}
if (mTouchMode == TOUCH_INIT_MODE) {
mTouchMode = mFullScreenHolder == null
@@ -5743,7 +5767,7 @@ public class WebView extends AbsoluteLayout
// don't set it.
ted.mMetaState = 0;
mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
- } else if (mPreventDrag == PREVENT_DRAG_NO) {
+ } else if (mPreventDrag != PREVENT_DRAG_YES) {
mTouchMode = TOUCH_DONE_MODE;
if (mFullScreenHolder == null) {
performLongClick();
@@ -5754,13 +5778,18 @@ public class WebView extends AbsoluteLayout
}
case RELEASE_SINGLE_TAP: {
if (mPreventDrag == PREVENT_DRAG_MAYBE_YES) {
- // if mPreventDrag is not confirmed, treat it as
- // no so that it won't block tap.
- mPreventDrag = PREVENT_DRAG_NO;
+ // if mPreventDrag is not confirmed, cancel it so that
+ // it won't block panning the page.
+ mPreventDrag = PREVENT_DRAG_CANCEL;
mPreventLongPress = false;
mPreventDoubleTap = false;
+ // remove the pending TOUCH_EVENT and send a cancel
+ mWebViewCore.removeMessages(EventHub.TOUCH_EVENT);
+ WebViewCore.TouchEventData ted = new WebViewCore.TouchEventData();
+ ted.mAction = MotionEvent.ACTION_CANCEL;
+ mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
}
- if (mPreventDrag == PREVENT_DRAG_NO) {
+ if (mPreventDrag != PREVENT_DRAG_YES) {
mTouchMode = TOUCH_DONE_MODE;
doShortPress();
}
@@ -5979,12 +6008,7 @@ public class WebView extends AbsoluteLayout
break;
}
case SET_ROOT_LAYER_MSG_ID: {
- int oldLayer = mRootLayer;
- mRootLayer = msg.arg1;
- nativeSetRootLayer(mRootLayer);
- if (oldLayer > 0) {
- nativeDestroyLayer(oldLayer);
- }
+ nativeSetRootLayer(msg.arg1);
invalidate();
break;
}
@@ -6744,7 +6768,6 @@ public class WebView extends AbsoluteLayout
/* package */ native boolean nativeCursorMatchesFocus();
private native boolean nativeCursorIntersects(Rect visibleRect);
private native boolean nativeCursorIsAnchor();
- private native boolean nativeCursorIsInLayer();
private native boolean nativeCursorIsTextInput();
private native Point nativeCursorPosition();
private native String nativeCursorText();
@@ -6755,14 +6778,8 @@ public class WebView extends AbsoluteLayout
private native boolean nativeCursorWantsKeyEvents();
private native void nativeDebugDump();
private native void nativeDestroy();
- private native void nativeDrawCursorRing(Canvas content);
- private native void nativeDestroyLayer(int layer);
- private native boolean nativeEvaluateLayersAnimations(int layer);
- private native void nativeDrawLayers(int layer, Canvas canvas);
- private native void nativeDrawMatches(Canvas canvas);
- private native void nativeDrawSelectionPointer(Canvas content,
- float scale, int x, int y, boolean extendSelection);
- private native void nativeDrawSelectionRegion(Canvas content);
+ private native boolean nativeEvaluateLayersAnimations();
+ private native void nativeDrawExtras(Canvas canvas, int extra);
private native void nativeDumpDisplayTree(String urlOrNull);
private native int nativeFindAll(String findLower, String findUpper);
private native void nativeFindNext(boolean forward);
@@ -6809,6 +6826,9 @@ public class WebView extends AbsoluteLayout
private native void nativeSetFollowedLink(boolean followed);
private native void nativeSetHeightCanMeasure(boolean measure);
private native void nativeSetRootLayer(int layer);
+ private native void nativeSetSelectionPointer(boolean set,
+ float scale, int x, int y, boolean extendSelection);
+ private native void nativeSetSelectionRegion(boolean set);
private native int nativeTextGeneration();
// Never call this version except by updateCachedTextfield(String) -
// we always want to pass in our generation number.
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index a79bbee..9ddfeff 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -1314,7 +1314,8 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
position, -1);
}
} else {
- isScrap[0] = true;
+ isScrap[0] = true;
+ child.dispatchFinishTemporaryDetach();
}
} else {
child = mAdapter.getView(position, null, this);
@@ -1960,7 +1961,6 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
if (getHeight() > 0 && getChildCount() > 0) {
// We do not lose focus initiating a touch (since AbsListView is focusable in
// touch mode). Force an initial layout to get rid of the selection.
- mLayoutMode = LAYOUT_NORMAL;
layoutChildren();
}
} else {
@@ -3118,7 +3118,9 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
void hideSelector() {
if (mSelectedPosition != INVALID_POSITION) {
- mResurrectToPosition = mSelectedPosition;
+ if (mLayoutMode != LAYOUT_SPECIFIC) {
+ mResurrectToPosition = mSelectedPosition;
+ }
if (mNextSelectedPosition >= 0 && mNextSelectedPosition != mSelectedPosition) {
mResurrectToPosition = mNextSelectedPosition;
}
@@ -4144,8 +4146,10 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
}
if (mViewTypeCount == 1) {
+ scrap.dispatchStartTemporaryDetach();
mCurrentScrap.add(scrap);
} else {
+ scrap.dispatchStartTemporaryDetach();
mScrapViews[viewType].add(scrap);
}
@@ -4164,7 +4168,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
ArrayList<View> scrapViews = mCurrentScrap;
final int count = activeViews.length;
- for (int i = 0; i < count; ++i) {
+ for (int i = count - 1; i >= 0; i--) {
final View victim = activeViews[i];
if (victim != null) {
int whichScrap = ((AbsListView.LayoutParams) victim.getLayoutParams()).viewType;
@@ -4180,6 +4184,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
if (multipleScraps) {
scrapViews = mScrapViews[whichScrap];
}
+ victim.dispatchStartTemporaryDetach();
scrapViews.add(victim);
if (hasListener) {
diff --git a/core/java/android/widget/AbsSpinner.java b/core/java/android/widget/AbsSpinner.java
index c939e3f..2b3b98d 100644
--- a/core/java/android/widget/AbsSpinner.java
+++ b/core/java/android/widget/AbsSpinner.java
@@ -28,8 +28,6 @@ import android.util.AttributeSet;
import android.util.SparseArray;
import android.view.View;
import android.view.ViewGroup;
-import android.view.animation.Interpolator;
-
/**
* An abstract base class for spinner widgets. SDK users will probably not
@@ -38,24 +36,21 @@ import android.view.animation.Interpolator;
* @attr ref android.R.styleable#AbsSpinner_entries
*/
public abstract class AbsSpinner extends AdapterView<SpinnerAdapter> {
-
SpinnerAdapter mAdapter;
int mHeightMeasureSpec;
int mWidthMeasureSpec;
boolean mBlockLayoutRequests;
+
int mSelectionLeftPadding = 0;
int mSelectionTopPadding = 0;
int mSelectionRightPadding = 0;
int mSelectionBottomPadding = 0;
- Rect mSpinnerPadding = new Rect();
- View mSelectedView = null;
- Interpolator mInterpolator;
+ final Rect mSpinnerPadding = new Rect();
- RecycleBin mRecycler = new RecycleBin();
+ final RecycleBin mRecycler = new RecycleBin();
private DataSetObserver mDataSetObserver;
-
/** Temporary frame to hold a child View's frame rectangle */
private Rect mTouchFrame;
@@ -95,7 +90,6 @@ public abstract class AbsSpinner extends AdapterView<SpinnerAdapter> {
setWillNotDraw(false);
}
-
/**
* The Adapter is used to provide the data which backs this Spinner.
* It also provides methods to transform spinner items based on their position
@@ -190,7 +184,7 @@ public abstract class AbsSpinner extends AdapterView<SpinnerAdapter> {
boolean needsMeasuring = true;
int selectedPosition = getSelectedItemPosition();
- if (selectedPosition >= 0 && mAdapter != null) {
+ if (selectedPosition >= 0 && mAdapter != null && selectedPosition < mAdapter.getCount()) {
// Try looking in the recycler. (Maybe we were measured once already)
View view = mRecycler.get(selectedPosition);
if (view == null) {
@@ -237,7 +231,6 @@ public abstract class AbsSpinner extends AdapterView<SpinnerAdapter> {
mWidthMeasureSpec = widthMeasureSpec;
}
-
int getChildHeight(View child) {
return child.getMeasuredHeight();
}
@@ -254,26 +247,17 @@ public abstract class AbsSpinner extends AdapterView<SpinnerAdapter> {
}
void recycleAllViews() {
- int childCount = getChildCount();
+ final int childCount = getChildCount();
final AbsSpinner.RecycleBin recycleBin = mRecycler;
+ final int position = mFirstPosition;
// All views go in recycler
- for (int i=0; i<childCount; i++) {
+ for (int i = 0; i < childCount; i++) {
View v = getChildAt(i);
- int index = mFirstPosition + i;
+ int index = position + i;
recycleBin.put(index, v);
}
}
-
- @Override
- void handleDataChanged() {
- // FIXME -- this is called from both measure and layout.
- // This is harmless right now, but we don't want to do redundant work if
- // this gets more complicated
- super.handleDataChanged();
- }
-
-
/**
* Jump directly to a specific item in the adapter data.
@@ -284,7 +268,6 @@ public abstract class AbsSpinner extends AdapterView<SpinnerAdapter> {
position <= mFirstPosition + getChildCount() - 1;
setSelectionInt(position, shouldAnimate);
}
-
@Override
public void setSelection(int position) {
@@ -335,8 +318,6 @@ public abstract class AbsSpinner extends AdapterView<SpinnerAdapter> {
}
}
-
-
@Override
public SpinnerAdapter getAdapter() {
return mAdapter;
@@ -452,7 +433,7 @@ public abstract class AbsSpinner extends AdapterView<SpinnerAdapter> {
}
class RecycleBin {
- private SparseArray<View> mScrapHeap = new SparseArray<View>();
+ private final SparseArray<View> mScrapHeap = new SparseArray<View>();
public void put(int position, View v) {
mScrapHeap.put(position, v);
@@ -469,12 +450,7 @@ public abstract class AbsSpinner extends AdapterView<SpinnerAdapter> {
}
return result;
}
-
- View peek(int position) {
- // System.out.print("Looking for " + position);
- return mScrapHeap.get(position);
- }
-
+
void clear() {
final SparseArray<View> scrapHeap = mScrapHeap;
final int count = scrapHeap.size();
diff --git a/core/java/android/widget/CheckedTextView.java b/core/java/android/widget/CheckedTextView.java
index aa9062b..bf63607 100644
--- a/core/java/android/widget/CheckedTextView.java
+++ b/core/java/android/widget/CheckedTextView.java
@@ -24,6 +24,7 @@ import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.Gravity;
+import android.view.ViewDebug;
import android.view.accessibility.AccessibilityEvent;
@@ -73,7 +74,8 @@ public class CheckedTextView extends TextView implements Checkable {
public void toggle() {
setChecked(!mChecked);
}
-
+
+ @ViewDebug.ExportedProperty
public boolean isChecked() {
return mChecked;
}
diff --git a/core/java/android/widget/CompoundButton.java b/core/java/android/widget/CompoundButton.java
index 98b0976..bf02ad3 100644
--- a/core/java/android/widget/CompoundButton.java
+++ b/core/java/android/widget/CompoundButton.java
@@ -26,6 +26,7 @@ import android.os.Parcel;
import android.os.Parcelable;
import android.util.AttributeSet;
import android.view.Gravity;
+import android.view.ViewDebug;
import android.view.accessibility.AccessibilityEvent;
/**
@@ -98,6 +99,7 @@ public abstract class CompoundButton extends Button implements Checkable {
return super.performClick();
}
+ @ViewDebug.ExportedProperty
public boolean isChecked() {
return mChecked;
}
diff --git a/core/java/android/widget/ExpandableListConnector.java b/core/java/android/widget/ExpandableListConnector.java
index ccce7c1..9c43e9b 100644
--- a/core/java/android/widget/ExpandableListConnector.java
+++ b/core/java/android/widget/ExpandableListConnector.java
@@ -25,7 +25,6 @@ import android.view.ViewGroup;
import java.util.ArrayList;
import java.util.Collections;
-import java.util.List;
/*
* Implementation notes:
@@ -637,7 +636,7 @@ class ExpandableListConnector extends BaseAdapter implements Filterable {
// Check to see if it's already expanded
if (posMetadata.groupMetadata != null) return false;
- /* Restrict number of exp groups to mMaxExpGroupCount */
+ /* Restrict number of expanded groups to mMaxExpGroupCount */
if (mExpGroupMetadataList.size() >= mMaxExpGroupCount) {
/* Collapse a group */
// TODO: Collapse something not on the screen instead of the first one?
diff --git a/core/java/android/widget/LinearLayout.java b/core/java/android/widget/LinearLayout.java
index 9fcb829..bd07e1f 100644
--- a/core/java/android/widget/LinearLayout.java
+++ b/core/java/android/widget/LinearLayout.java
@@ -632,6 +632,8 @@ public class LinearLayout extends ViewGroup {
final boolean baselineAligned = mBaselineAligned;
final boolean useLargestChild = mUseLargestChild;
+
+ final boolean isExactly = widthMode == MeasureSpec.EXACTLY;
int largestChildWidth = Integer.MIN_VALUE;
@@ -658,14 +660,19 @@ public class LinearLayout extends ViewGroup {
// Optimization: don't bother measuring children who are going to use
// leftover space. These views will get measured again down below if
// there is any leftover space.
- final int totalLength = mTotalLength;
- mTotalLength = Math.max(totalLength, totalLength + lp.leftMargin + lp.rightMargin);
+ if (isExactly) {
+ mTotalLength += lp.leftMargin + lp.rightMargin;
+ } else {
+ final int totalLength = mTotalLength;
+ mTotalLength = Math.max(totalLength, totalLength +
+ lp.leftMargin + lp.rightMargin);
+ }
// Baseline alignment requires to measure widgets to obtain the
- // baseline offset (in particular for TextViews).
- // The following defeats the optimization mentioned above.
- // Allow the child to use as much space as it wants because we
- // can shrink things later (and re-measure).
+ // baseline offset (in particular for TextViews). The following
+ // defeats the optimization mentioned above. Allow the child to
+ // use as much space as it wants because we can shrink things
+ // later (and re-measure).
if (baselineAligned) {
final int freeSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
child.measure(freeSpec, freeSpec);
@@ -695,9 +702,14 @@ public class LinearLayout extends ViewGroup {
}
final int childWidth = child.getMeasuredWidth();
- final int totalLength = mTotalLength;
- mTotalLength = Math.max(totalLength, totalLength + childWidth + lp.leftMargin +
- lp.rightMargin + getNextLocationOffset(child));
+ if (isExactly) {
+ mTotalLength += childWidth + lp.leftMargin + lp.rightMargin +
+ getNextLocationOffset(child);
+ } else {
+ final int totalLength = mTotalLength;
+ mTotalLength = Math.max(totalLength, totalLength + childWidth + lp.leftMargin +
+ lp.rightMargin + getNextLocationOffset(child));
+ }
if (useLargestChild) {
largestChildWidth = Math.max(childWidth, largestChildWidth);
@@ -782,9 +794,14 @@ public class LinearLayout extends ViewGroup {
final LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams)
child.getLayoutParams();
- final int totalLength = mTotalLength;
- mTotalLength = Math.max(totalLength, totalLength + largestChildWidth +
- lp.leftMargin + lp.rightMargin + getNextLocationOffset(child));
+ if (isExactly) {
+ mTotalLength += largestChildWidth + lp.leftMargin + lp.rightMargin +
+ getNextLocationOffset(child);
+ } else {
+ final int totalLength = mTotalLength;
+ mTotalLength = Math.max(totalLength, totalLength + largestChildWidth +
+ lp.leftMargin + lp.rightMargin + getNextLocationOffset(child));
+ }
}
}
@@ -854,9 +871,14 @@ public class LinearLayout extends ViewGroup {
}
}
- final int totalLength = mTotalLength;
- mTotalLength = Math.max(totalLength, totalLength + child.getMeasuredWidth() +
- lp.leftMargin + lp.rightMargin + getNextLocationOffset(child));
+ if (isExactly) {
+ mTotalLength += child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin +
+ getNextLocationOffset(child);
+ } else {
+ final int totalLength = mTotalLength;
+ mTotalLength = Math.max(totalLength, totalLength + child.getMeasuredWidth() +
+ lp.leftMargin + lp.rightMargin + getNextLocationOffset(child));
+ }
boolean matchHeightLocally = heightMode != MeasureSpec.EXACTLY &&
lp.height == LayoutParams.MATCH_PARENT;
diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java
index 2feed03..8d688a5 100644
--- a/core/java/android/widget/ListView.java
+++ b/core/java/android/widget/ListView.java
@@ -1485,7 +1485,6 @@ public class ListView extends AbsListView {
}
// Clear out old views
- //removeAllViewsInLayout();
detachAllViewsFromParent();
switch (mLayoutMode) {
diff --git a/core/java/android/widget/ProgressBar.java b/core/java/android/widget/ProgressBar.java
index 1dcb203..202e658 100644
--- a/core/java/android/widget/ProgressBar.java
+++ b/core/java/android/widget/ProgressBar.java
@@ -36,6 +36,7 @@ import android.graphics.drawable.shapes.Shape;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.View;
+import android.view.ViewDebug;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
@@ -335,6 +336,7 @@ public class ProgressBar extends View {
*
* @return true if the progress bar is in indeterminate mode
*/
+ @ViewDebug.ExportedProperty
public synchronized boolean isIndeterminate() {
return mIndeterminate;
}
@@ -607,6 +609,7 @@ public class ProgressBar extends View {
* @see #setMax(int)
* @see #getMax()
*/
+ @ViewDebug.ExportedProperty
public synchronized int getProgress() {
return mIndeterminate ? 0 : mProgress;
}
@@ -623,6 +626,7 @@ public class ProgressBar extends View {
* @see #setMax(int)
* @see #getMax()
*/
+ @ViewDebug.ExportedProperty
public synchronized int getSecondaryProgress() {
return mIndeterminate ? 0 : mSecondaryProgress;
}
@@ -636,6 +640,7 @@ public class ProgressBar extends View {
* @see #getProgress()
* @see #getSecondaryProgress()
*/
+ @ViewDebug.ExportedProperty
public synchronized int getMax() {
return mMax;
}
@@ -691,8 +696,7 @@ public class ProgressBar extends View {
* <p>Start the indeterminate progress animation.</p>
*/
void startAnimation() {
- int visibility = getVisibility();
- if (visibility != VISIBLE) {
+ if (getVisibility() != VISIBLE) {
return;
}
@@ -766,7 +770,7 @@ public class ProgressBar extends View {
// let's be nice with the UI thread
if (v == GONE || v == INVISIBLE) {
stopAnimation();
- } else if (v == VISIBLE) {
+ } else {
startAnimation();
}
}
@@ -774,6 +778,20 @@ public class ProgressBar extends View {
}
@Override
+ protected void onVisibilityChanged(View changedView, int visibility) {
+ super.onVisibilityChanged(changedView, visibility);
+
+ if (mIndeterminate) {
+ // let's be nice with the UI thread
+ if (visibility == GONE || visibility == INVISIBLE) {
+ stopAnimation();
+ } else {
+ startAnimation();
+ }
+ }
+ }
+
+ @Override
public void invalidateDrawable(Drawable dr) {
if (!mInDrawing) {
if (verifyDrawable(dr)) {
diff --git a/core/java/android/widget/ScrollView.java b/core/java/android/widget/ScrollView.java
index 52ed11d..fd24058 100644
--- a/core/java/android/widget/ScrollView.java
+++ b/core/java/android/widget/ScrollView.java
@@ -22,6 +22,7 @@ import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Rect;
import android.util.AttributeSet;
+import android.util.Log;
import android.view.FocusFinder;
import android.view.KeyEvent;
import android.view.MotionEvent;
@@ -51,6 +52,8 @@ import java.util.List;
* <p>ScrollView only supports vertical scrolling.
*/
public class ScrollView extends FrameLayout {
+ private static final String TAG = "ScrollView";
+
static final int ANIMATED_SCROLL_GAP = 250;
static final float MAX_SCROLL_FACTOR = 0.5f;
@@ -112,6 +115,18 @@ public class ScrollView extends FrameLayout {
private int mTouchSlop;
private int mMinimumVelocity;
private int mMaximumVelocity;
+
+ /**
+ * ID of the active pointer. This is used to retain consistency during
+ * drags/flings if multiple pointers are used.
+ */
+ private int mActivePointerId = INVALID_POINTER;
+
+ /**
+ * Sentinel value for no current active pointer.
+ * Used by {@link #mActivePointerId}.
+ */
+ private static final int INVALID_POINTER = -1;
public ScrollView(Context context) {
this(context, null);
@@ -360,6 +375,17 @@ public class ScrollView extends FrameLayout {
return handled;
}
+ private boolean inChild(int x, int y) {
+ if (getChildCount() > 0) {
+ final View child = getChildAt(0);
+ return !(y < child.getTop()
+ || y >= child.getBottom()
+ || x < child.getLeft()
+ || x >= child.getRight());
+ }
+ return false;
+ }
+
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
/*
@@ -378,10 +404,8 @@ public class ScrollView extends FrameLayout {
return true;
}
- final float y = ev.getY();
-
- switch (action) {
- case MotionEvent.ACTION_MOVE:
+ switch (action & MotionEvent.ACTION_MASK) {
+ case MotionEvent.ACTION_MOVE: {
/*
* mIsBeingDragged == false, otherwise the shortcut would have caught it. Check
* whether the user has moved far enough from his original down touch.
@@ -391,16 +415,29 @@ public class ScrollView extends FrameLayout {
* Locally do absolute value. mLastMotionY is set to the y value
* of the down event.
*/
+ final int pointerIndex = ev.findPointerIndex(mActivePointerId);
+ final float y = ev.getY(pointerIndex);
final int yDiff = (int) Math.abs(y - mLastMotionY);
if (yDiff > mTouchSlop) {
mIsBeingDragged = true;
mLastMotionY = y;
}
break;
+ }
- case MotionEvent.ACTION_DOWN:
- /* Remember location of down touch */
+ case MotionEvent.ACTION_DOWN: {
+ final float y = ev.getY();
+ if (!inChild((int)ev.getX(), (int)y)) {
+ mIsBeingDragged = false;
+ break;
+ }
+
+ /*
+ * Remember location of down touch.
+ * ACTION_DOWN always refers to pointer index 0.
+ */
mLastMotionY = y;
+ mActivePointerId = ev.getPointerId(0);
/*
* If being flinged and user touches the screen, initiate drag;
@@ -409,11 +446,16 @@ public class ScrollView extends FrameLayout {
*/
mIsBeingDragged = !mScroller.isFinished();
break;
+ }
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
/* Release the drag */
mIsBeingDragged = false;
+ mActivePointerId = INVALID_POINTER;
+ break;
+ case MotionEvent.ACTION_POINTER_UP:
+ onSecondaryPointerUp(ev);
break;
}
@@ -439,10 +481,9 @@ public class ScrollView extends FrameLayout {
mVelocityTracker.addMovement(ev);
final int action = ev.getAction();
- final float y = ev.getY();
- switch (action) {
- case MotionEvent.ACTION_DOWN:
+ switch (action & MotionEvent.ACTION_MASK) {
+ case MotionEvent.ACTION_DOWN: {
/*
* If being flinged and user touches, stop the fling. isFinished
* will be false if being flinged.
@@ -451,41 +492,78 @@ public class ScrollView extends FrameLayout {
mScroller.abortAnimation();
}
+ final float y = ev.getY();
+ if (!(mIsBeingDragged = inChild((int)ev.getX(), (int)y))) {
+ return false;
+ }
+
// Remember where the motion event started
mLastMotionY = y;
+ mActivePointerId = ev.getPointerId(0);
break;
+ }
case MotionEvent.ACTION_MOVE:
- // Scroll to follow the motion event
- final int deltaY = (int) (mLastMotionY - y);
- mLastMotionY = y;
+ if (mIsBeingDragged) {
+ // Scroll to follow the motion event
+ final int activePointerIndex = ev.findPointerIndex(mActivePointerId);
+ final float y = ev.getY(activePointerIndex);
+ final int deltaY = (int) (mLastMotionY - y);
+ mLastMotionY = y;
- overscrollBy(0, deltaY, 0, mScrollY, 0, getScrollRange(),
- 0, getOverscrollMax());
+ overscrollBy(0, deltaY, 0, mScrollY, 0, getScrollRange(),
+ 0, getOverscrollMax());
+ }
break;
- case MotionEvent.ACTION_UP:
- final VelocityTracker velocityTracker = mVelocityTracker;
- velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
- int initialVelocity = (int) velocityTracker.getYVelocity();
-
- if (getChildCount() > 0) {
- if ((Math.abs(initialVelocity) > mMinimumVelocity)) {
- fling(-initialVelocity);
- } else {
- final int bottom = getScrollRange();
- if (mScroller.springback(mScrollX, mScrollY, 0, 0, 0, bottom)) {
- invalidate();
+ case MotionEvent.ACTION_UP:
+ if (mIsBeingDragged) {
+ final VelocityTracker velocityTracker = mVelocityTracker;
+ velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
+ int initialVelocity = (int) velocityTracker.getYVelocity(mActivePointerId);
+
+ if (getChildCount() > 0) {
+ if ((Math.abs(initialVelocity) > mMinimumVelocity)) {
+ fling(-initialVelocity);
+ } else {
+ final int bottom = getScrollRange();
+ if (mScroller.springback(mScrollX, mScrollY, 0, 0, 0, bottom)) {
+ invalidate();
+ }
}
}
- }
- if (mVelocityTracker != null) {
- mVelocityTracker.recycle();
- mVelocityTracker = null;
+ mActivePointerId = INVALID_POINTER;
+ mIsBeingDragged = false;
+
+ if (mVelocityTracker != null) {
+ mVelocityTracker.recycle();
+ mVelocityTracker = null;
+ }
}
+ break;
+ case MotionEvent.ACTION_POINTER_UP:
+ onSecondaryPointerUp(ev);
+ break;
}
return true;
}
+ private void onSecondaryPointerUp(MotionEvent ev) {
+ final int pointerIndex = (ev.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK) >>
+ MotionEvent.ACTION_POINTER_INDEX_SHIFT;
+ final int pointerId = ev.getPointerId(pointerIndex);
+ if (pointerId == mActivePointerId) {
+ // This was our active pointer going up. Choose a new
+ // active pointer and adjust accordingly.
+ // TODO: Make this decision more intelligent.
+ final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
+ mLastMotionY = ev.getY(newPointerIndex);
+ mActivePointerId = ev.getPointerId(newPointerIndex);
+ if (mVelocityTracker != null) {
+ mVelocityTracker.clear();
+ }
+ }
+ }
+
@Override
protected void onOverscrolled(int scrollX, int scrollY,
boolean clampedX, boolean clampedY) {
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 7ba0fa1..951563a 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -198,6 +198,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
private boolean mFreezesText;
private boolean mFrozenWithFocus;
private boolean mTemporaryDetach;
+ private boolean mDispatchTemporaryDetach;
private boolean mEatTouchRelease = false;
private boolean mScrolled = false;
@@ -5731,6 +5732,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
/**
* Convenience for {@link Selection#getSelectionStart}.
*/
+ @ViewDebug.ExportedProperty
public int getSelectionStart() {
return Selection.getSelectionStart(getText());
}
@@ -5738,6 +5740,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
/**
* Convenience for {@link Selection#getSelectionEnd}.
*/
+ @ViewDebug.ExportedProperty
public int getSelectionEnd() {
return Selection.getSelectionEnd(getText());
}
@@ -6369,14 +6372,30 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
mBlink.postAtTime(mBlink, mShowCursor + BLINK);
}
+ /**
+ * @hide
+ */
+ @Override
+ public void dispatchFinishTemporaryDetach() {
+ mDispatchTemporaryDetach = true;
+ super.dispatchFinishTemporaryDetach();
+ mDispatchTemporaryDetach = false;
+ }
+
@Override
public void onStartTemporaryDetach() {
- mTemporaryDetach = true;
+ super.onStartTemporaryDetach();
+ // Only track when onStartTemporaryDetach() is called directly,
+ // usually because this instance is an editable field in a list
+ if (!mDispatchTemporaryDetach) mTemporaryDetach = true;
}
@Override
public void onFinishTemporaryDetach() {
- mTemporaryDetach = false;
+ super.onFinishTemporaryDetach();
+ // Only track when onStartTemporaryDetach() is called directly,
+ // usually because this instance is an editable field in a list
+ if (!mDispatchTemporaryDetach) mTemporaryDetach = false;
}
@Override
diff --git a/core/java/android/widget/VideoView.java b/core/java/android/widget/VideoView.java
index 906bca1..c2517a8 100644
--- a/core/java/android/widget/VideoView.java
+++ b/core/java/android/widget/VideoView.java
@@ -62,6 +62,8 @@ public class VideoView extends SurfaceView implements MediaPlayerControl {
private static final int STATE_PLAYING = 3;
private static final int STATE_PAUSED = 4;
private static final int STATE_PLAYBACK_COMPLETED = 5;
+ private static final int STATE_SUSPEND = 6;
+ private static final int STATE_RESUME = 7;
// mCurrentState is a VideoView object's current state.
// mTargetState is the state that a method caller intends to reach.
@@ -87,6 +89,7 @@ public class VideoView extends SurfaceView implements MediaPlayerControl {
private boolean mCanPause;
private boolean mCanSeekBack;
private boolean mCanSeekForward;
+ private int mStateWhenSuspended; //state before calling suspend()
public VideoView(Context context) {
super(context);
@@ -466,7 +469,14 @@ public class VideoView extends SurfaceView implements MediaPlayerControl {
public void surfaceCreated(SurfaceHolder holder)
{
mSurfaceHolder = holder;
- openVideo();
+ //resume() was called before surfaceCreated()
+ if (mMediaPlayer != null && mCurrentState == STATE_SUSPEND
+ && mTargetState == STATE_RESUME) {
+ mMediaPlayer.setDisplay(mSurfaceHolder);
+ resume();
+ } else {
+ openVideo();
+ }
}
public void surfaceDestroyed(SurfaceHolder holder)
@@ -474,7 +484,6 @@ 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();
- release(true);
}
};
@@ -567,7 +576,36 @@ public class VideoView extends SurfaceView implements MediaPlayerControl {
mTargetState = STATE_PAUSED;
}
- // cache duration as mDuration for faster access
+ public void suspend() {
+ if (isInPlaybackState()) {
+ if (mMediaPlayer.suspend()) {
+ mStateWhenSuspended = mCurrentState;
+ mCurrentState = STATE_SUSPEND;
+ mTargetState = STATE_SUSPEND;
+ } else {
+ Log.w(TAG, "Unable to suspend video");
+ mErrorListener.onError(mMediaPlayer, MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
+ }
+ }
+ }
+
+ public void resume() {
+ if (mSurfaceHolder == null && mCurrentState == STATE_SUSPEND){
+ mTargetState = STATE_RESUME;
+ return;
+ }
+ if (mMediaPlayer != null && mCurrentState == STATE_SUSPEND) {
+ if (mMediaPlayer.resume()) {
+ mCurrentState = mStateWhenSuspended;
+ mTargetState = mStateWhenSuspended;
+ } else {
+ Log.w(TAG, "Unable to resume video");
+ mErrorListener.onError(mMediaPlayer, MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
+ }
+ }
+ }
+
+ // cache duration as mDuration for faster access
public int getDuration() {
if (isInPlaybackState()) {
if (mDuration > 0) {
diff --git a/core/java/com/android/internal/app/AlertController.java b/core/java/com/android/internal/app/AlertController.java
index f56b15c..107b145 100644
--- a/core/java/com/android/internal/app/AlertController.java
+++ b/core/java/com/android/internal/app/AlertController.java
@@ -26,6 +26,7 @@ import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.Message;
import android.text.TextUtils;
+import android.util.AttributeSet;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.LayoutInflater;
@@ -48,7 +49,6 @@ import android.widget.ScrollView;
import android.widget.SimpleCursorAdapter;
import android.widget.TextView;
import android.widget.AdapterView.OnItemClickListener;
-import android.util.AttributeSet;
import com.android.internal.R;
@@ -322,24 +322,24 @@ public class AlertController {
public Button getButton(int whichButton) {
switch (whichButton) {
case DialogInterface.BUTTON_POSITIVE:
- return mButtonPositiveMessage != null ? mButtonPositive : null;
+ return mButtonPositive;
case DialogInterface.BUTTON_NEGATIVE:
- return mButtonNegativeMessage != null ? mButtonNegative : null;
+ return mButtonNegative;
case DialogInterface.BUTTON_NEUTRAL:
- return mButtonNeutralMessage != null ? mButtonNeutral : null;
+ return mButtonNeutral;
default:
return null;
}
}
+ @SuppressWarnings({"UnusedDeclaration"})
public boolean onKeyDown(int keyCode, KeyEvent event) {
- if (mScrollView != null && mScrollView.executeKeyEvent(event)) return true;
- return false;
+ return mScrollView != null && mScrollView.executeKeyEvent(event);
}
+ @SuppressWarnings({"UnusedDeclaration"})
public boolean onKeyUp(int keyCode, KeyEvent event) {
- if (mScrollView != null && mScrollView.executeKeyEvent(event)) return true;
- return false;
+ return mScrollView != null && mScrollView.executeKeyEvent(event);
}
private void setupView() {
@@ -469,7 +469,6 @@ public class AlertController {
}
private boolean setupButtons() {
- View defaultButton = null;
int BIT_BUTTON_POSITIVE = 1;
int BIT_BUTTON_NEGATIVE = 2;
int BIT_BUTTON_NEUTRAL = 4;
@@ -482,7 +481,6 @@ public class AlertController {
} else {
mButtonPositive.setText(mButtonPositiveText);
mButtonPositive.setVisibility(View.VISIBLE);
- defaultButton = mButtonPositive;
whichButtons = whichButtons | BIT_BUTTON_POSITIVE;
}
@@ -495,9 +493,6 @@ public class AlertController {
mButtonNegative.setText(mButtonNegativeText);
mButtonNegative.setVisibility(View.VISIBLE);
- if (defaultButton == null) {
- defaultButton = mButtonNegative;
- }
whichButtons = whichButtons | BIT_BUTTON_NEGATIVE;
}
@@ -510,9 +505,6 @@ public class AlertController {
mButtonNeutral.setText(mButtonNeutralText);
mButtonNeutral.setVisibility(View.VISIBLE);
- if (defaultButton == null) {
- defaultButton = mButtonNeutral;
- }
whichButtons = whichButtons | BIT_BUTTON_NEUTRAL;
}
@@ -565,8 +557,6 @@ public class AlertController {
R.styleable.AlertDialog_bottomBright, R.drawable.popup_bottom_bright);
int bottomMedium = a.getResourceId(
R.styleable.AlertDialog_bottomMedium, R.drawable.popup_bottom_medium);
- int centerMedium = a.getResourceId(
- R.styleable.AlertDialog_centerMedium, R.drawable.popup_center_medium);
/*
* We now set the background of all of the sections of the alert.
@@ -596,7 +586,7 @@ public class AlertController {
*/
views[pos] = (contentPanel.getVisibility() == View.GONE)
? null : contentPanel;
- light[pos] = mListView == null ? false : true;
+ light[pos] = mListView != null;
pos++;
if (customPanel != null) {
views[pos] = customPanel;
diff --git a/core/java/com/android/internal/app/TetherActivity.java b/core/java/com/android/internal/app/TetherActivity.java
index a48ccf9..5d71231 100644
--- a/core/java/com/android/internal/app/TetherActivity.java
+++ b/core/java/com/android/internal/app/TetherActivity.java
@@ -141,7 +141,7 @@ public class TetherActivity extends AlertActivity implements
}
} else {
for (String t : tethered) {
- if (!cm.untether("ppp0")) {
+ if (!cm.untether(t)) {
error = true;
}
}
diff --git a/core/java/com/android/internal/content/PackageHelper.java b/core/java/com/android/internal/content/PackageHelper.java
index bc7dbf4..c5db83f 100644
--- a/core/java/com/android/internal/content/PackageHelper.java
+++ b/core/java/com/android/internal/content/PackageHelper.java
@@ -36,7 +36,7 @@ public class PackageHelper {
public static final int RECOMMEND_INSTALL_EXTERNAL = 2;
public static final int RECOMMEND_FAILED_INSUFFICIENT_STORAGE = -1;
public static final int RECOMMEND_FAILED_INVALID_APK = -2;
- private static final boolean DEBUG_SD_INSTALL = true;
+ private static final boolean localLOGV = true;
private static final String TAG = "PackageHelper";
public static IMountService getMountService() {
@@ -58,7 +58,7 @@ public class PackageHelper {
if ((len - (mbLen * 1024 * 1024)) > 0) {
mbLen++;
}
- if (DEBUG_SD_INSTALL) Log.i(TAG, "Size of resource " + mbLen);
+ if (localLOGV) Log.i(TAG, "Size of resource " + mbLen);
try {
int rc = mountService.createSecureContainer(
@@ -68,7 +68,7 @@ public class PackageHelper {
return null;
}
String cachePath = mountService.getSecureContainerPath(cid);
- if (DEBUG_SD_INSTALL) Log.i(TAG, "Created secure container " + cid +
+ if (localLOGV) Log.i(TAG, "Created secure container " + cid +
" at " + cachePath);
return cachePath;
} catch (RemoteException e) {
@@ -93,7 +93,7 @@ public class PackageHelper {
public static boolean unMountSdDir(String cid) {
try {
- int rc = getMountService().unmountSecureContainer(cid, false);
+ int rc = getMountService().unmountSecureContainer(cid, true);
if (rc != StorageResultCode.OperationSucceeded) {
Log.e(TAG, "Failed to unmount " + cid + " with rc " + rc);
return false;
@@ -148,7 +148,8 @@ public class PackageHelper {
public static boolean destroySdDir(String cid) {
try {
- int rc = getMountService().destroySecureContainer(cid, false);
+ if (localLOGV) Log.i(TAG, "Forcibly destroying container " + cid);
+ int rc = getMountService().destroySecureContainer(cid, true);
if (rc != StorageResultCode.OperationSucceeded) {
Log.i(TAG, "Failed to destroy container " + cid);
return false;
diff --git a/core/java/com/android/internal/content/PackageMonitor.java b/core/java/com/android/internal/content/PackageMonitor.java
new file mode 100644
index 0000000..343041f
--- /dev/null
+++ b/core/java/com/android/internal/content/PackageMonitor.java
@@ -0,0 +1,287 @@
+package com.android.internal.content;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.net.Uri;
+
+import java.util.HashSet;
+
+/**
+ * Helper class for monitoring the state of packages: adding, removing,
+ * updating, and disappearing and reappearing on the SD card.
+ */
+public abstract class PackageMonitor extends android.content.BroadcastReceiver {
+ static final IntentFilter sPackageFilt = new IntentFilter();
+ static final IntentFilter sNonDataFilt = new IntentFilter();
+ static final IntentFilter sExternalFilt = new IntentFilter();
+
+ static {
+ sPackageFilt.addAction(Intent.ACTION_PACKAGE_ADDED);
+ sPackageFilt.addAction(Intent.ACTION_PACKAGE_REMOVED);
+ sPackageFilt.addAction(Intent.ACTION_PACKAGE_CHANGED);
+ sPackageFilt.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
+ sPackageFilt.addAction(Intent.ACTION_PACKAGE_RESTARTED);
+ sPackageFilt.addAction(Intent.ACTION_UID_REMOVED);
+ sPackageFilt.addDataScheme("package");
+ sNonDataFilt.addAction(Intent.ACTION_UID_REMOVED);
+ sExternalFilt.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
+ sExternalFilt.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
+ }
+
+ final HashSet<String> mUpdatingPackages = new HashSet<String>();
+
+ Context mRegisteredContext;
+ String[] mDisappearingPackages;
+ String[] mAppearingPackages;
+ String[] mModifiedPackages;
+ int mChangeType;
+ boolean mSomePackagesChanged;
+
+ String[] mTempArray = new String[1];
+
+ public void register(Context context, boolean externalStorage) {
+ if (mRegisteredContext != null) {
+ throw new IllegalStateException("Already registered");
+ }
+ mRegisteredContext = context;
+ context.registerReceiver(this, sPackageFilt);
+ context.registerReceiver(this, sNonDataFilt);
+ if (externalStorage) {
+ context.registerReceiver(this, sExternalFilt);
+ }
+ }
+
+ public void unregister() {
+ if (mRegisteredContext == null) {
+ throw new IllegalStateException("Not registered");
+ }
+ mRegisteredContext.unregisterReceiver(this);
+ mRegisteredContext = null;
+ }
+
+ //not yet implemented
+ boolean isPackageUpdating(String packageName) {
+ synchronized (mUpdatingPackages) {
+ return mUpdatingPackages.contains(packageName);
+ }
+ }
+
+ public void onBeginPackageChanges() {
+ }
+
+ public void onPackageAdded(String packageName, int uid) {
+ }
+
+ public void onPackageRemoved(String packageName, int uid) {
+ }
+
+ public void onPackageUpdateStarted(String packageName, int uid) {
+ }
+
+ public void onPackageUpdateFinished(String packageName, int uid) {
+ }
+
+ public void onPackageChanged(String packageName, int uid, String[] components) {
+ }
+
+ public boolean onHandleForceStop(Intent intent, String[] packages, int uid, boolean doit) {
+ return false;
+ }
+
+ public void onUidRemoved(int uid) {
+ }
+
+ public void onPackagesAvailable(String[] packages) {
+ }
+
+ public void onPackagesUnavailable(String[] packages) {
+ }
+
+ public static final int PACKAGE_UNCHANGED = 0;
+ public static final int PACKAGE_UPDATING = 1;
+ public static final int PACKAGE_TEMPORARY_CHANGE = 2;
+ public static final int PACKAGE_PERMANENT_CHANGE = 3;
+
+ public void onPackageDisappeared(String packageName, int reason) {
+ }
+
+ public void onPackageAppeared(String packageName, int reason) {
+ }
+
+ public void onPackageModified(String packageName) {
+ }
+
+ public boolean didSomePackagesChange() {
+ return mSomePackagesChanged;
+ }
+
+ public int isPackageAppearing(String packageName) {
+ if (mAppearingPackages != null) {
+ for (int i=mAppearingPackages.length-1; i>=0; i--) {
+ if (packageName.equals(mAppearingPackages[i])) {
+ return mChangeType;
+ }
+ }
+ }
+ return PACKAGE_UNCHANGED;
+ }
+
+ public boolean anyPackagesAppearing() {
+ return mAppearingPackages != null;
+ }
+
+ public int isPackageDisappearing(String packageName) {
+ if (mDisappearingPackages != null) {
+ for (int i=mDisappearingPackages.length-1; i>=0; i--) {
+ if (packageName.equals(mDisappearingPackages[i])) {
+ return mChangeType;
+ }
+ }
+ }
+ return PACKAGE_UNCHANGED;
+ }
+
+ public boolean anyPackagesDisappearing() {
+ return mDisappearingPackages != null;
+ }
+
+ public boolean isPackageModified(String packageName) {
+ if (mModifiedPackages != null) {
+ for (int i=mModifiedPackages.length-1; i>=0; i--) {
+ if (packageName.equals(mModifiedPackages[i])) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ public void onSomePackagesChanged() {
+ }
+
+ public void onFinishPackageChanges() {
+ }
+
+ String getPackageName(Intent intent) {
+ Uri uri = intent.getData();
+ String pkg = uri != null ? uri.getSchemeSpecificPart() : null;
+ return pkg;
+ }
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ onBeginPackageChanges();
+
+ mDisappearingPackages = mAppearingPackages = null;
+ mSomePackagesChanged = false;
+
+ String action = intent.getAction();
+ if (Intent.ACTION_PACKAGE_ADDED.equals(action)) {
+ String pkg = getPackageName(intent);
+ int uid = intent.getIntExtra(Intent.EXTRA_UID, 0);
+ // We consider something to have changed regardless of whether
+ // this is just an update, because the update is now finished
+ // and the contents of the package may have changed.
+ mSomePackagesChanged = true;
+ if (pkg != null) {
+ mAppearingPackages = mTempArray;
+ mTempArray[0] = pkg;
+ if (intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
+ mModifiedPackages = mTempArray;
+ mChangeType = PACKAGE_UPDATING;
+ onPackageUpdateFinished(pkg, uid);
+ onPackageModified(pkg);
+ } else {
+ mChangeType = PACKAGE_PERMANENT_CHANGE;
+ onPackageAdded(pkg, uid);
+ }
+ onPackageAppeared(pkg, mChangeType);
+ if (mChangeType == PACKAGE_UPDATING) {
+ synchronized (mUpdatingPackages) {
+ mUpdatingPackages.remove(pkg);
+ }
+ }
+ }
+ } else if (Intent.ACTION_PACKAGE_REMOVED.equals(action)) {
+ String pkg = getPackageName(intent);
+ int uid = intent.getIntExtra(Intent.EXTRA_UID, 0);
+ if (pkg != null) {
+ mDisappearingPackages = mTempArray;
+ mTempArray[0] = pkg;
+ if (intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
+ mChangeType = PACKAGE_UPDATING;
+ synchronized (mUpdatingPackages) {
+ //not used for now
+ //mUpdatingPackages.add(pkg);
+ }
+ onPackageUpdateStarted(pkg, uid);
+ } else {
+ mChangeType = PACKAGE_PERMANENT_CHANGE;
+ // We only consider something to have changed if this is
+ // not a replace; for a replace, we just need to consider
+ // it when it is re-added.
+ mSomePackagesChanged = true;
+ onPackageRemoved(pkg, uid);
+ }
+ onPackageDisappeared(pkg, mChangeType);
+ }
+ } else if (Intent.ACTION_PACKAGE_CHANGED.equals(action)) {
+ String pkg = getPackageName(intent);
+ int uid = intent.getIntExtra(Intent.EXTRA_UID, 0);
+ String[] components = intent.getStringArrayExtra(
+ Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST);
+ if (pkg != null) {
+ mModifiedPackages = mTempArray;
+ mTempArray[0] = pkg;
+ onPackageChanged(pkg, uid, components);
+ // XXX Don't want this to always cause mSomePackagesChanged,
+ // since it can happen a fair amount.
+ onPackageModified(pkg);
+ }
+ } else if (Intent.ACTION_QUERY_PACKAGE_RESTART.equals(action)) {
+ mDisappearingPackages = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES);
+ mChangeType = PACKAGE_TEMPORARY_CHANGE;
+ boolean canRestart = onHandleForceStop(intent,
+ mDisappearingPackages,
+ intent.getIntExtra(Intent.EXTRA_UID, 0), false);
+ if (canRestart) setResultCode(Activity.RESULT_OK);
+ } else if (Intent.ACTION_PACKAGE_RESTARTED.equals(action)) {
+ mDisappearingPackages = new String[] {getPackageName(intent)};
+ mChangeType = PACKAGE_TEMPORARY_CHANGE;
+ onHandleForceStop(intent, mDisappearingPackages,
+ intent.getIntExtra(Intent.EXTRA_UID, 0), true);
+ } else if (Intent.ACTION_UID_REMOVED.equals(action)) {
+ onUidRemoved(intent.getIntExtra(Intent.EXTRA_UID, 0));
+ } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(action)) {
+ String[] pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
+ mAppearingPackages = pkgList;
+ mChangeType = PACKAGE_TEMPORARY_CHANGE;
+ mSomePackagesChanged = true;
+ if (pkgList != null) {
+ onPackagesAvailable(pkgList);
+ for (int i=0; i<pkgList.length; i++) {
+ onPackageAppeared(pkgList[i], PACKAGE_TEMPORARY_CHANGE);
+ }
+ }
+ } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) {
+ String[] pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
+ mDisappearingPackages = pkgList;
+ mChangeType = PACKAGE_TEMPORARY_CHANGE;
+ mSomePackagesChanged = true;
+ if (pkgList != null) {
+ onPackagesUnavailable(pkgList);
+ for (int i=0; i<pkgList.length; i++) {
+ onPackageDisappeared(pkgList[i], PACKAGE_TEMPORARY_CHANGE);
+ }
+ }
+ }
+
+ if (mSomePackagesChanged) {
+ onSomePackagesChanged();
+ }
+
+ onFinishPackageChanges();
+ }
+}
diff --git a/core/java/com/android/internal/content/SyncStateContentProviderHelper.java b/core/java/com/android/internal/content/SyncStateContentProviderHelper.java
index cd6a9a1..274082c 100644
--- a/core/java/com/android/internal/content/SyncStateContentProviderHelper.java
+++ b/core/java/com/android/internal/content/SyncStateContentProviderHelper.java
@@ -50,6 +50,11 @@ public class SyncStateContentProviderHelper {
public static final String PATH = "syncstate";
+ private static final String QUERY_COUNT_SYNC_STATE_ROWS =
+ "SELECT count(*)"
+ + " FROM " + SYNC_STATE_TABLE
+ + " WHERE " + SyncStateContract.Columns._ID + "=?";
+
public void createDatabase(SQLiteDatabase db) {
db.execSQL("DROP TABLE IF EXISTS " + SYNC_STATE_TABLE);
db.execSQL("CREATE TABLE " + SYNC_STATE_TABLE + " ("
@@ -96,11 +101,17 @@ public class SyncStateContentProviderHelper {
return db.update(SYNC_STATE_TABLE, values, selection, selectionArgs);
}
- public void update(SQLiteDatabase db, long rowId, Object data) {
+ public int update(SQLiteDatabase db, long rowId, Object data) {
+ if (DatabaseUtils.longForQuery(db, QUERY_COUNT_SYNC_STATE_ROWS,
+ new String[]{Long.toString(rowId)}) < 1) {
+ return 0;
+ }
db.execSQL("UPDATE " + SYNC_STATE_TABLE
+ " SET " + SyncStateContract.Columns.DATA + "=?"
+ " WHERE " + SyncStateContract.Columns._ID + "=" + rowId,
new Object[]{data});
+ // assume a row was modified since we know it exists
+ return 1;
}
public void onAccountsChanged(SQLiteDatabase db, Account[] accounts) {
diff --git a/common/java/com/android/common/DNParser.java b/core/java/com/android/internal/net/DNParser.java
index 32d57c0..5254207 100644
--- a/common/java/com/android/common/DNParser.java
+++ b/core/java/com/android/internal/net/DNParser.java
@@ -15,7 +15,8 @@
* limitations under the License.
*/
-package com.android.common;
+package com.android.internal.net;
+
import android.util.Log;
@@ -34,6 +35,8 @@ import javax.security.auth.x500.X500Principal;
*
* <p>This class is used by {@link DomainNameValidator} only. However, in order to make this
* class visible from unit tests, it's made public.
+ *
+ * @hide
*/
public final class DNParser {
private static final String TAG = "DNParser";
diff --git a/common/java/com/android/common/DomainNameValidator.java b/core/java/com/android/internal/net/DomainNameValidator.java
index 25dc007..dbd5019 100644
--- a/common/java/com/android/common/DomainNameValidator.java
+++ b/core/java/com/android/internal/net/DomainNameValidator.java
@@ -13,7 +13,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.common;
+package com.android.internal.net;
+
import android.util.Config;
import android.util.Log;
@@ -30,6 +31,7 @@ import java.util.regex.PatternSyntaxException;
import javax.security.auth.x500.X500Principal;
+/** @hide */
public class DomainNameValidator {
private final static String TAG = "DomainNameValidator";
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index dfcc8f7..71ccb3b 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -59,6 +59,13 @@ public final class BatteryStatsImpl extends BatteryStats {
// Current on-disk Parcel version
private static final int VERSION = 42;
+ // The maximum number of names wakelocks we will keep track of
+ // per uid; once the limit is reached, we batch the remaining wakelocks
+ // in to one common name.
+ private static final int MAX_WAKELOCKS_PER_UID = 20;
+
+ private static final String BATCHED_WAKELOCK_NAME = "*overflow*";
+
private static int sNumSpeedSteps;
private final File mFile;
@@ -1757,7 +1764,12 @@ public final class BatteryStatsImpl extends BatteryStats {
String wakelockName = in.readString();
Uid.Wakelock wakelock = new Wakelock();
wakelock.readFromParcelLocked(unpluggables, in);
- mWakelockStats.put(wakelockName, wakelock);
+ if (mWakelockStats.size() < MAX_WAKELOCKS_PER_UID) {
+ // We will just drop some random set of wakelocks if
+ // the previous run of the system was an older version
+ // that didn't impose a limit.
+ mWakelockStats.put(wakelockName, wakelock);
+ }
}
int numSensors = in.readInt();
@@ -2583,8 +2595,14 @@ public final class BatteryStatsImpl extends BatteryStats {
public StopwatchTimer getWakeTimerLocked(String name, int type) {
Wakelock wl = mWakelockStats.get(name);
if (wl == null) {
- wl = new Wakelock();
- mWakelockStats.put(name, wl);
+ if (mWakelockStats.size() > MAX_WAKELOCKS_PER_UID) {
+ name = BATCHED_WAKELOCK_NAME;
+ wl = mWakelockStats.get(name);
+ }
+ if (wl == null) {
+ wl = new Wakelock();
+ mWakelockStats.put(name, wl);
+ }
}
StopwatchTimer t = null;
switch (type) {
diff --git a/core/java/com/android/internal/os/PowerProfile.java b/core/java/com/android/internal/os/PowerProfile.java
index 9e5bdff..2369d25 100644
--- a/core/java/com/android/internal/os/PowerProfile.java
+++ b/core/java/com/android/internal/os/PowerProfile.java
@@ -20,7 +20,7 @@ package com.android.internal.os;
import android.content.Context;
import android.content.res.XmlResourceParser;
-import com.android.common.XmlUtils;
+import com.android.internal.util.XmlUtils;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
diff --git a/common/java/com/android/common/FastXmlSerializer.java b/core/java/com/android/internal/util/FastXmlSerializer.java
index 0d33941..592a8fa 100644
--- a/common/java/com/android/common/FastXmlSerializer.java
+++ b/core/java/com/android/internal/util/FastXmlSerializer.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.common;
+package com.android.internal.util;
import org.xmlpull.v1.XmlSerializer;
diff --git a/common/java/com/android/common/XmlUtils.java b/core/java/com/android/internal/util/XmlUtils.java
index dd57e49..8d8df16 100644
--- a/common/java/com/android/common/XmlUtils.java
+++ b/core/java/com/android/internal/util/XmlUtils.java
@@ -14,7 +14,8 @@
* limitations under the License.
*/
-package com.android.common;
+package com.android.internal.util;
+
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index f074b80..9713c27 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -104,14 +104,24 @@ public class LockPatternUtils {
private static String sLockPatternFilename;
private static String sLockPasswordFilename;
+ DevicePolicyManager getDevicePolicyManager() {
+ if (mDevicePolicyManager == null) {
+ mDevicePolicyManager =
+ (DevicePolicyManager)mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
+ if (mDevicePolicyManager == null) {
+ Log.e(TAG, "Can't get DevicePolicyManagerService: is it running?",
+ new IllegalStateException("Stack trace:"));
+ }
+ }
+ return mDevicePolicyManager;
+ }
/**
* @param contentResolver Used to look up and save settings.
*/
public LockPatternUtils(Context context) {
mContext = context;
mContentResolver = context.getContentResolver();
- mDevicePolicyManager =
- (DevicePolicyManager)context.getSystemService(Context.DEVICE_POLICY_SERVICE);
+ mDevicePolicyManager = getDevicePolicyManager();
// Initialize the location of gesture lock file
if (sLockPatternFilename == null) {
sLockPatternFilename = android.os.Environment.getDataDirectory()
@@ -123,7 +133,7 @@ public class LockPatternUtils {
}
public int getRequestedMinimumPasswordLength() {
- return mDevicePolicyManager.getPasswordMinimumLength(null);
+ return getDevicePolicyManager().getPasswordMinimumLength(null);
}
/**
@@ -133,7 +143,7 @@ public class LockPatternUtils {
* @return
*/
public int getRequestedPasswordMode() {
- int policyMode = mDevicePolicyManager.getPasswordQuality(null);
+ int policyMode = getDevicePolicyManager().getPasswordQuality(null);
switch (policyMode) {
case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC:
return MODE_PASSWORD;
@@ -151,11 +161,11 @@ public class LockPatternUtils {
* @return
*/
public void reportFailedPasswordAttempt() {
- mDevicePolicyManager.reportFailedPasswordAttempt();
+ getDevicePolicyManager().reportFailedPasswordAttempt();
}
public void reportSuccessfulPasswordAttempt() {
- mDevicePolicyManager.reportSuccessfulPasswordAttempt();
+ getDevicePolicyManager().reportSuccessfulPasswordAttempt();
}
public void setActivePasswordState(int mode, int length) {
@@ -171,7 +181,7 @@ public class LockPatternUtils {
policyMode = DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC;
break;
}
- mDevicePolicyManager.setActivePasswordState(policyMode, length);
+ getDevicePolicyManager().setActivePasswordState(policyMode, length);
}
/**
@@ -279,7 +289,7 @@ public class LockPatternUtils {
saveLockPattern(null);
setLong(PASSWORD_TYPE_KEY, MODE_PATTERN);
}
-
+
/**
* Save a lock pattern.
* @param pattern The new pattern to save.
@@ -334,7 +344,7 @@ public class LockPatternUtils {
hasNonDigit = true;
}
}
-
+
// First check if it is sufficient.
switch (reqMode) {
case MODE_PASSWORD: {
@@ -342,19 +352,19 @@ public class LockPatternUtils {
return MODE_UNSPECIFIED;
}
} break;
-
+
case MODE_PIN:
case MODE_PATTERN: {
// Whatever we have is acceptable; we may need to promote the
// mode later.
} break;
-
+
default:
// If it isn't a mode we specifically know, then fail fast.
Log.w(TAG, "adjustPasswordMode: unknown mode " + reqMode);
return MODE_UNSPECIFIED;
}
-
+
// Do we need to promote?
if (hasNonDigit) {
if (reqMode < MODE_PASSWORD) {
@@ -366,10 +376,10 @@ public class LockPatternUtils {
reqMode = MODE_PIN;
}
}
-
+
return reqMode;
}
-
+
/**
* Save a lock password. Does not ensure that the pattern is as good
* as the requested mode, but will adjust the mode to be as good as the
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index e8749ed..85d1a6f 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -45,6 +45,7 @@ LOCAL_SRC_FILES:= \
android_view_Surface.cpp \
android_view_ViewRoot.cpp \
android_text_AndroidCharacter.cpp \
+ android_text_AndroidBidi.cpp \
android_text_KeyCharacterMap.cpp \
android_os_Debug.cpp \
android_os_FileUtils.cpp \
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 7c8df03..8586aca 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -142,6 +142,7 @@ extern int register_android_net_NetworkUtils(JNIEnv* env);
extern int register_android_net_wifi_WifiManager(JNIEnv* env);
extern int register_android_security_Md5MessageDigest(JNIEnv *env);
extern int register_android_text_AndroidCharacter(JNIEnv *env);
+extern int register_android_text_AndroidBidi(JNIEnv *env);
extern int register_android_text_KeyCharacterMap(JNIEnv *env);
extern int register_android_opengl_classes(JNIEnv *env);
extern int register_android_bluetooth_HeadsetBase(JNIEnv* env);
@@ -1184,6 +1185,7 @@ static const RegJNIRec gRegJNI[] = {
REG_JNI(register_android_emoji_EmojiFactory),
REG_JNI(register_android_security_Md5MessageDigest),
REG_JNI(register_android_text_AndroidCharacter),
+ REG_JNI(register_android_text_AndroidBidi),
REG_JNI(register_android_text_KeyCharacterMap),
REG_JNI(register_android_os_Process),
REG_JNI(register_android_os_Binder),
diff --git a/core/jni/android_text_AndroidBidi.cpp b/core/jni/android_text_AndroidBidi.cpp
new file mode 100644
index 0000000..7696bb3
--- /dev/null
+++ b/core/jni/android_text_AndroidBidi.cpp
@@ -0,0 +1,81 @@
+/* //device/libs/android_runtime/android_text_AndroidBidi.cpp
+**
+** Copyright 2010, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT 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 "AndroidUnicode"
+
+#include <jni.h>
+#include <android_runtime/AndroidRuntime.h>
+#include "utils/misc.h"
+#include "utils/Log.h"
+#include "unicode/ubidi.h"
+
+namespace android {
+
+static void jniThrowException(JNIEnv* env, const char* exc, const char* msg = NULL)
+{
+ jclass excClazz = env->FindClass(exc);
+ LOG_ASSERT(excClazz, "Unable to find class %s", exc);
+
+ env->ThrowNew(excClazz, msg);
+}
+
+static jint runBidi(JNIEnv* env, jobject obj, jint dir, jcharArray chsArray,
+ jbyteArray infoArray, int n, jboolean haveInfo)
+{
+ // Parameters are checked on java side
+ // Failures from GetXXXArrayElements indicate a serious out-of-memory condition
+ // that we don't bother to report, we're probably dead anyway.
+ jint result = 0;
+ jchar* chs = env->GetCharArrayElements(chsArray, NULL);
+ if (chs != NULL) {
+ jbyte* info = env->GetByteArrayElements(infoArray, NULL);
+ if (info != NULL) {
+ UErrorCode status = U_ZERO_ERROR;
+ UBiDi* bidi = ubidi_openSized(n, 0, &status);
+ ubidi_setPara(bidi, chs, n, dir, NULL, &status);
+ if (U_SUCCESS(status)) {
+ for (int i = 0; i < n; ++i) {
+ info[i] = ubidi_getLevelAt(bidi, i);
+ }
+ result = ubidi_getParaLevel(bidi);
+ } else {
+ jniThrowException(env, "java/lang/RuntimeException", NULL);
+ }
+ ubidi_close(bidi);
+
+ env->ReleaseByteArrayElements(infoArray, info, 0);
+ }
+ env->ReleaseCharArrayElements(chsArray, chs, JNI_ABORT);
+ }
+ return result;
+}
+
+static JNINativeMethod gMethods[] = {
+ { "runBidi", "(I[C[BIZ)I",
+ (void*) runBidi }
+};
+
+int register_android_text_AndroidBidi(JNIEnv* env)
+{
+ jclass clazz = env->FindClass("android/text/AndroidBidi");
+ LOG_ASSERT(clazz, "Cannot find android/text/AndroidBidi");
+
+ return AndroidRuntime::registerNativeMethods(env, "android/text/AndroidBidi",
+ gMethods, NELEM(gMethods));
+}
+
+}
diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp
index a82a21e..5afa034 100644
--- a/core/jni/android_util_AssetManager.cpp
+++ b/core/jni/android_util_AssetManager.cpp
@@ -1466,19 +1466,25 @@ static jobjectArray android_content_AssetManager_getArrayStringResource(JNIEnv*
for (size_t i=0; ((ssize_t)i)<N; i++, bag++) {
value = bag->map.value;
jstring str = NULL;
-
+
// Take care of resolving the found resource to its final value.
ssize_t block = res.resolveReference(&value, bag->stringBlock, NULL);
if (value.dataType == Res_value::TYPE_STRING) {
- const char16_t* str16 = res.getTableStringBlock(block)->stringAt(value.data, &strLen);
- str = env->NewString(str16, strLen);
- if (str == NULL) {
- doThrow(env, "java/lang/OutOfMemoryError");
- res.unlockBag(startOfBag);
- return NULL;
+ const ResStringPool* pool = res.getTableStringBlock(block);
+ const char* str8 = pool->string8At(value.data, &strLen);
+ if (str8 != NULL) {
+ str = env->NewStringUTF(str8);
+ } else {
+ const char16_t* str16 = pool->stringAt(value.data, &strLen);
+ str = env->NewString(str16, strLen);
+ if (str == NULL) {
+ doThrow(env, "java/lang/OutOfMemoryError");
+ res.unlockBag(startOfBag);
+ return NULL;
+ }
}
}
-
+
env->SetObjectArrayElement(array, i, str);
}
res.unlockBag(startOfBag);
diff --git a/core/jni/android_util_StringBlock.cpp b/core/jni/android_util_StringBlock.cpp
index ffb271c..641fbce 100644
--- a/core/jni/android_util_StringBlock.cpp
+++ b/core/jni/android_util_StringBlock.cpp
@@ -89,6 +89,11 @@ static jstring android_content_StringBlock_nativeGetString(JNIEnv* env, jobject
}
size_t len;
+ const char* str8 = osb->string8At(idx, &len);
+ if (str8 != NULL) {
+ return env->NewStringUTF(str8);
+ }
+
const char16_t* str = osb->stringAt(idx, &len);
if (str == NULL) {
doThrow(env, "java/lang/IndexOutOfBoundsException");
diff --git a/core/res/res/drawable-hdpi/btn_dropdown_disabled.9.png b/core/res/res/drawable-hdpi/btn_dropdown_disabled.9.png
new file mode 100644
index 0000000..c6503c7
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_dropdown_disabled.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_dropdown_disabled_focused.9.png b/core/res/res/drawable-hdpi/btn_dropdown_disabled_focused.9.png
new file mode 100644
index 0000000..152de8b
--- /dev/null
+++ b/core/res/res/drawable-hdpi/btn_dropdown_disabled_focused.9.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
index 7acd0df..72faccf 100644
--- a/core/res/res/drawable-hdpi/btn_search_dialog_default.9.png
+++ 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
index a8b843a..369be10 100644
--- a/core/res/res/drawable-hdpi/btn_search_dialog_pressed.9.png
+++ 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
index cfbc092..7e996ec 100644
--- a/core/res/res/drawable-hdpi/btn_search_dialog_selected.9.png
+++ 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
index 3d0d16e..44668b3 100644
--- 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
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
index 2ccd3da..3a4571e 100644
--- 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
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
index 966ea44..60dc632 100644
--- 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
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
deleted file mode 100644
index af80855..0000000
--- a/core/res/res/drawable-hdpi/spinnerbox_arrow_first.9.png
+++ /dev/null
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
deleted file mode 100644
index dc47275..0000000
--- a/core/res/res/drawable-hdpi/spinnerbox_arrow_last.9.png
+++ /dev/null
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
deleted file mode 100644
index 007f279..0000000
--- a/core/res/res/drawable-hdpi/spinnerbox_arrow_middle.9.png
+++ /dev/null
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
deleted file mode 100644
index 24592a3..0000000
--- a/core/res/res/drawable-hdpi/spinnerbox_arrow_single.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_dropdown_disabled.9.png b/core/res/res/drawable-mdpi/btn_dropdown_disabled.9.png
new file mode 100644
index 0000000..f7464c7
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_dropdown_disabled.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_dropdown_disabled_focused.9.png b/core/res/res/drawable-mdpi/btn_dropdown_disabled_focused.9.png
new file mode 100644
index 0000000..ffe219f
--- /dev/null
+++ b/core/res/res/drawable-mdpi/btn_dropdown_disabled_focused.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_search_dialog_voice_default.9.png b/core/res/res/drawable-mdpi/btn_search_dialog_voice_default.9.png
index febf222..437fbc7 100644
--- a/core/res/res/drawable-mdpi/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-mdpi/btn_search_dialog_voice_pressed.9.png b/core/res/res/drawable-mdpi/btn_search_dialog_voice_pressed.9.png
index 70a200b..a679426 100644
--- a/core/res/res/drawable-mdpi/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-mdpi/btn_search_dialog_voice_selected.9.png b/core/res/res/drawable-mdpi/btn_search_dialog_voice_selected.9.png
index 6f2989f..eb95f22 100644
--- a/core/res/res/drawable-mdpi/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-mdpi/spinnerbox_arrow_first.9.png b/core/res/res/drawable-mdpi/spinnerbox_arrow_first.9.png
deleted file mode 100644
index d8e268d..0000000
--- a/core/res/res/drawable-mdpi/spinnerbox_arrow_first.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/spinnerbox_arrow_last.9.png b/core/res/res/drawable-mdpi/spinnerbox_arrow_last.9.png
deleted file mode 100644
index 087e650..0000000
--- a/core/res/res/drawable-mdpi/spinnerbox_arrow_last.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/spinnerbox_arrow_middle.9.png b/core/res/res/drawable-mdpi/spinnerbox_arrow_middle.9.png
deleted file mode 100644
index f1f2ff5..0000000
--- a/core/res/res/drawable-mdpi/spinnerbox_arrow_middle.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/spinnerbox_arrow_single.9.png b/core/res/res/drawable-mdpi/spinnerbox_arrow_single.9.png
deleted file mode 100644
index f537b3b..0000000
--- a/core/res/res/drawable-mdpi/spinnerbox_arrow_single.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/btn_circle.xml b/core/res/res/drawable/btn_circle.xml
index 9208010..243f506 100644
--- a/core/res/res/drawable/btn_circle.xml
+++ b/core/res/res/drawable/btn_circle.xml
@@ -19,6 +19,8 @@
android:drawable="@drawable/btn_circle_normal" />
<item android:state_window_focused="false" android:state_enabled="false"
android:drawable="@drawable/btn_circle_disable" />
+ <item android:state_pressed="true" android:state_enabled="false"
+ android:drawable="@drawable/btn_circle_disable" />
<item android:state_pressed="true"
android:drawable="@drawable/btn_circle_pressed" />
<item android:state_focused="true" android:state_enabled="true"
diff --git a/core/res/res/drawable/btn_dropdown.xml b/core/res/res/drawable/btn_dropdown.xml
index 8ec8ece..34a0504 100644
--- a/core/res/res/drawable/btn_dropdown.xml
+++ b/core/res/res/drawable/btn_dropdown.xml
@@ -15,10 +15,24 @@
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_window_focused="false" android:drawable="@drawable/btn_dropdown_normal" />
- <item android:state_pressed="true" android:drawable="@drawable/btn_dropdown_pressed" />
- <item android:state_focused="true" android:state_pressed="false"
+ <item
+ android:state_window_focused="false" android:state_enabled="true"
+ android:drawable="@drawable/btn_dropdown_normal" />
+ <item
+ android:state_window_focused="false" android:state_enabled="false"
+ android:drawable="@drawable/btn_dropdown_disabled" />
+ <item
+ android:state_pressed="true"
+ android:drawable="@drawable/btn_dropdown_pressed" />
+ <item
+ android:state_focused="true" android:state_enabled="true"
android:drawable="@drawable/btn_dropdown_selected" />
- <item android:drawable="@drawable/btn_dropdown_normal" />
+ <item
+ android:state_enabled="true"
+ android:drawable="@drawable/btn_dropdown_normal" />
+ <item
+ android:state_focused="true"
+ android:drawable="@drawable/btn_dropdown_disabled_focused" />
+ <item
+ android:drawable="@drawable/btn_dropdown_disabled" />
</selector>
-
diff --git a/core/res/res/drawable/spinnerbox_arrows.xml b/core/res/res/drawable/spinnerbox_arrows.xml
deleted file mode 100644
index 276a0f0..0000000
--- a/core/res/res/drawable/spinnerbox_arrows.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/* //device/apps/common/res/drawable/spinnerbox_arrows.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.
-*/
--->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_single="true" android:drawable="@drawable/spinnerbox_arrow_single" />
- <item android:state_first="true" android:drawable="@drawable/spinnerbox_arrow_first" />
- <item android:state_last="true" android:drawable="@drawable/spinnerbox_arrow_last" />
- <item android:state_middle="true" android:drawable="@drawable/spinnerbox_arrow_middle" />
- <item android:state_pressed="true" android:drawable="@drawable/spinnerbox_arrow_single" />
-</selector>
diff --git a/core/res/res/layout/alert_dialog.xml b/core/res/res/layout/alert_dialog.xml
index 7ae68f9..25a41f8 100644
--- a/core/res/res/layout/alert_dialog.xml
+++ b/core/res/res/layout/alert_dialog.xml
@@ -80,7 +80,8 @@
android:paddingTop="2dip"
android:paddingBottom="12dip"
android:paddingLeft="14dip"
- android:paddingRight="10dip">
+ android:paddingRight="10dip"
+ android:overscrollMode="ifContentScrolls">
<TextView android:id="@+id/message"
style="?android:attr/textAppearanceMedium"
android:layout_width="match_parent"
diff --git a/core/res/res/layout/search_bar.xml b/core/res/res/layout/search_bar.xml
index cf246ba..7935e2a 100644
--- a/core/res/res/layout/search_bar.xml
+++ b/core/res/res/layout/search_bar.xml
@@ -34,7 +34,7 @@
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingLeft="12dip"
- android:paddingRight="12dip"
+ android:paddingRight="6dip"
android:paddingTop="7dip"
android:paddingBottom="16dip"
android:background="@drawable/search_plate_global" >
@@ -95,7 +95,10 @@
android:id="@+id/search_voice_btn"
android:layout_width="wrap_content"
android:layout_height="match_parent"
- android:layout_marginLeft="8dip"
+ android:layout_marginLeft="0dip"
+ android:layout_marginTop="-6.5dip"
+ android:layout_marginBottom="-7dip"
+ android:layout_marginRight="-5dip"
android:background="@drawable/btn_search_dialog_voice"
android:src="@android:drawable/ic_btn_speak_now"
/>
diff --git a/core/res/res/layout/status_bar_expanded.xml b/core/res/res/layout/status_bar_expanded.xml
index a0cd11d..30138a7 100644
--- a/core/res/res/layout/status_bar_expanded.xml
+++ b/core/res/res/layout/status_bar_expanded.xml
@@ -20,9 +20,9 @@
<com.android.server.status.ExpandedView xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
- android:background="@drawable/status_bar_background"
android:focusable="true"
- android:descendantFocusability="afterDescendants">
+ android:descendantFocusability="afterDescendants"
+ >
<LinearLayout
android:layout_width="match_parent"
@@ -79,19 +79,18 @@
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:layout_weight="1"
>
<ScrollView
android:id="@+id/scroll"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_weight="1"
+ android:layout_height="match_parent"
android:fadingEdge="none"
>
<com.android.server.status.NotificationLinearLayout
android:id="@+id/notificationLinearLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_weight="1"
android:orientation="vertical"
>
@@ -136,7 +135,7 @@
<ImageView
android:layout_width="match_parent"
- android:layout_height="wrap_content"
+ android:layout_height="match_parent"
android:src="@drawable/title_bar_shadow"
android:scaleType="fitXY"
/>
diff --git a/core/res/res/values/arrays.xml b/core/res/res/values/arrays.xml
index cdc15c2..0c065ef 100644
--- a/core/res/res/values/arrays.xml
+++ b/core/res/res/values/arrays.xml
@@ -127,15 +127,4 @@
<item><xliff:g id="id">ime</xliff:g></item>
</string-array>
- <!-- Do not translate. Each string points to the component name of an ACTION_WEB_SEARCH
- handling activity. On startup if there were no preferred ACTION_WEB_SEARCH handlers,
- the first component from this list which is found to be installed is set as the
- preferred activity. -->
- <string-array name="default_web_search_providers">
- <item>com.google.android.googlequicksearchbox/.google.GoogleSearch</item>
- <item>com.android.quicksearchbox/.google.GoogleSearch</item>
- <item>com.google.android.providers.enhancedgooglesearch/.Launcher</item>
- <item>com.android.googlesearch/.GoogleSearch</item>
- <item>com.android.websearch/.Search.1</item>
- </string-array>
</resources>
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 33b509b..d66f513 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -302,7 +302,7 @@
<!-- Specify whether an activity should be finished when a "close system
windows" request has been made. This happens, for example, when
the home key is pressed, when the device is locked, when a system
- dialog like recent apps is displayed, etc. -->
+ dialog showing recent applications is displayed, etc. -->
<attr name="finishOnCloseSystemDialogs" format="boolean" />
<!-- Specify whether an activity's task should be cleared when it
@@ -487,7 +487,7 @@
the display will rotate based on how the user moves the device. -->
<enum name="sensor" value="4" />
<!-- Always ignore orientation determined by orientation sensor:
- tthe display will not rotate when the user moves the device. -->
+ the display will not rotate when the user moves the device. -->
<enum name="nosensor" value="5" />
</attr>
@@ -523,7 +523,7 @@
<flag name="keyboard" value="0x0010" />
<!-- The keyboard or navigation accessibility has changed, for example
the user has slid the keyboard out to expose it. Note that
- inspite of its name, this applied to any accessibility: keyboard
+ despite its name, this applied to any accessibility: keyboard
or navigation. -->
<flag name="keyboardHidden" value="0x0020" />
<!-- The navigation type has changed. Should never normally happen. -->
@@ -592,11 +592,16 @@
backup and restore of the application's settings to external storage. -->
<attr name="backupAgent" format="string" />
- <!-- This is not the attribute you are looking for. -->
+ <!-- Whether to allow the application to participate in backup
+ infrastructure. If this attribute is set to <code>false</code>, no backup
+ of the application will ever be performed, even by a full-system backup that
+ would otherwise cause all application data to be saved via adb. The
+ default value of this attribute is <code>true</code>. -->
<attr name="allowBackup" format="boolean" />
<!-- Whether the application in question should be terminated after its
- settings have been restored. The default is to do so. -->
+ settings have been restored. The default is <code>true</code>,
+ which means to do so. -->
<attr name="killAfterRestore" format="boolean" />
<!-- Whether the application needs to have its own Application subclass
@@ -604,15 +609,25 @@
Application class to avoid interference with application logic. -->
<attr name="restoreNeedsApplication" format="boolean" />
+ <!-- Indicate that the application is prepared to attempt a restore of any
+ backed-up dataset, even if the backup is apparently from a newer version
+ of the application than is currently installed on the device. Setting
+ this attribute to <code>true</code> will permit the Backup Manager to
+ attempt restore even when a version mismatch suggests that the data are
+ incompatible. <em>Use with caution!</em>
+
+ <p>The default value of this attribute is <code>false</code>. -->
+ <attr name="restoreAnyVersion" format="boolean" />
+
<!-- The default install location defined by an application. -->
<attr name="installLocation">
<!-- Let the system decide ideal install location -->
<enum name="auto" value="0" />
- <!-- Explicitly request to be installed on internal phone storate
+ <!-- Explicitly request to be installed on internal phone storage
only. -->
<enum name="internalOnly" value="1" />
- <!-- Prefer to be installed on sdcard. There is no guarantee that
- the system will honour this request. The application might end
+ <!-- Prefer to be installed on SD card. There is no guarantee that
+ the system will honor this request. The application might end
up being installed on internal storage if external media
is unavailable or too full. -->
<enum name="preferExternal" value="2" />
@@ -698,6 +713,7 @@
<attr name="allowBackup" />
<attr name="killAfterRestore" />
<attr name="restoreNeedsApplication" />
+ <attr name="restoreAnyVersion" />
<attr name="neverEncrypt" />
</declare-styleable>
@@ -813,7 +829,7 @@
<!-- The <code>uses-feature</code> tag specifies
a specific feature used by the application.
For example an application might specify that it requires
- specific version of open gl. Multiple such attribute
+ specific version of OpenGL. Multiple such attribute
values can be specified by the application.
<p>This appears as a child tag of the root
@@ -1359,7 +1375,7 @@
{@link android.content.Intent#setData Intent.setData()}.
<p><em>Note: scheme and host name matching in the Android framework is
case-sensitive, unlike the formal RFC. As a result,
- Uris here should always be normalized to use lower case letters
+ URIs here should always be normalized to use lower case letters
for these elements (as well as other proper Uri normalization).</em></p> -->
<attr name="data" format="string" />
<!-- The MIME type name to assign to the Intent, as per
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 5d561b8..1e11a99 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -138,6 +138,9 @@
closed. The default is 0. -->
<integer name="config_lidNavigationAccessibility">0</integer>
+ <!-- Indicate whether the SD card is accessible without removing the battery. -->
+ <bool name="config_batterySdCardAccessibility">false</bool>
+
<!-- Vibrator pattern for feedback about a long screen/key press -->
<integer-array name="config_longPressVibePattern">
<item>0</item>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index b334337..5da8e85 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1231,6 +1231,7 @@
<public type="attr" name="safeMode" id="0x010102b8" />
<public type="attr" name="webTextViewStyle" id="0x010102b9" />
<public type="attr" name="overscrollMode" id="0x010102ba" />
+ <public type="attr" name="restoreAnyVersion" id="0x010102bb" />
<public type="anim" name="cycle_interpolator" id="0x010a000c" />
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index f1501ae..5d2d272 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -779,18 +779,18 @@
applications can use this to read phone owner data.</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_readCalendar">read calendar data</string>
+ <string name="permlab_readCalendar">read calendar events</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_readCalendar">Allows an application to read all
of the calendar events stored on your phone. Malicious applications
can use this to send your calendar events to other people.</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_writeCalendar">write calendar data</string>
+ <string name="permlab_writeCalendar">add or modify calendar events and send email to guests</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_writeCalendar">Allows an application to modify the
- calendar events stored on your phone. Malicious
- applications can use this to erase or modify your calendar data.</string>
+ <string name="permdesc_writeCalendar">Allows an application to add or change the
+ events on your calendar, which may send email to guests. Malicious applications can use this
+ to erase or modify your calendar events or to send email to guests.</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_accessMockLocation">mock location sources for testing</string>
diff --git a/core/tests/coretests/Android.mk b/core/tests/coretests/Android.mk
index 1fb9852..b0e2843 100644
--- a/core/tests/coretests/Android.mk
+++ b/core/tests/coretests/Android.mk
@@ -9,6 +9,8 @@ LOCAL_SRC_FILES := \
$(call all-java-files-under, src) \
src/android/os/IAidlTest.aidl
+LOCAL_STATIC_JAVA_LIBRARIES += android-common
+
LOCAL_JAVA_LIBRARIES := android.test.runner
LOCAL_PACKAGE_NAME := FrameworksCoreTests
diff --git a/core/tests/coretests/src/android/app/SearchablesTest.java b/core/tests/coretests/src/android/app/SearchablesTest.java
index 9b4520e..6cb31d4 100644
--- a/core/tests/coretests/src/android/app/SearchablesTest.java
+++ b/core/tests/coretests/src/android/app/SearchablesTest.java
@@ -64,39 +64,7 @@ public class SearchablesTest extends AndroidTestCase {
* findActionKey works
* getIcon works
*/
-
- /**
- * The goal of this test is to confirm proper operation of the
- * SearchableInfo helper class.
- *
- * TODO: The metadata source needs to be mocked out because adding
- * searchability metadata via this test is causing it to leak into the
- * real system. So for now I'm just going to test for existence of the
- * GlobalSearch app (which is searchable).
- */
- public void testSearchableGlobalSearch() {
- // test basic array & hashmap
- Searchables searchables = new Searchables(mContext);
- searchables.buildSearchableList();
- // test linkage from another activity
- // TODO inject this via mocking into the package manager.
- // TODO for now, just check for searchable GlobalSearch app (this isn't really a unit test)
- ComponentName thisActivity = new ComponentName(
- "com.android.globalsearch",
- "com.android.globalsearch.GlobalSearch");
-
- SearchableInfo si = searchables.getSearchableInfo(thisActivity);
- assertNotNull(si);
- assertEquals(thisActivity, si.getSearchActivity());
-
- Context appContext = si.getActivityContext(mContext);
- assertNotNull(appContext);
- MoreAsserts.assertNotEqual(appContext, mContext);
- assertEquals("Quick Search Box", appContext.getString(si.getHintId()));
- assertEquals("Quick Search Box", appContext.getString(si.getLabelId()));
- }
-
/**
* Test that non-searchable activities return no searchable info (this would typically
* trigger the use of the default searchable e.g. contacts)
@@ -113,18 +81,7 @@ public class SearchablesTest extends AndroidTestCase {
SearchableInfo si = searchables.getSearchableInfo(nonActivity);
assertNull(si);
}
-
- /**
- * Test that there is a default searchable (aka global search provider).
- */
- public void testDefaultSearchable() {
- Searchables searchables = new Searchables(mContext);
- searchables.buildSearchableList();
- SearchableInfo si = searchables.getDefaultSearchable();
- checkSearchable(si);
- assertTrue(searchables.isDefaultSearchable(si));
- }
-
+
/**
* This is an attempt to run the searchable info list with a mocked context. Here are some
* things I'd like to test.
@@ -371,7 +328,8 @@ public class SearchablesTest extends AndroidTestCase {
public List<ResolveInfo> queryIntentActivities(Intent intent, int flags) {
assertNotNull(intent);
assertTrue(intent.getAction().equals(Intent.ACTION_SEARCH)
- || intent.getAction().equals(Intent.ACTION_WEB_SEARCH));
+ || intent.getAction().equals(Intent.ACTION_WEB_SEARCH)
+ || intent.getAction().equals(SearchManager.INTENT_ACTION_GLOBAL_SEARCH));
switch (mSearchablesMode) {
case SEARCHABLES_PASSTHROUGH:
return mRealPackageManager.queryIntentActivities(intent, flags);
@@ -472,6 +430,20 @@ public class SearchablesTest extends AndroidTestCase {
throw new UnsupportedOperationException();
}
}
+
+ @Override
+ public int checkPermission(String permName, String pkgName) {
+ assertNotNull(permName);
+ assertNotNull(pkgName);
+ switch (mSearchablesMode) {
+ case SEARCHABLES_PASSTHROUGH:
+ return mRealPackageManager.checkPermission(permName, pkgName);
+ case SEARCHABLES_MOCK_ZERO:
+ return PackageManager.PERMISSION_DENIED;
+ default:
+ throw new UnsupportedOperationException();
+ }
+ }
}
}
diff --git a/core/tests/coretests/src/android/text/StaticLayoutBidiTest.java b/core/tests/coretests/src/android/text/StaticLayoutBidiTest.java
new file mode 100644
index 0000000..da6036a
--- /dev/null
+++ b/core/tests/coretests/src/android/text/StaticLayoutBidiTest.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package android.text;
+
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.Log;
+
+import junit.framework.TestCase;
+
+/**
+ * Tests StaticLayout bidi implementation.
+ */
+public class StaticLayoutBidiTest extends TestCase {
+
+ public static final int REQ_DL = 2; // Layout.DIR_REQUEST_DEFAULT_LTR;
+ public static final int REQ_DR = -2; // Layout.DIR_REQUEST_DEFAULT_RTL;
+ public static final int REQ_L = 1; // Layout.DIR_REQUEST_LTR;
+ public static final int REQ_R = -1; // Layout.DIR_REQUEST_RTL;
+ public static final int L = Layout.DIR_LEFT_TO_RIGHT;
+ public static final int R = Layout.DIR_RIGHT_TO_LEFT;
+
+ public static final String SP = " ";
+ public static final String ALEF = "\u05d0";
+ public static final String BET = "\u05d1";
+ public static final String GIMEL = "\u05d2";
+ public static final String DALET = "\u05d3";
+
+ @SmallTest
+ public void testAllLtr() {
+ expectBidi(REQ_DL, "a test", "000000", L);
+ }
+
+ @SmallTest
+ public void testLtrRtl() {
+ expectBidi(REQ_DL, "abc " + ALEF + BET + GIMEL, "0000111", L);
+ }
+
+ @SmallTest
+ public void testAllRtl() {
+ expectBidi(REQ_DL, ALEF + SP + ALEF + BET + GIMEL + DALET, "111111", R);
+ }
+
+ @SmallTest
+ public void testRtlLtr() {
+ expectBidi(REQ_DL, ALEF + BET + GIMEL + " abc", "1111000", R);
+ }
+
+ @SmallTest
+ public void testRAllLtr() {
+ expectBidi(REQ_R, "a test", "000000", R);
+ }
+
+ @SmallTest
+ public void testRLtrRtl() {
+ expectBidi(REQ_R, "abc " + ALEF + BET + GIMEL, "0001111", R);
+ }
+
+ @SmallTest
+ public void testLAllRtl() {
+ expectBidi(REQ_L, ALEF + SP + ALEF + BET + GIMEL + DALET, "111111", L);
+ }
+
+ @SmallTest
+ public void testLRtlLtr() {
+ expectBidi(REQ_L, ALEF + BET + GIMEL + " abc", "1110000", L);
+ }
+
+ private void expectBidi(int dir, String text,
+ String expectedLevels, int expectedDir) {
+ char[] chs = text.toCharArray();
+ int n = chs.length;
+ byte[] chInfo = new byte[n];
+
+ int resultDir = StaticLayout.bidi(dir, chs, chInfo, n, false);
+
+ {
+ StringBuilder sb = new StringBuilder("info:");
+ for (int i = 0; i < n; ++i) {
+ sb.append(" ").append(String.valueOf(chInfo[i]));
+ }
+ Log.i("BIDI", sb.toString());
+ }
+
+ char[] resultLevelChars = new char[n];
+ for (int i = 0; i < n; ++i) {
+ resultLevelChars[i] = (char)('0' + chInfo[i]);
+ }
+ String resultLevels = new String(resultLevelChars);
+ assertEquals("direction", expectedDir, resultDir);
+ assertEquals("levels", expectedLevels, resultLevels);
+ }
+
+ @SmallTest
+ public void testNativeBidi() {
+ // native bidi returns levels, not simply directions
+ expectNativeBidi(REQ_DL, ALEF + BET + GIMEL + " abc", "1111222", R);
+ }
+
+ private void expectNativeBidi(int dir, String text,
+ String expectedLevels, int expectedDir) {
+ char[] chs = text.toCharArray();
+ int n = chs.length;
+ byte[] chInfo = new byte[n];
+
+ int resultDir = AndroidBidi.bidi(dir, chs, chInfo, n, false);
+
+ {
+ StringBuilder sb = new StringBuilder("info:");
+ for (int i = 0; i < n; ++i) {
+ sb.append(" ").append(String.valueOf(chInfo[i]));
+ }
+ Log.i("BIDI", sb.toString());
+ }
+
+ char[] resultLevelChars = new char[n];
+ for (int i = 0; i < n; ++i) {
+ resultLevelChars[i] = (char)('0' + chInfo[i]);
+ }
+ String resultLevels = new String(resultLevelChars);
+ assertEquals("direction", expectedDir, resultDir);
+ assertEquals("levels", expectedLevels, resultLevels);
+ }
+}
diff --git a/core/tests/coretests/src/android/text/StaticLayoutTest.java b/core/tests/coretests/src/android/text/StaticLayoutTest.java
index 1e4db3d..7511ec1 100644
--- a/core/tests/coretests/src/android/text/StaticLayoutTest.java
+++ b/core/tests/coretests/src/android/text/StaticLayoutTest.java
@@ -213,13 +213,13 @@ public class StaticLayoutTest extends TestCase {
}
public int scale(float height) {
- int altVal = (int)(height * sMult + sAdd + 0.5); // existing impl
+ int altVal = (int)(height * sMult + sAdd + 0.5);
int rndVal = Math.round(height * sMult + sAdd);
if (altVal != rndVal) {
Log.i("Scale", "expected scale: " + rndVal +
" != returned scale: " + altVal);
}
- return altVal; // existing implementation
+ return rndVal;
}
}
diff --git a/core/tests/coretests/src/android/widget/expandablelistview/ExpandableListBasicTest.java b/core/tests/coretests/src/android/widget/expandablelistview/ExpandableListBasicTest.java
index 23a4cde..22bbabc 100644
--- a/core/tests/coretests/src/android/widget/expandablelistview/ExpandableListBasicTest.java
+++ b/core/tests/coretests/src/android/widget/expandablelistview/ExpandableListBasicTest.java
@@ -16,29 +16,28 @@
package android.widget.expandablelistview;
-import android.widget.expandablelistview.ExpandableListSimple;
+import android.app.Instrumentation;
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.suitebuilder.annotation.MediumTest;
import android.util.ExpandableListScenario;
import android.util.ListUtil;
import android.util.ExpandableListScenario.MyGroup;
-
-import java.util.List;
-
-import android.test.ActivityInstrumentationTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
import android.view.KeyEvent;
+import android.view.View;
import android.widget.BaseExpandableListAdapter;
import android.widget.ExpandableListAdapter;
import android.widget.ExpandableListView;
-public class ExpandableListBasicTest extends ActivityInstrumentationTestCase<ExpandableListSimple> {
+import java.util.List;
+
+public class ExpandableListBasicTest extends ActivityInstrumentationTestCase2<ExpandableListSimple> {
private ExpandableListScenario mActivity;
private ExpandableListView mListView;
private ExpandableListAdapter mAdapter;
private ListUtil mListUtil;
public ExpandableListBasicTest() {
- super("com.android.frameworks.coretests",
- ExpandableListSimple.class);
+ super(ExpandableListSimple.class);
}
@Override
@@ -87,7 +86,6 @@ public class ExpandableListBasicTest extends ActivityInstrumentationTestCase<Exp
@MediumTest
public void testExpandedGroupMovement() {
-
// Expand the first group
mListUtil.arrowScrollToSelectedPosition(0);
sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
@@ -125,5 +123,55 @@ public class ExpandableListBasicTest extends ActivityInstrumentationTestCase<Exp
assertFalse("The expanded state was given to the inserted group",
mListView.isGroupExpanded(0));
}
-
+
+ // Static utility method, shared by different ExpandableListView scenario.
+ static void checkGroupAndChildPositions(ExpandableListView elv,
+ ActivityInstrumentationTestCase2<? extends ExpandableListScenario> activityInstrumentation) {
+ // Add a position tester ContextMenu listener to the ExpandableListView
+ PositionTesterContextMenuListener menuListener = new PositionTesterContextMenuListener();
+ elv.setOnCreateContextMenuListener(menuListener);
+
+ ListUtil listUtil = new ListUtil(elv, activityInstrumentation.getInstrumentation());
+ ExpandableListAdapter adapter = elv.getExpandableListAdapter();
+ Instrumentation instrumentation = activityInstrumentation.getInstrumentation();
+
+ int index = elv.getHeaderViewsCount();
+ int groupCount = adapter.getGroupCount();
+ for (int groupIndex = 0; groupIndex < groupCount; groupIndex++) {
+
+ // Expand group
+ assertFalse("Group is already expanded", elv.isGroupExpanded(groupIndex));
+ listUtil.arrowScrollToSelectedPosition(index);
+ instrumentation.waitForIdleSync();
+ activityInstrumentation.sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
+ activityInstrumentation.getInstrumentation().waitForIdleSync();
+ assertTrue("Group did not expand " + groupIndex, elv.isGroupExpanded(groupIndex));
+
+ // Check group index in context menu
+ menuListener.expectGroupContextMenu(groupIndex);
+ // Make sure the group is visible so that getChild finds it
+ listUtil.arrowScrollToSelectedPosition(index);
+ View groupChild = elv.getChildAt(index - elv.getFirstVisiblePosition());
+ elv.showContextMenuForChild(groupChild);
+ index++;
+
+ final int childrenCount = adapter.getChildrenCount(groupIndex);
+ for (int childIndex = 0; childIndex < childrenCount; childIndex++) {
+ // Check child index in context menu
+ listUtil.arrowScrollToSelectedPosition(index);
+ menuListener.expectChildContextMenu(groupIndex, childIndex);
+ View child = elv.getChildAt(index - elv.getFirstVisiblePosition());
+ elv.showContextMenuForChild(child);
+ index++;
+ }
+ }
+
+ // Cleanup: remove the listener we added.
+ elv.setOnCreateContextMenuListener(null);
+ }
+
+ @MediumTest
+ public void testGroupChildPositions() {
+ checkGroupAndChildPositions(mListView, this);
+ }
}
diff --git a/core/tests/coretests/src/android/widget/expandablelistview/ExpandableListWithHeaders.java b/core/tests/coretests/src/android/widget/expandablelistview/ExpandableListWithHeaders.java
index 7965f9f..2251c1d 100644
--- a/core/tests/coretests/src/android/widget/expandablelistview/ExpandableListWithHeaders.java
+++ b/core/tests/coretests/src/android/widget/expandablelistview/ExpandableListWithHeaders.java
@@ -16,13 +16,10 @@
package android.widget.expandablelistview;
-import android.util.ExpandableListScenario;
-
import android.os.Bundle;
+import android.util.ExpandableListScenario;
import android.widget.Button;
import android.widget.ExpandableListView;
-import android.widget.ListAdapter;
-import android.widget.ListView;
public class ExpandableListWithHeaders extends ExpandableListScenario {
private static final int[] sNumChildren = {1, 4, 3, 2, 6};
@@ -46,13 +43,13 @@ public class ExpandableListWithHeaders extends ExpandableListScenario {
for (int i = 0; i < sNumOfHeadersAndFooters; i++) {
Button header = new Button(this);
- header.setText("Header View");
+ header.setText("Header View " + i);
expandableListView.addHeaderView(header);
}
for (int i = 0; i < sNumOfHeadersAndFooters; i++) {
Button footer = new Button(this);
- footer.setText("Footer View");
+ footer.setText("Footer View " + i);
expandableListView.addFooterView(footer);
}
diff --git a/core/tests/coretests/src/android/widget/expandablelistview/ExpandableListWithHeadersTest.java b/core/tests/coretests/src/android/widget/expandablelistview/ExpandableListWithHeadersTest.java
index 50d0929..ca07e6b 100644
--- a/core/tests/coretests/src/android/widget/expandablelistview/ExpandableListWithHeadersTest.java
+++ b/core/tests/coretests/src/android/widget/expandablelistview/ExpandableListWithHeadersTest.java
@@ -16,22 +16,20 @@
package android.widget.expandablelistview;
-import android.test.ActivityInstrumentationTestCase;
+import android.test.ActivityInstrumentationTestCase2;
import android.test.suitebuilder.annotation.LargeTest;
import android.test.suitebuilder.annotation.MediumTest;
+import android.util.ListUtil;
import android.view.KeyEvent;
import android.widget.ExpandableListView;
-import android.widget.expandablelistview.ExpandableListWithHeaders;
-import android.util.ListUtil;
-
-public class ExpandableListWithHeadersTest extends ActivityInstrumentationTestCase<ExpandableListWithHeaders> {
+public class ExpandableListWithHeadersTest extends
+ ActivityInstrumentationTestCase2<ExpandableListWithHeaders> {
private ExpandableListView mExpandableListView;
private ListUtil mListUtil;
public ExpandableListWithHeadersTest() {
- super("com.android.frameworks.coretests",
- ExpandableListWithHeaders.class);
+ super(ExpandableListWithHeaders.class);
}
@Override
@@ -63,4 +61,9 @@ public class ExpandableListWithHeadersTest extends ActivityInstrumentationTestCa
getInstrumentation().waitForIdleSync();
assertTrue(mExpandableListView.isGroupExpanded(0));
}
+
+ @MediumTest
+ public void testGroupChildPositions() {
+ ExpandableListBasicTest.checkGroupAndChildPositions(mExpandableListView, this);
+ }
}
diff --git a/core/tests/coretests/src/android/widget/expandablelistview/InflatedExpandableListView.java b/core/tests/coretests/src/android/widget/expandablelistview/InflatedExpandableListView.java
index 08b0d31..f4c9d56 100644
--- a/core/tests/coretests/src/android/widget/expandablelistview/InflatedExpandableListView.java
+++ b/core/tests/coretests/src/android/widget/expandablelistview/InflatedExpandableListView.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.view.widget.expandablelistview;
+package android.widget.expandablelistview;
import com.android.frameworks.coretests.R;
diff --git a/core/tests/coretests/src/android/widget/expandablelistview/PositionTesterContextMenuListener.java b/core/tests/coretests/src/android/widget/expandablelistview/PositionTesterContextMenuListener.java
new file mode 100644
index 0000000..b96bca1
--- /dev/null
+++ b/core/tests/coretests/src/android/widget/expandablelistview/PositionTesterContextMenuListener.java
@@ -0,0 +1,43 @@
+package android.widget.expandablelistview;
+
+import android.view.ContextMenu;
+import android.view.View;
+import android.view.ContextMenu.ContextMenuInfo;
+import android.view.View.OnCreateContextMenuListener;
+import android.widget.ExpandableListView;
+
+import junit.framework.Assert;
+
+public class PositionTesterContextMenuListener implements OnCreateContextMenuListener {
+
+ private int groupPosition, childPosition;
+
+ private int testType; // as returned by getPackedPositionType
+
+ public void expectGroupContextMenu(int groupPosition) {
+ this.groupPosition = groupPosition;
+ testType = ExpandableListView.PACKED_POSITION_TYPE_GROUP;
+ }
+
+ public void expectChildContextMenu(int groupPosition, int childPosition) {
+ this.groupPosition = groupPosition;
+ this.childPosition = childPosition;
+ testType = ExpandableListView.PACKED_POSITION_TYPE_CHILD;
+ }
+
+ public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
+ ExpandableListView.ExpandableListContextMenuInfo elvMenuInfo = (ExpandableListView.ExpandableListContextMenuInfo) menuInfo;
+ long packedPosition = elvMenuInfo.packedPosition;
+
+ int packedPositionType = ExpandableListView.getPackedPositionType(packedPosition);
+ Assert.assertEquals("Wrong packed position type", testType, packedPositionType);
+
+ int packedPositionGroup = ExpandableListView.getPackedPositionGroup(packedPosition);
+ Assert.assertEquals("Wrong group position", groupPosition, packedPositionGroup);
+
+ if (testType == ExpandableListView.PACKED_POSITION_TYPE_CHILD) {
+ int packedPositionChild = ExpandableListView.getPackedPositionChild(packedPosition);
+ Assert.assertEquals("Wrong child position", childPosition, packedPositionChild);
+ }
+ }
+}
diff --git a/docs/html/guide/practices/design/performance.jd b/docs/html/guide/practices/design/performance.jd
index ab3b3d3..baed020 100644
--- a/docs/html/guide/practices/design/performance.jd
+++ b/docs/html/guide/practices/design/performance.jd
@@ -356,25 +356,19 @@ for loop syntax will be exactly equivalent to explicit iterator usage.</p>
<p>There are several alternatives for iterating through an array:</p>
-<pre>public class Foo {
- int mSplat;
-}
-public class ArrayBenchmark {
- Foo[] mArray = new Foo[27];
- {
- for (int i = 0; i &lt; mArray.length; ++i) {
- mArray[i] = new Foo();
- }
+<pre> static class Foo {
+ int mSplat;
}
+ Foo[] mArray = ...
- public static void zero() {
+ public void zero() {
int sum = 0;
for (int i = 0; i &lt; mArray.length; ++i) {
sum += mArray[i].mSplat;
}
}
- public static void one() {
+ public void one() {
int sum = 0;
Foo[] localArray = mArray;
int len = localArray.length;
@@ -384,13 +378,13 @@ public class ArrayBenchmark {
}
}
- public static void two() {
+ public void two() {
int sum = 0;
for (Foo a : mArray) {
sum += a.mSplat;
}
}
-}</pre>
+</pre>
<p><strong>zero()</strong> is slowest, because the JIT can't yet optimize away
the cost of getting the array length once for every iteration through the
diff --git a/include/binder/Parcel.h b/include/binder/Parcel.h
index ba6c711..66c34b2 100644
--- a/include/binder/Parcel.h
+++ b/include/binder/Parcel.h
@@ -30,6 +30,7 @@ class IBinder;
class ProcessState;
class String8;
class TextOutput;
+class Flattenable;
struct flat_binder_object; // defined in support_p/binder_module.h
@@ -81,6 +82,7 @@ public:
status_t writeString16(const char16_t* str, size_t len);
status_t writeStrongBinder(const sp<IBinder>& val);
status_t writeWeakBinder(const wp<IBinder>& val);
+ status_t write(const Flattenable& 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
@@ -119,7 +121,7 @@ public:
const char16_t* readString16Inplace(size_t* outLen) const;
sp<IBinder> readStrongBinder() const;
wp<IBinder> readWeakBinder() const;
-
+ status_t read(Flattenable& val) const;
// Retrieve native_handle from the parcel. This returns a copy of the
// parcel's native_handle (the caller takes ownership). The caller
diff --git a/include/media/stagefright/AudioPlayer.h b/include/media/stagefright/AudioPlayer.h
index 8e5f05f..ea15a5c 100644
--- a/include/media/stagefright/AudioPlayer.h
+++ b/include/media/stagefright/AudioPlayer.h
@@ -61,7 +61,7 @@ public:
status_t seekTo(int64_t time_us);
bool isSeeking();
- bool reachedEOS();
+ bool reachedEOS(status_t *finalStatus);
private:
sp<MediaSource> mSource;
@@ -81,6 +81,7 @@ private:
bool mSeeking;
bool mReachedEOS;
+ status_t mFinalStatus;
int64_t mSeekTimeUs;
bool mStarted;
diff --git a/include/media/stagefright/OMXCodec.h b/include/media/stagefright/OMXCodec.h
index f8bc7ab..24c2f46 100644
--- a/include/media/stagefright/OMXCodec.h
+++ b/include/media/stagefright/OMXCodec.h
@@ -96,6 +96,7 @@ private:
kRequiresFlushBeforeShutdown = 64,
kDefersOutputBufferAllocation = 128,
kDecoderLiesAboutNumberOfChannels = 256,
+ kInputBufferSizesAreBogus = 512,
};
struct BufferInfo {
@@ -131,6 +132,7 @@ private:
PortStatus mPortStatus[2];
bool mInitialBufferSubmit;
bool mSignalledEOS;
+ status_t mFinalStatus;
bool mNoMoreOutputData;
bool mOutputPortSettingsHaveChanged;
int64_t mSeekTimeUs;
diff --git a/include/ui/GraphicBuffer.h b/include/ui/GraphicBuffer.h
index b9c491b..e72b6b3 100644
--- a/include/ui/GraphicBuffer.h
+++ b/include/ui/GraphicBuffer.h
@@ -23,6 +23,7 @@
#include <ui/android_native_buffer.h>
#include <ui/PixelFormat.h>
#include <ui/Rect.h>
+#include <utils/Flattenable.h>
#include <pixelflinger/pixelflinger.h>
struct android_native_buffer_t;
@@ -30,7 +31,6 @@ struct android_native_buffer_t;
namespace android {
class GraphicBufferMapper;
-class Parcel;
// ===========================================================================
// GraphicBuffer
@@ -40,7 +40,7 @@ class GraphicBuffer
: public EGLNativeBase<
android_native_buffer_t,
GraphicBuffer,
- LightRefBase<GraphicBuffer> >
+ LightRefBase<GraphicBuffer> >, public Flattenable
{
public:
@@ -97,7 +97,6 @@ public:
uint32_t getVerticalStride() const;
protected:
- GraphicBuffer(const Parcel& reply);
virtual ~GraphicBuffer();
enum {
@@ -122,8 +121,16 @@ private:
status_t initSize(uint32_t w, uint32_t h, PixelFormat format,
uint32_t usage);
- static status_t writeToParcel(Parcel* reply,
- android_native_buffer_t const* buffer);
+ void free_handle();
+
+ // Flattenable interface
+ size_t getFlattenedSize() const;
+ size_t getFdCount() const;
+ status_t flatten(void* buffer, size_t size,
+ int fds[], size_t count) const;
+ status_t unflatten(void const* buffer, size_t size,
+ int fds[], size_t count);
+
GraphicBufferMapper& mBufferMapper;
ssize_t mInitCheck;
diff --git a/include/utils/Flattenable.h b/include/utils/Flattenable.h
new file mode 100644
index 0000000..852be3b
--- /dev/null
+++ b/include/utils/Flattenable.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_UTILS_FLATTENABLE_H
+#define ANDROID_UTILS_FLATTENABLE_H
+
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <utils/Errors.h>
+
+namespace android {
+
+class Flattenable
+{
+public:
+ // size in bytes of the flattened object
+ virtual size_t getFlattenedSize() const = 0;
+
+ // number of file descriptors to flatten
+ virtual size_t getFdCount() const = 0;
+
+ // flattens the object into buffer.
+ // size should be at least of getFlattenedSize()
+ // file descriptors are written in the fds[] array but ownership is
+ // not transfered (ie: they must be dupped by the caller of
+ // flatten() if needed).
+ virtual status_t flatten(void* buffer, size_t size,
+ int fds[], size_t count) const = 0;
+
+ // unflattens the object from buffer.
+ // size should be equal to the value of getFlattenedSize() when the
+ // object was flattened.
+ // unflattened file descriptors are found in the fds[] array and
+ // don't need to be dupped(). ie: the caller of unflatten doesn't
+ // keep ownership. If a fd is not retained by unflatten() it must be
+ // explicitly closed.
+ virtual status_t unflatten(void const* buffer, size_t size,
+ int fds[], size_t count) = 0;
+
+protected:
+ virtual ~Flattenable() = 0;
+
+};
+
+}; // namespace android
+
+
+#endif /* ANDROID_UTILS_FLATTENABLE_H */
diff --git a/include/utils/ResourceTypes.h b/include/utils/ResourceTypes.h
index 13ea27e..cd657e8 100644
--- a/include/utils/ResourceTypes.h
+++ b/include/utils/ResourceTypes.h
@@ -447,6 +447,8 @@ public:
}
const char16_t* stringAt(size_t idx, size_t* outLen) const;
+ const char* string8At(size_t idx, size_t* outLen) const;
+
const ResStringPool_span* styleAt(const ResStringPool_ref& ref) const;
const ResStringPool_span* styleAt(size_t idx) const;
diff --git a/keystore/java/android/security/SystemKeyStore.java b/keystore/java/android/security/SystemKeyStore.java
index 61a4293..abdb0ae 100644
--- a/keystore/java/android/security/SystemKeyStore.java
+++ b/keystore/java/android/security/SystemKeyStore.java
@@ -17,6 +17,7 @@
package android.security;
import android.os.Environment;
+import android.os.FileUtils;
import android.os.Process;
import java.io.File;
@@ -92,6 +93,8 @@ public class SystemKeyStore {
fos.write(retKey);
fos.flush();
fos.close();
+ FileUtils.setPermissions(keyFile.getName(), (FileUtils.S_IRUSR | FileUtils.S_IWUSR),
+ -1, -1);
} catch (IOException ioe) {
return null;
}
diff --git a/libs/audioflinger/AudioPolicyManagerBase.cpp b/libs/audioflinger/AudioPolicyManagerBase.cpp
index 096aa73..7b866c7 100644
--- a/libs/audioflinger/AudioPolicyManagerBase.cpp
+++ b/libs/audioflinger/AudioPolicyManagerBase.cpp
@@ -82,8 +82,8 @@ status_t AudioPolicyManagerBase::setDeviceConnectionState(AudioSystem::audio_dev
// keep track of SCO device address
mScoDeviceAddress = String8(device_address, MAX_DEVICE_ADDRESS_LEN);
#ifdef WITH_A2DP
- if ((mA2dpDeviceAddress == mScoDeviceAddress) &&
- (mPhoneState != AudioSystem::MODE_NORMAL)) {
+ if (mA2dpOutput != 0 &&
+ mPhoneState != AudioSystem::MODE_NORMAL) {
mpClientInterface->suspendOutput(mA2dpOutput);
}
#endif
@@ -116,8 +116,8 @@ status_t AudioPolicyManagerBase::setDeviceConnectionState(AudioSystem::audio_dev
if (AudioSystem::isBluetoothScoDevice(device)) {
mScoDeviceAddress = "";
#ifdef WITH_A2DP
- if ((mA2dpDeviceAddress == mScoDeviceAddress) &&
- (mPhoneState != AudioSystem::MODE_NORMAL)) {
+ if (mA2dpOutput != 0 &&
+ mPhoneState != AudioSystem::MODE_NORMAL) {
mpClientInterface->restoreOutput(mA2dpOutput);
}
#endif
@@ -275,10 +275,8 @@ void AudioPolicyManagerBase::setPhoneState(int state)
newDevice = getNewDevice(mHardwareOutput, false);
#ifdef WITH_A2DP
checkOutputForAllStrategies(newDevice);
- // suspend A2DP output if SCO device address is the same as A2DP device address.
- // no need to check that a SCO device is actually connected as mScoDeviceAddress == ""
- // if none is connected and the test below will fail.
- if (mA2dpDeviceAddress == mScoDeviceAddress) {
+ // suspend A2DP output if a SCO device is present.
+ if (mA2dpOutput != 0 && mScoDeviceAddress != "") {
if (oldState == AudioSystem::MODE_NORMAL) {
mpClientInterface->suspendOutput(mA2dpOutput);
} else if (state == AudioSystem::MODE_NORMAL) {
@@ -295,13 +293,31 @@ void AudioPolicyManagerBase::setPhoneState(int state)
if (oldState == AudioSystem::MODE_IN_CALL && newDevice == 0) {
newDevice = hwOutputDesc->device();
}
+
+ // when changing from ring tone to in call mode, mute the ringing tone
+ // immediately and delay the route change to avoid sending the ring tone
+ // tail into the earpiece or headset.
+ int delayMs = 0;
+ if (state == AudioSystem::MODE_IN_CALL && oldState == AudioSystem::MODE_RINGTONE) {
+ // delay the device change command by twice the output latency to have some margin
+ // and be sure that audio buffers not yet affected by the mute are out when
+ // we actually apply the route change
+ delayMs = hwOutputDesc->mLatency*2;
+ setStreamMute(AudioSystem::RING, true, mHardwareOutput);
+ }
+
// change routing is necessary
- setOutputDevice(mHardwareOutput, newDevice, force);
+ setOutputDevice(mHardwareOutput, newDevice, force, delayMs);
// if entering in call state, handle special case of active streams
// pertaining to sonification strategy see handleIncallSonification()
if (state == AudioSystem::MODE_IN_CALL) {
LOGV("setPhoneState() in call state management: new state is %d", state);
+ // unmute the ringing tone after a sufficient delay if it was muted before
+ // setting output device above
+ if (oldState == AudioSystem::MODE_RINGTONE) {
+ setStreamMute(AudioSystem::RING, false, mHardwareOutput, MUTE_TIME_MS);
+ }
for (int stream = 0; stream < AudioSystem::NUM_STREAM_TYPES; stream++) {
handleIncallSonification(stream, true, true);
}
@@ -1173,7 +1189,7 @@ status_t AudioPolicyManagerBase::handleA2dpConnection(AudioSystem::audio_devices
}
AudioOutputDescriptor *hwOutputDesc = mOutputs.valueFor(mHardwareOutput);
- if (mA2dpDeviceAddress == mScoDeviceAddress) {
+ if (mScoDeviceAddress != "") {
// It is normal to suspend twice if we are both in call,
// and have the hardware audio output routed to BT SCO
if (mPhoneState != AudioSystem::MODE_NORMAL) {
@@ -1207,10 +1223,10 @@ status_t AudioPolicyManagerBase::handleA2dpDisconnection(AudioSystem::audio_devi
return INVALID_OPERATION;
}
- // mute media during 2 seconds to avoid outputing sound on hardware output while music stream
+ // mute media strategy to avoid outputting sound on hardware output while music stream
// is switched from A2DP output and before music is paused by music application
setStrategyMute(STRATEGY_MEDIA, true, mHardwareOutput);
- setStrategyMute(STRATEGY_MEDIA, false, mHardwareOutput, 2000);
+ setStrategyMute(STRATEGY_MEDIA, false, mHardwareOutput, MUTE_TIME_MS);
if (!a2dpUsedForSonification()) {
// unmute music on A2DP output if a notification or ringtone is playing
@@ -1538,9 +1554,9 @@ void AudioPolicyManagerBase::setOutputDevice(audio_io_handle_t output, uint32_t
usleep(outputDesc->mLatency*2*1000);
}
#ifdef WITH_A2DP
- // suspend A2D output if SCO device is selected
+ // suspend A2DP output if SCO device is selected
if (AudioSystem::isBluetoothScoDevice((AudioSystem::audio_devices)device)) {
- if (mA2dpOutput && mScoDeviceAddress == mA2dpDeviceAddress) {
+ if (mA2dpOutput != 0) {
mpClientInterface->suspendOutput(mA2dpOutput);
}
}
@@ -1555,7 +1571,7 @@ void AudioPolicyManagerBase::setOutputDevice(audio_io_handle_t output, uint32_t
#ifdef WITH_A2DP
// if disconnecting SCO device, restore A2DP output
if (AudioSystem::isBluetoothScoDevice((AudioSystem::audio_devices)prevDevice)) {
- if (mA2dpOutput && mScoDeviceAddress == mA2dpDeviceAddress) {
+ if (mA2dpOutput != 0) {
LOGV("restore A2DP output");
mpClientInterface->restoreOutput(mA2dpOutput);
}
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index e397bce..00d2210 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -28,6 +28,7 @@
#include <utils/String16.h>
#include <utils/TextOutput.h>
#include <utils/misc.h>
+#include <utils/Flattenable.h>
#include <private/binder/binder_module.h>
@@ -675,6 +676,42 @@ status_t Parcel::writeDupFileDescriptor(int fd)
return writeObject(obj, true);
}
+status_t Parcel::write(const Flattenable& val)
+{
+ status_t err;
+
+ // size if needed
+ size_t len = val.getFlattenedSize();
+ size_t fd_count = val.getFdCount();
+
+ err = this->writeInt32(len);
+ if (err) return err;
+
+ err = this->writeInt32(fd_count);
+ if (err) return err;
+
+ // payload
+ void* buf = this->writeInplace(PAD_SIZE(len));
+ if (buf == NULL)
+ return BAD_VALUE;
+
+ int* fds = NULL;
+ if (fd_count) {
+ fds = new int[fd_count];
+ }
+
+ err = val.flatten(buf, len, fds, fd_count);
+ for (size_t i=0 ; i<fd_count && err==NO_ERROR ; i++) {
+ err = this->writeDupFileDescriptor( fds[i] );
+ }
+
+ if (fd_count) {
+ delete [] fds;
+ }
+
+ return err;
+}
+
status_t Parcel::writeObject(const flat_binder_object& val, bool nullMetaData)
{
const bool enoughData = (mDataPos+sizeof(val)) <= mDataCapacity;
@@ -713,7 +750,6 @@ restart_write:
goto restart_write;
}
-
void Parcel::remove(size_t start, size_t amt)
{
LOG_ALWAYS_FATAL("Parcel::remove() not yet implemented!");
@@ -940,6 +976,38 @@ int Parcel::readFileDescriptor() const
return BAD_TYPE;
}
+status_t Parcel::read(Flattenable& val) const
+{
+ // size
+ const size_t len = this->readInt32();
+ const size_t fd_count = this->readInt32();
+
+ // payload
+ void const* buf = this->readInplace(PAD_SIZE(len));
+ if (buf == NULL)
+ return BAD_VALUE;
+
+ int* fds = NULL;
+ if (fd_count) {
+ fds = new int[fd_count];
+ }
+
+ status_t err = NO_ERROR;
+ for (size_t i=0 ; i<fd_count && err==NO_ERROR ; i++) {
+ fds[i] = dup(this->readFileDescriptor());
+ if (fds[i] < 0) err = BAD_VALUE;
+ }
+
+ if (err == NO_ERROR) {
+ err = val.unflatten(buf, len, fds, fd_count);
+ }
+
+ if (fd_count) {
+ delete [] fds;
+ }
+
+ return err;
+}
const flat_binder_object* Parcel::readObject(bool nullMetaData) const
{
const size_t DPOS = mDataPos;
diff --git a/libs/rs/rsContext.cpp b/libs/rs/rsContext.cpp
index dec993a..cc3a74f 100644
--- a/libs/rs/rsContext.cpp
+++ b/libs/rs/rsContext.cpp
@@ -546,6 +546,8 @@ void Context::setSurface(uint32_t w, uint32_t h, android_native_window_t *sur)
glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &mGL.mMaxFragmentTextureImageUnits);
glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_VECTORS, &mGL.mMaxFragmentUniformVectors);
+
+ mGL.OES_texture_npot = NULL != strstr((const char *)mGL.mExtensions, "GL_OES_texture_npot");
}
}
diff --git a/libs/rs/rsContext.h b/libs/rs/rsContext.h
index 03e65f1..04bd748 100644
--- a/libs/rs/rsContext.h
+++ b/libs/rs/rsContext.h
@@ -163,6 +163,8 @@ public:
mutable const ObjectBase * mObjHead;
+ bool ext_OES_texture_npot() const {return mGL.OES_texture_npot;}
+
protected:
Device *mDev;
@@ -196,6 +198,8 @@ protected:
int32_t mMaxVertexAttribs;
int32_t mMaxVertexUniformVectors;
int32_t mMaxVertexTextureUnits;
+
+ bool OES_texture_npot;
} mGL;
uint32_t mWidth;
diff --git a/libs/rs/rsProgramFragment.cpp b/libs/rs/rsProgramFragment.cpp
index 15f3269..c17b94c 100644
--- a/libs/rs/rsProgramFragment.cpp
+++ b/libs/rs/rsProgramFragment.cpp
@@ -109,7 +109,7 @@ void ProgramFragment::setupGL(const Context *rsc, ProgramFragmentState *state)
}
if (mSamplers[ct].get()) {
- mSamplers[ct]->setupGL(rsc);
+ mSamplers[ct]->setupGL(rsc, mTextures[ct]->getType()->getIsNp2());
} else {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
@@ -159,7 +159,7 @@ void ProgramFragment::setupGL2(const Context *rsc, ProgramFragmentState *state,
glBindTexture(GL_TEXTURE_2D, mTextures[ct]->getTextureID());
rsc->checkError("ProgramFragment::setupGL2 tex bind");
if (mSamplers[ct].get()) {
- mSamplers[ct]->setupGL(rsc);
+ mSamplers[ct]->setupGL(rsc, mTextures[ct]->getType()->getIsNp2());
} else {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
diff --git a/libs/rs/rsSampler.cpp b/libs/rs/rsSampler.cpp
index 7552d54..71f508f 100644
--- a/libs/rs/rsSampler.cpp
+++ b/libs/rs/rsSampler.cpp
@@ -53,7 +53,7 @@ Sampler::~Sampler()
{
}
-void Sampler::setupGL(const Context *rsc)
+void Sampler::setupGL(const Context *rsc, bool npot)
{
GLenum trans[] = {
GL_NEAREST, //RS_SAMPLER_NEAREST,
@@ -64,11 +64,21 @@ void Sampler::setupGL(const Context *rsc)
};
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, trans[mMinFilter]);
+ bool forceNonMip = false;
+ if (!rsc->ext_OES_texture_npot() && npot) {
+ forceNonMip = true;
+ }
+
+ if ((mMinFilter == RS_SAMPLER_LINEAR_MIP_LINEAR) && forceNonMip) {
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ } else {
+ 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]);
+
rsc->checkError("ProgramFragment::setupGL2 tex env");
}
diff --git a/libs/rs/rsSampler.h b/libs/rs/rsSampler.h
index 9e20a2f..0506081 100644
--- a/libs/rs/rsSampler.h
+++ b/libs/rs/rsSampler.h
@@ -41,7 +41,7 @@ public:
virtual ~Sampler();
void bind(Allocation *);
- void setupGL(const Context *);
+ void setupGL(const Context *, bool npot);
void bindToContext(SamplerState *, uint32_t slot);
void unbindFromContext(SamplerState *);
diff --git a/libs/rs/rsType.cpp b/libs/rs/rsType.cpp
index 9d24c6c..c09e979 100644
--- a/libs/rs/rsType.cpp
+++ b/libs/rs/rsType.cpp
@@ -283,6 +283,24 @@ void Type::dumpLOGV(const char *prefix) const
mElement->dumpLOGV(buf);
}
+bool Type::getIsNp2() const
+{
+ uint32_t x = getDimX();
+ uint32_t y = getDimY();
+ uint32_t z = getDimZ();
+
+ if (x && (x & (x-1))) {
+ return true;
+ }
+ if (y && (y & (y-1))) {
+ return true;
+ }
+ if (z && (z & (z-1))) {
+ return true;
+ }
+ return false;
+}
+
//////////////////////////////////////////////////
//
diff --git a/libs/rs/rsType.h b/libs/rs/rsType.h
index 28e6274..c25577c 100644
--- a/libs/rs/rsType.h
+++ b/libs/rs/rsType.h
@@ -56,6 +56,7 @@ public:
uint32_t getLODOffset(uint32_t lod, uint32_t x, uint32_t y, uint32_t z) const;
uint32_t getLODCount() const {return mLODCount;}
+ bool getIsNp2() const;
void setElement(const Element *e) {mElement.set(e);}
@@ -65,6 +66,7 @@ public:
void setDimFaces(bool v) {mFaces = v;}
void setDimLOD(bool v) {mDimLOD = v;}
+
void clear();
void compute();
diff --git a/libs/surfaceflinger/Android.mk b/libs/surfaceflinger/Android.mk
index 395a937..86eb78d 100644
--- a/libs/surfaceflinger/Android.mk
+++ b/libs/surfaceflinger/Android.mk
@@ -35,7 +35,6 @@ LOCAL_SHARED_LIBRARIES := \
libpixelflinger \
libhardware \
libutils \
- libskia \
libEGL \
libGLESv1_CM \
libbinder \
diff --git a/libs/surfaceflinger/LayerBase.h b/libs/surfaceflinger/LayerBase.h
index d1bbd04..6aacd82 100644
--- a/libs/surfaceflinger/LayerBase.h
+++ b/libs/surfaceflinger/LayerBase.h
@@ -22,6 +22,7 @@
#include <EGL/egl.h>
#include <EGL/eglext.h>
+#include <GLES/gl.h>
#include <utils/RefBase.h>
diff --git a/libs/surfaceflinger/SurfaceFlinger.cpp b/libs/surfaceflinger/SurfaceFlinger.cpp
index 2d6152e..b408779 100644
--- a/libs/surfaceflinger/SurfaceFlinger.cpp
+++ b/libs/surfaceflinger/SurfaceFlinger.cpp
@@ -1496,8 +1496,8 @@ status_t SurfaceFlinger::dump(int fd, const Vector<String16>& args)
layer->needsBlending(), layer->needsDithering(),
layer->contentDirty,
s.alpha, s.flags,
- s.transform[0], s.transform[1],
- s.transform[2], s.transform[3]);
+ s.transform[0][0], s.transform[0][1],
+ s.transform[1][0], s.transform[1][1]);
result.append(buffer);
buffer[0] = 0;
/*** LayerBaseClient ***/
@@ -1833,27 +1833,25 @@ void GraphicPlane::setDisplayHardware(DisplayHardware *hw)
status_t GraphicPlane::orientationToTransfrom(
int orientation, int w, int h, Transform* tr)
-{
- float a, b, c, d, x, y;
+{
+ uint32_t flags = 0;
switch (orientation) {
case ISurfaceComposer::eOrientationDefault:
- // make sure the default orientation is optimal
- tr->reset();
- return NO_ERROR;
+ flags = Transform::ROT_0;
+ break;
case ISurfaceComposer::eOrientation90:
- a=0; b=-1; c=1; d=0; x=w; y=0;
+ flags = Transform::ROT_90;
break;
case ISurfaceComposer::eOrientation180:
- a=-1; b=0; c=0; d=-1; x=w; y=h;
+ flags = Transform::ROT_180;
break;
case ISurfaceComposer::eOrientation270:
- a=0; b=1; c=-1; d=0; x=0; y=h;
+ flags = Transform::ROT_270;
break;
default:
return BAD_VALUE;
}
- tr->set(a, b, c, d);
- tr->set(x, y);
+ tr->set(flags, w, h);
return NO_ERROR;
}
@@ -1869,24 +1867,13 @@ status_t GraphicPlane::setOrientation(int orientation)
mHeight = int(h);
Transform orientationTransform;
- if (UNLIKELY(orientation == 42)) {
- float a, b, c, d, x, y;
- const float r = (3.14159265f / 180.0f) * 42.0f;
- const float si = sinf(r);
- const float co = cosf(r);
- a=co; b=-si; c=si; d=co;
- x = si*(h*0.5f) + (1-co)*(w*0.5f);
- y =-si*(w*0.5f) + (1-co)*(h*0.5f);
- orientationTransform.set(a, b, c, d);
- orientationTransform.set(x, y);
- } else {
- GraphicPlane::orientationToTransfrom(orientation, w, h,
- &orientationTransform);
- if (orientation & ISurfaceComposer::eOrientationSwapMask) {
- mWidth = int(h);
- mHeight = int(w);
- }
+ GraphicPlane::orientationToTransfrom(orientation, w, h,
+ &orientationTransform);
+ if (orientation & ISurfaceComposer::eOrientationSwapMask) {
+ mWidth = int(h);
+ mHeight = int(w);
}
+
mOrientation = orientation;
mGlobalTransform = mDisplayTransform * orientationTransform;
return NO_ERROR;
diff --git a/libs/surfaceflinger/Transform.cpp b/libs/surfaceflinger/Transform.cpp
index ab6f7ba..b2d5856 100644
--- a/libs/surfaceflinger/Transform.cpp
+++ b/libs/surfaceflinger/Transform.cpp
@@ -14,180 +14,257 @@
* limitations under the License.
*/
-#include <ui/Region.h>
+#include <math.h>
-#include <private/pixelflinger/ggl_fixed.h>
+#include <cutils/compiler.h>
+#include <utils/String8.h>
+#include <ui/Region.h>
#include "Transform.h"
// ---------------------------------------------------------------------------
-#define LIKELY( exp ) (__builtin_expect( (exp) != 0, true ))
-#define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false ))
+namespace android {
// ---------------------------------------------------------------------------
-namespace android {
+template <typename T> inline T min(T a, T b) {
+ return a<b ? a : b;
+}
+template <typename T> inline T min(T a, T b, T c) {
+ return min(a, min(b, c));
+}
+template <typename T> inline T min(T a, T b, T c, T d) {
+ return min(a, b, min(c, d));
+}
+
+template <typename T> inline T max(T a, T b) {
+ return a>b ? a : b;
+}
+template <typename T> inline T max(T a, T b, T c) {
+ return max(a, max(b, c));
+}
+template <typename T> inline T max(T a, T b, T c, T d) {
+ return max(a, b, max(c, d));
+}
// ---------------------------------------------------------------------------
-Transform::Transform()
- : mType(0)
-{
- mTransform.reset();
+Transform::Transform() {
+ reset();
}
Transform::Transform(const Transform& other)
- : mTransform(other.mTransform), mType(other.mType)
-{
+ : mMatrix(other.mMatrix), mType(other.mType) {
}
-Transform::Transform(int32_t flags) {
- mTransform.reset();
- int sx = (flags & FLIP_H) ? -1 : 1;
- int sy = (flags & FLIP_V) ? -1 : 1;
- if (flags & ROT_90) {
- this->set(0, -sy, sx, 0);
- } else {
- this->set(sx, 0, 0, sy);
- }
+Transform::Transform(uint32_t orientation) {
+ set(orientation, 0, 0);
}
Transform::~Transform() {
}
+
+bool Transform::absIsOne(float f) {
+ return fabs(f) == 1.0f;
+}
+
+bool Transform::isZero(float f) {
+ return fabs(f) == 0.0f;
+}
+
+bool Transform::absEqual(float a, float b) {
+ return fabs(a) == fabs(b);
+}
+
Transform Transform::operator * (const Transform& rhs) const
{
- if (LIKELY(mType == 0))
+ if (CC_LIKELY(mType == IDENTITY))
return rhs;
Transform r(*this);
- r.mTransform.preConcat(rhs.mTransform);
+ if (rhs.mType == IDENTITY)
+ return r;
+
+ // TODO: we could use mType to optimize the matrix multiply
+ const mat33& A(mMatrix);
+ const mat33& B(rhs.mMatrix);
+ mat33& D(r.mMatrix);
+ for (int i=0 ; i<3 ; i++) {
+ const float v0 = A[0][i];
+ const float v1 = A[1][i];
+ const float v2 = A[2][i];
+ D[0][i] = v0*B[0][0] + v1*B[0][1] + v2*B[0][2];
+ D[1][i] = v0*B[1][0] + v1*B[1][1] + v2*B[1][2];
+ D[2][i] = v0*B[2][0] + v1*B[2][1] + v2*B[2][2];
+ }
r.mType |= rhs.mType;
- return r;
-}
-float Transform::operator [] (int i) const
-{
- float r = 0;
- switch(i) {
- case 0: r = SkScalarToFloat( mTransform[SkMatrix::kMScaleX] ); break;
- case 1: r = SkScalarToFloat( mTransform[SkMatrix::kMSkewX] ); break;
- case 2: r = SkScalarToFloat( mTransform[SkMatrix::kMSkewY] ); break;
- case 3: r = SkScalarToFloat( mTransform[SkMatrix::kMScaleY] ); break;
- }
+ // TODO: we could recompute this value from r and rhs
+ r.mType &= 0xFF;
+ r.mType |= UNKNOWN_TYPE;
return r;
}
-uint8_t Transform::type() const
-{
- if (UNLIKELY(mType & 0x80000000)) {
- mType = mTransform.getType();
- }
- return uint8_t(mType & 0xFF);
+float const* Transform::operator [] (int i) const {
+ return mMatrix[i].v;
}
bool Transform::transformed() const {
- return type() > SkMatrix::kTranslate_Mask;
+ return type() > TRANSLATE;
}
int Transform::tx() const {
- return SkScalarRound( mTransform[SkMatrix::kMTransX] );
+ return floorf(mMatrix[2][0] + 0.5f);
}
int Transform::ty() const {
- return SkScalarRound( mTransform[SkMatrix::kMTransY] );
+ return floorf(mMatrix[2][1] + 0.5f);
}
void Transform::reset() {
- mTransform.reset();
- mType = 0;
+ mType = IDENTITY;
+ for(int i=0 ; i<3 ; i++) {
+ vec3& v(mMatrix[i]);
+ for (int j=0 ; j<3 ; j++)
+ v[j] = ((i==j) ? 1.0f : 0.0f);
+ }
}
-void Transform::set( float xx, float xy,
- float yx, float yy)
+void Transform::set(float tx, float ty)
{
- mTransform.set(SkMatrix::kMScaleX, SkFloatToScalar(xx));
- mTransform.set(SkMatrix::kMSkewX, SkFloatToScalar(xy));
- mTransform.set(SkMatrix::kMSkewY, SkFloatToScalar(yx));
- mTransform.set(SkMatrix::kMScaleY, SkFloatToScalar(yy));
- mType |= 0x80000000;
+ mMatrix[2][0] = tx;
+ mMatrix[2][1] = ty;
+ mMatrix[2][2] = 1.0f;
+
+ if (isZero(tx) && isZero(ty)) {
+ mType &= ~TRANSLATE;
+ } else {
+ mType |= TRANSLATE;
+ }
}
-void Transform::set(float radian, float x, float y)
-{
- float r00 = cosf(radian); float r01 = -sinf(radian);
- float r10 = sinf(radian); float r11 = cosf(radian);
- mTransform.set(SkMatrix::kMScaleX, SkFloatToScalar(r00));
- mTransform.set(SkMatrix::kMSkewX, SkFloatToScalar(r01));
- mTransform.set(SkMatrix::kMSkewY, SkFloatToScalar(r10));
- mTransform.set(SkMatrix::kMScaleY, SkFloatToScalar(r11));
- mTransform.set(SkMatrix::kMTransX, SkIntToScalar(x - r00*x - r01*y));
- mTransform.set(SkMatrix::kMTransY, SkIntToScalar(y - r10*x - r11*y));
- mType |= 0x80000000 | SkMatrix::kTranslate_Mask;
-}
-
-void Transform::scale(float s, float x, float y)
+void Transform::set(float a, float b, float c, float d)
{
- mTransform.postScale(s, s, x, y);
- mType |= 0x80000000;
+ mat33& M(mMatrix);
+ M[0][0] = a; M[1][0] = b;
+ M[0][1] = c; M[1][1] = d;
+ M[0][2] = 0; M[1][2] = 0;
+ mType = UNKNOWN_TYPE;
}
-void Transform::set(int tx, int ty)
+void Transform::set(uint32_t flags, float w, float h)
{
- if (tx | ty) {
- mTransform.set(SkMatrix::kMTransX, SkIntToScalar(tx));
- mTransform.set(SkMatrix::kMTransY, SkIntToScalar(ty));
- mType |= SkMatrix::kTranslate_Mask;
+ mType = flags << 8;
+ float sx = (flags & FLIP_H) ? -1 : 1;
+ float sy = (flags & FLIP_V) ? -1 : 1;
+ float a=0, b=0, c=0, d=0, x=0, y=0;
+ int xmask = 0;
+
+ // computation of x,y
+ // x y
+ // 0 0 0
+ // w 0 ROT90
+ // w h FLIPH|FLIPV
+ // 0 h FLIPH|FLIPV|ROT90
+
+ if (flags & ROT_90) {
+ mType |= ROTATE;
+ b = -sy;
+ c = sx;
+ xmask = 1;
} else {
- mTransform.set(SkMatrix::kMTransX, 0);
- mTransform.set(SkMatrix::kMTransY, 0);
- mType &= ~SkMatrix::kTranslate_Mask;
+ a = sx;
+ d = sy;
}
+
+ if (flags & FLIP_H) {
+ mType ^= SCALE;
+ xmask ^= 1;
+ }
+
+ if (flags & FLIP_V) {
+ mType ^= SCALE;
+ y = h;
+ }
+
+ if ((flags & ROT_180) == ROT_180) {
+ mType |= ROTATE;
+ }
+
+ if (xmask) {
+ x = w;
+ }
+
+ if (!isZero(x) || !isZero(y)) {
+ mType |= TRANSLATE;
+ }
+
+ mat33& M(mMatrix);
+ M[0][0] = a; M[1][0] = b; M[2][0] = x;
+ M[0][1] = c; M[1][1] = d; M[2][1] = y;
+ M[0][2] = 0; M[1][2] = 0; M[2][2] = 1;
+}
+
+Transform::vec2 Transform::transform(const vec2& v) const {
+ vec2 r;
+ const mat33& M(mMatrix);
+ r[0] = M[0][0]*v[0] + M[1][0]*v[1] + M[2][0];
+ r[1] = M[0][1]*v[0] + M[1][1]*v[1] + M[2][1];
+ return r;
}
-void Transform::transform(GLfixed* point, int x, int y) const
+Transform::vec3 Transform::transform(const vec3& v) const {
+ vec3 r;
+ const mat33& M(mMatrix);
+ r[0] = M[0][0]*v[0] + M[1][0]*v[1] + M[2][0]*v[2];
+ r[1] = M[0][1]*v[0] + M[1][1]*v[1] + M[2][1]*v[2];
+ r[2] = M[0][2]*v[0] + M[1][2]*v[1] + M[2][2]*v[2];
+ return r;
+}
+
+void Transform::transform(fixed1616* point, int x, int y) const
{
- SkPoint s;
- mTransform.mapXY(SkIntToScalar(x), SkIntToScalar(y), &s);
- point[0] = SkScalarToFixed(s.fX);
- point[1] = SkScalarToFixed(s.fY);
+ const float toFixed = 65536.0f;
+ const mat33& M(mMatrix);
+ vec2 v(x, y);
+ v = transform(v);
+ point[0] = v[0] * toFixed;
+ point[1] = v[1] * toFixed;
}
Rect Transform::makeBounds(int w, int h) const
{
- Rect r;
- SkRect d, s;
- s.set(0, 0, SkIntToScalar(w), SkIntToScalar(h));
- mTransform.mapRect(&d, s);
- r.left = SkScalarRound( d.fLeft );
- r.top = SkScalarRound( d.fTop );
- r.right = SkScalarRound( d.fRight );
- r.bottom = SkScalarRound( d.fBottom );
- return r;
+ return transform( Rect(w, h) );
}
Rect Transform::transform(const Rect& bounds) const
{
Rect r;
- SkRect d, s;
- s.set( SkIntToScalar( bounds.left ),
- SkIntToScalar( bounds.top ),
- SkIntToScalar( bounds.right ),
- SkIntToScalar( bounds.bottom ));
- mTransform.mapRect(&d, s);
- r.left = SkScalarRound( d.fLeft );
- r.top = SkScalarRound( d.fTop );
- r.right = SkScalarRound( d.fRight );
- r.bottom = SkScalarRound( d.fBottom );
+ vec2 lt( bounds.left, bounds.top );
+ vec2 rt( bounds.right, bounds.top );
+ vec2 lb( bounds.left, bounds.bottom );
+ vec2 rb( bounds.right, bounds.bottom );
+
+ lt = transform(lt);
+ rt = transform(rt);
+ lb = transform(lb);
+ rb = transform(rb);
+
+ r.left = floorf(min(lt[0], rt[0], lb[0], rb[0]) + 0.5f);
+ r.top = floorf(min(lt[1], rt[1], lb[1], rb[1]) + 0.5f);
+ r.right = floorf(max(lt[0], rt[0], lb[0], rb[0]) + 0.5f);
+ r.bottom = floorf(max(lt[1], rt[1], lb[1], rb[1]) + 0.5f);
+
return r;
}
Region Transform::transform(const Region& reg) const
{
Region out;
- if (UNLIKELY(transformed())) {
- if (LIKELY(preserveRects())) {
+ if (CC_UNLIKELY(transformed())) {
+ if (CC_LIKELY(preserveRects())) {
Region::const_iterator it = reg.begin();
Region::const_iterator const end = reg.end();
while (it != end) {
@@ -202,31 +279,108 @@ Region Transform::transform(const Region& reg) const
return out;
}
-int32_t Transform::getOrientation() const
+uint32_t Transform::type() const
{
- uint32_t flags = 0;
- if (UNLIKELY(transformed())) {
- SkScalar a = mTransform[SkMatrix::kMScaleX];
- SkScalar b = mTransform[SkMatrix::kMSkewX];
- SkScalar c = mTransform[SkMatrix::kMSkewY];
- SkScalar d = mTransform[SkMatrix::kMScaleY];
- if (b==0 && c==0 && a && d) {
- if (a<0) flags |= FLIP_H;
- if (d<0) flags |= FLIP_V;
- } else if (b && c && a==0 && d==0) {
- flags |= ROT_90;
- if (b>0) flags |= FLIP_H;
- if (c<0) flags |= FLIP_V;
+ if (mType & UNKNOWN_TYPE) {
+ // recompute what this transform is
+
+ const mat33& M(mMatrix);
+ const float a = M[0][0];
+ const float b = M[1][0];
+ const float c = M[0][1];
+ const float d = M[1][1];
+ const float x = M[2][0];
+ const float y = M[2][1];
+
+ bool scale = false;
+ uint32_t flags = ROT_0;
+ if (isZero(b) && isZero(c)) {
+ if (absEqual(a, d)) {
+ if (a<0) flags |= FLIP_H;
+ if (d<0) flags |= FLIP_V;
+ if (!absIsOne(a) || !absIsOne(d)) {
+ scale = true;
+ }
+ } else {
+ flags = ROT_INVALID;
+ }
+ } else if (isZero(a) && isZero(d)) {
+ if (absEqual(b, c)) {
+ flags |= ROT_90;
+ if (b>0) flags |= FLIP_H;
+ if (c<0) flags |= FLIP_V;
+ if (!absIsOne(b) || !absIsOne(c)) {
+ scale = true;
+ }
+ } else {
+ flags = ROT_INVALID;
+ }
+ } else {
+ flags = ROT_INVALID;
+ }
+
+ mType = flags << 8;
+ if (flags & ROT_INVALID) {
+ mType |= UNKNOWN;
} else {
- flags = 0x80000000;
+ if ((flags & ROT_90) || ((flags & ROT_180) == ROT_180))
+ mType |= ROTATE;
+ if (flags & FLIP_H)
+ mType ^= SCALE;
+ if (flags & FLIP_V)
+ mType ^= SCALE;
+ if (scale)
+ mType |= SCALE;
}
+
+ if (!isZero(x) || !isZero(y))
+ mType |= TRANSLATE;
}
- return flags;
+ return mType;
+}
+
+uint32_t Transform::getType() const {
+ return type() & 0xFF;
+}
+
+uint32_t Transform::getOrientation() const
+{
+ return (type() >> 8) & 0xFF;
}
bool Transform::preserveRects() const
{
- return mTransform.rectStaysRect();
+ return (type() & ROT_INVALID) ? false : true;
+}
+
+void Transform::dump(const char* name) const
+{
+ type(); // updates the type
+
+ String8 flags, type;
+ const mat33& m(mMatrix);
+ uint32_t orient = mType >> 8;
+
+ if (orient&ROT_INVALID)
+ flags.append("ROT_INVALID ");
+ if (orient&ROT_90)
+ flags.append("ROT_90 ");
+ if (orient&FLIP_V)
+ flags.append("FLIP_V ");
+ if (orient&FLIP_H)
+ flags.append("FLIP_H ");
+
+ if (mType&SCALE)
+ type.append("SCALE ");
+ if (mType&ROTATE)
+ type.append("ROTATE ");
+ if (mType&TRANSLATE)
+ type.append("TRANSLATE ");
+
+ LOGD("%s (%s, %s)", name, flags.string(), type.string());
+ LOGD("%.2f %.2f %.2f", m[0][0], m[1][0], m[2][0]);
+ LOGD("%.2f %.2f %.2f", m[0][1], m[1][1], m[2][1]);
+ LOGD("%.2f %.2f %.2f", m[0][2], m[1][2], m[2][2]);
}
// ---------------------------------------------------------------------------
diff --git a/libs/surfaceflinger/Transform.h b/libs/surfaceflinger/Transform.h
index ddab404..51d3e3f 100644
--- a/libs/surfaceflinger/Transform.h
+++ b/libs/surfaceflinger/Transform.h
@@ -23,10 +23,6 @@
#include <ui/Point.h>
#include <ui/Rect.h>
-#include <GLES/gl.h>
-
-#include <core/SkMatrix.h>
-
namespace android {
class Region;
@@ -38,9 +34,12 @@ class Transform
public:
Transform();
Transform(const Transform& other);
- Transform(int32_t flags);
+ explicit Transform(uint32_t orientation);
~Transform();
+ typedef int32_t fixed1616;
+
+ // FIXME: must match OVERLAY_TRANSFORM_*, pull from hardware.h
enum orientation_flags {
ROT_0 = 0x00000000,
FLIP_H = 0x00000001,
@@ -48,48 +47,79 @@ public:
ROT_90 = 0x00000004,
ROT_180 = FLIP_H|FLIP_V,
ROT_270 = ROT_180|ROT_90,
- ROT_INVALID = 0x80000000
+ ROT_INVALID = 0x80
};
enum type_mask {
IDENTITY = 0,
TRANSLATE = 0x1,
- SCALE = 0x2,
- AFFINE = 0x4,
- PERSPECTIVE = 0x8
+ ROTATE = 0x2,
+ SCALE = 0x4,
+ UNKNOWN = 0x8
};
- bool transformed() const;
- int32_t getOrientation() const;
- bool preserveRects() const;
-
+ // query the transform
+ bool transformed() const;
+ bool preserveRects() const;
+ uint32_t getType() const;
+ uint32_t getOrientation() const;
+
+ float const* operator [] (int i) const; // returns column i
int tx() const;
int ty() const;
-
+
+ // modify the transform
void reset();
- void set(float xx, float xy, float yx, float yy);
- void set(int tx, int ty);
- void set(float radian, float x, float y);
- void scale(float s, float x, float y);
-
+ void set(float tx, float ty);
+ void set(float a, float b, float c, float d);
+ void set(uint32_t flags, float w, float h);
+
+ // transform data
Rect makeBounds(int w, int h) const;
- void transform(GLfixed* point, int x, int y) const;
+ void transform(fixed1616* point, int x, int y) const;
Region transform(const Region& reg) const;
- Rect transform(const Rect& bounds) const;
-
Transform operator * (const Transform& rhs) const;
- float operator [] (int i) const;
-
- inline uint32_t getType() const { return type(); }
-
- inline Transform(bool) : mType(0xFF) { };
-
-private:
- uint8_t type() const;
private:
- SkMatrix mTransform;
- mutable uint32_t mType;
+ struct vec3 {
+ float v[3];
+ inline vec3() { }
+ inline vec3(float a, float b, float c) {
+ v[0] = a; v[1] = b; v[2] = c;
+ }
+ inline float operator [] (int i) const { return v[i]; }
+ inline float& operator [] (int i) { return v[i]; }
+ };
+ struct vec2 {
+ float v[2];
+ inline vec2() { }
+ inline vec2(float a, float b) {
+ v[0] = a; v[1] = b;
+ }
+ inline float operator [] (int i) const { return v[i]; }
+ inline float& operator [] (int i) { return v[i]; }
+ };
+ struct mat33 {
+ vec3 v[3];
+ inline const vec3& operator [] (int i) const { return v[i]; }
+ inline vec3& operator [] (int i) { return v[i]; }
+ };
+
+ enum { UNKNOWN_TYPE = 0x80000000 };
+
+ // assumes the last row is < 0 , 0 , 1 >
+ vec2 transform(const vec2& v) const;
+ vec3 transform(const vec3& v) const;
+ Rect transform(const Rect& bounds) const;
+ uint32_t type() const;
+ static bool absIsOne(float f);
+ static bool absEqual(float a, float b);
+ static bool isZero(float f);
+
+ void dump(const char* name) const;
+
+ mat33 mMatrix;
+ mutable uint32_t mType;
};
// ---------------------------------------------------------------------------
diff --git a/libs/surfaceflinger_client/ISurface.cpp b/libs/surfaceflinger_client/ISurface.cpp
index 9125146..bb86199 100644
--- a/libs/surfaceflinger_client/ISurface.cpp
+++ b/libs/surfaceflinger_client/ISurface.cpp
@@ -78,7 +78,8 @@ public:
data.writeInt32(bufferIdx);
data.writeInt32(usage);
remote()->transact(REQUEST_BUFFER, data, &reply);
- sp<GraphicBuffer> buffer = new GraphicBuffer(reply);
+ sp<GraphicBuffer> buffer = new GraphicBuffer();
+ reply.read(*buffer);
return buffer;
}
@@ -141,7 +142,9 @@ status_t BnSurface::onTransact(
int bufferIdx = data.readInt32();
int usage = data.readInt32();
sp<GraphicBuffer> buffer(requestBuffer(bufferIdx, usage));
- return GraphicBuffer::writeToParcel(reply, buffer.get());
+ if (buffer == NULL)
+ return BAD_VALUE;
+ return reply->write(*buffer);
}
case REGISTER_BUFFERS: {
CHECK_INTERFACE(ISurface, data, reply);
diff --git a/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp
index 6a5c8a9..ba1fd9c 100644
--- a/libs/ui/GraphicBuffer.cpp
+++ b/libs/ui/GraphicBuffer.cpp
@@ -14,12 +14,12 @@
* limitations under the License.
*/
+#define LOG_TAG "GraphicBuffer"
+
#include <stdlib.h>
#include <stdint.h>
#include <sys/types.h>
-#include <binder/Parcel.h>
-
#include <utils/Errors.h>
#include <utils/Log.h>
@@ -77,34 +77,21 @@ GraphicBuffer::GraphicBuffer(uint32_t w, uint32_t h,
handle = inHandle;
}
-GraphicBuffer::GraphicBuffer(const Parcel& data)
- : BASE(), mOwner(ownHandle), mBufferMapper(GraphicBufferMapper::get()),
- mInitCheck(NO_ERROR), mVStride(0), mIndex(-1)
+GraphicBuffer::~GraphicBuffer()
{
- // 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();
+ if (handle) {
+ free_handle();
}
}
-GraphicBuffer::~GraphicBuffer()
+void GraphicBuffer::free_handle()
{
- if (handle) {
- if (mOwner == ownHandle) {
- native_handle_close(handle);
- native_handle_delete(const_cast<native_handle*>(handle));
- } else if (mOwner == ownData) {
- GraphicBufferAllocator& allocator(GraphicBufferAllocator::get());
- allocator.free(handle);
- }
+ if (mOwner == ownHandle) {
+ native_handle_close(handle);
+ native_handle_delete(const_cast<native_handle*>(handle));
+ } else if (mOwner == ownData) {
+ GraphicBufferAllocator& allocator(GraphicBufferAllocator::get());
+ allocator.free(handle);
}
}
@@ -192,29 +179,83 @@ status_t GraphicBuffer::lock(GGLSurface* sur, uint32_t usage)
return res;
}
+size_t GraphicBuffer::getFlattenedSize() const {
+ return (8 + (handle ? handle->numInts : 0))*sizeof(int);
+}
+
+size_t GraphicBuffer::getFdCount() const {
+ return handle ? handle->numFds : 0;
+}
-status_t GraphicBuffer::writeToParcel(Parcel* reply,
- android_native_buffer_t const* buffer)
+status_t GraphicBuffer::flatten(void* buffer, size_t size,
+ int fds[], size_t count) const
{
- if (buffer == NULL)
- return BAD_VALUE;
+ size_t sizeNeeded = GraphicBuffer::getFlattenedSize();
+ if (size < sizeNeeded) return NO_MEMORY;
+
+ size_t fdCountNeeded = GraphicBuffer::getFdCount();
+ if (count < fdCountNeeded) return NO_MEMORY;
+
+ int* buf = static_cast<int*>(buffer);
+ buf[0] = 'GBFR';
+ buf[1] = width;
+ buf[2] = height;
+ buf[3] = stride;
+ buf[4] = format;
+ buf[5] = usage;
+ buf[6] = 0;
+ buf[7] = 0;
- if (buffer->width < 0 || buffer->height < 0)
- return BAD_VALUE;
+ if (handle) {
+ buf[6] = handle->numFds;
+ buf[7] = handle->numInts;
+ native_handle_t const* const h = handle;
+ memcpy(fds, h->data, h->numFds*sizeof(int));
+ memcpy(&buf[8], h->data + h->numFds, h->numInts*sizeof(int));
+ }
+
+ return NO_ERROR;
+}
+
+status_t GraphicBuffer::unflatten(void const* buffer, size_t size,
+ int fds[], size_t count)
+{
+ if (size < 8*sizeof(int)) return NO_MEMORY;
+
+ int const* buf = static_cast<int const*>(buffer);
+ if (buf[0] != 'GBFR') return BAD_TYPE;
+
+ const size_t numFds = buf[6];
+ const size_t numInts = buf[7];
- status_t err = NO_ERROR;
- if (buffer->handle == NULL) {
- // this buffer doesn't have a handle
- reply->writeInt32(NO_MEMORY);
+ const size_t sizeNeeded = (8 + numInts) * sizeof(int);
+ if (size < sizeNeeded) return NO_MEMORY;
+
+ size_t fdCountNeeded = 0;
+ if (count < fdCountNeeded) return NO_MEMORY;
+
+ if (handle) {
+ // free previous handle if any
+ free_handle();
+ }
+
+ if (numFds || numInts) {
+ width = buf[1];
+ height = buf[2];
+ stride = buf[3];
+ format = buf[4];
+ usage = buf[5];
+ native_handle* h = native_handle_create(numFds, numInts);
+ memcpy(h->data, fds, numFds*sizeof(int));
+ memcpy(h->data + numFds, &buf[8], numInts*sizeof(int));
+ handle = h;
} 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);
+ width = height = stride = format = usage = 0;
+ handle = NULL;
}
- return err;
+
+ mOwner = ownHandle;
+ return NO_ERROR;
}
diff --git a/libs/utils/Android.mk b/libs/utils/Android.mk
index d2cfd3b..d0eedb4 100644
--- a/libs/utils/Android.mk
+++ b/libs/utils/Android.mk
@@ -25,6 +25,7 @@ commonSources:= \
CallStack.cpp \
Debug.cpp \
FileMap.cpp \
+ Flattenable.cpp \
RefBase.cpp \
ResourceTypes.cpp \
SharedBuffer.cpp \
diff --git a/libs/utils/Flattenable.cpp b/libs/utils/Flattenable.cpp
new file mode 100644
index 0000000..1f2ffaa
--- /dev/null
+++ b/libs/utils/Flattenable.cpp
@@ -0,0 +1,24 @@
+/*
+ * 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 <utils/Flattenable.h>
+
+namespace android {
+
+Flattenable::~Flattenable() {
+}
+
+}; // namespace android
diff --git a/libs/utils/ResourceTypes.cpp b/libs/utils/ResourceTypes.cpp
index e8bd5cf..38600b9 100644
--- a/libs/utils/ResourceTypes.cpp
+++ b/libs/utils/ResourceTypes.cpp
@@ -497,6 +497,34 @@ const uint16_t* ResStringPool::stringAt(size_t idx, size_t* outLen) const
return NULL;
}
+const char* ResStringPool::string8At(size_t idx, size_t* outLen) const
+{
+ if (mError == NO_ERROR && idx < mHeader->stringCount) {
+ const bool isUTF8 = (mHeader->flags&ResStringPool_header::UTF8_FLAG) != 0;
+ const uint32_t off = mEntries[idx]/(isUTF8?sizeof(char):sizeof(char16_t));
+ if (off < (mStringPoolSize-1)) {
+ if (isUTF8) {
+ const uint8_t* strings = (uint8_t*)mStrings;
+ const uint8_t* str = strings+off;
+ DECODE_LENGTH(str, sizeof(uint8_t), *outLen)
+ size_t encLen;
+ DECODE_LENGTH(str, sizeof(uint8_t), encLen)
+ if ((uint32_t)(str+encLen-strings) < mStringPoolSize) {
+ return (const char*)str;
+ } else {
+ LOGW("Bad string block: string #%d extends to %d, past end at %d\n",
+ (int)idx, (int)(str+encLen-strings), (int)mStringPoolSize);
+ }
+ }
+ } else {
+ LOGW("Bad string block: string #%d entry is at %d, past end at %d\n",
+ (int)idx, (int)(off*sizeof(uint16_t)),
+ (int)(mStringPoolSize*sizeof(uint16_t)));
+ }
+ }
+ return NULL;
+}
+
const ResStringPool_span* ResStringPool::styleAt(const ResStringPool_ref& ref) const
{
return styleAt(ref.index);
@@ -4018,14 +4046,19 @@ void ResTable::print_value(const Package* pkg, const Res_value& value) const
printf("(attribute) 0x%08x\n", value.data);
} else if (value.dataType == Res_value::TYPE_STRING) {
size_t len;
- const char16_t* str = pkg->header->values.stringAt(
+ const char* str8 = pkg->header->values.string8At(
value.data, &len);
- if (str == NULL) {
- printf("(string) null\n");
+ if (str8 != NULL) {
+ printf("(string8) \"%s\"\n", str8);
} else {
- printf("(string%d) \"%s\"\n",
- pkg->header->values.isUTF8()?8:16,
- String8(str, len).string());
+ const char16_t* str16 = pkg->header->values.stringAt(
+ value.data, &len);
+ if (str16 != NULL) {
+ printf("(string16) \"%s\"\n",
+ String8(str16, len).string());
+ } else {
+ printf("(string) null\n");
+ }
}
} else if (value.dataType == Res_value::TYPE_FLOAT) {
printf("(float) %g\n", *(const float*)&value.data);
diff --git a/location/java/com/android/internal/location/GpsLocationProvider.java b/location/java/com/android/internal/location/GpsLocationProvider.java
index 8e84106..90b50cc 100755
--- a/location/java/com/android/internal/location/GpsLocationProvider.java
+++ b/location/java/com/android/internal/location/GpsLocationProvider.java
@@ -321,7 +321,9 @@ public class GpsLocationProvider implements LocationProviderInterface {
public GpsLocationProvider(Context context, ILocationManager locationManager) {
mContext = context;
mLocationManager = locationManager;
- mNIHandler= new GpsNetInitiatedHandler(context, this);
+ mNIHandler = new GpsNetInitiatedHandler(context, this);
+
+ mLocation.setExtras(mLocationExtras);
// Create a wake lock
PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
@@ -759,7 +761,7 @@ public class GpsLocationProvider implements LocationProviderInterface {
positionMode = GPS_POSITION_MODE_STANDALONE;
}
- if (!native_start(positionMode, false, mFixInterval)) {
+ if (!native_start(positionMode, false, 1)) {
mStarted = false;
Log.e(TAG, "native_start failed in startNavigating()");
return;
@@ -870,7 +872,12 @@ public class GpsLocationProvider implements LocationProviderInterface {
}
if (mStarted && mStatus != LocationProvider.AVAILABLE) {
- mAlarmManager.cancel(mTimeoutIntent);
+ // we still want to time out if we do not receive MIN_FIX_COUNT
+ // within the time out and we are requesting infrequent fixes
+ if (mFixInterval < NO_FIX_TIMEOUT) {
+ mAlarmManager.cancel(mTimeoutIntent);
+ }
+
// send an intent to notify that the GPS is receiving fixes.
Intent intent = new Intent(GPS_FIX_CHANGE_ACTION);
intent.putExtra(EXTRA_ENABLED, true);
diff --git a/location/java/com/android/internal/location/GpsXtraDownloader.java b/location/java/com/android/internal/location/GpsXtraDownloader.java
index 02a9f48..978bda2 100644
--- a/location/java/com/android/internal/location/GpsXtraDownloader.java
+++ b/location/java/com/android/internal/location/GpsXtraDownloader.java
@@ -32,10 +32,10 @@ import java.util.Random;
import android.content.Context;
import android.net.Proxy;
+import android.net.http.AndroidHttpClient;
import android.util.Config;
import android.util.Log;
-import com.android.common.AndroidHttpClient;
/**
diff --git a/media/java/android/media/MediaFile.java b/media/java/android/media/MediaFile.java
index 2294069..9d1d420 100644
--- a/media/java/android/media/MediaFile.java
+++ b/media/java/android/media/MediaFile.java
@@ -17,13 +17,16 @@
package android.media;
import android.content.ContentValues;
-import android.os.SystemProperties;
import android.provider.MediaStore.Audio;
import android.provider.MediaStore.Images;
import android.provider.MediaStore.Video;
+import android.media.DecoderCapabilities;
+import android.media.DecoderCapabilities.VideoDecoder;
+import android.media.DecoderCapabilities.AudioDecoder;
import java.util.HashMap;
import java.util.Iterator;
+import java.util.List;
/**
* MediaScanner helper class.
@@ -98,13 +101,34 @@ public class MediaFile {
sFileTypeMap.put(extension, new MediaFileType(fileType, mimeType));
sMimeTypeMap.put(mimeType, Integer.valueOf(fileType));
}
+
+ private static boolean isWMAEnabled() {
+ List<AudioDecoder> decoders = DecoderCapabilities.getAudioDecoders();
+ for (AudioDecoder decoder: decoders) {
+ if (decoder == AudioDecoder.AUDIO_DECODER_WMA) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private static boolean isWMVEnabled() {
+ List<VideoDecoder> decoders = DecoderCapabilities.getVideoDecoders();
+ for (VideoDecoder decoder: decoders) {
+ if (decoder == VideoDecoder.VIDEO_DECODER_WMV) {
+ return true;
+ }
+ }
+ return false;
+ }
+
static {
addFileType("MP3", FILE_TYPE_MP3, "audio/mpeg");
addFileType("M4A", FILE_TYPE_M4A, "audio/mp4");
addFileType("WAV", FILE_TYPE_WAV, "audio/x-wav");
addFileType("AMR", FILE_TYPE_AMR, "audio/amr");
addFileType("AWB", FILE_TYPE_AWB, "audio/amr-wb");
- if (SystemProperties.getInt("ro.media.dec.aud.wma.enabled", 0) != 0) {
+ if (isWMAEnabled()) {
addFileType("WMA", FILE_TYPE_WMA, "audio/x-ms-wma");
}
addFileType("OGG", FILE_TYPE_OGG, "application/ogg");
@@ -127,7 +151,7 @@ public class MediaFile {
addFileType("3GPP", FILE_TYPE_3GPP, "video/3gpp");
addFileType("3G2", FILE_TYPE_3GPP2, "video/3gpp2");
addFileType("3GPP2", FILE_TYPE_3GPP2, "video/3gpp2");
- if (SystemProperties.getInt("ro.media.dec.vid.wmv.enabled", 0) != 0) {
+ if (isWMVEnabled()) {
addFileType("WMV", FILE_TYPE_WMV, "video/x-ms-wmv");
addFileType("ASF", FILE_TYPE_ASF, "video/x-ms-asf");
}
diff --git a/media/jni/android_media_ResampleInputStream.cpp b/media/jni/android_media_ResampleInputStream.cpp
index f248557..d965d9a 100644
--- a/media/jni/android_media_ResampleInputStream.cpp
+++ b/media/jni/android_media_ResampleInputStream.cpp
@@ -92,7 +92,7 @@ static void android_media_ResampleInputStream_fir21(JNIEnv *env, jclass clazz,
jint jNpoints) {
// safety first!
- if (nFir21 + jNpoints > BUF_SIZE) {
+ if (nFir21 + jNpoints * 2 > BUF_SIZE) {
throwException(env, "java/lang/IllegalArgumentException",
"FIR+data too long %d", nFir21 + jNpoints);
return;
diff --git a/media/libstagefright/AudioPlayer.cpp b/media/libstagefright/AudioPlayer.cpp
index 7997cd6..57f58be 100644
--- a/media/libstagefright/AudioPlayer.cpp
+++ b/media/libstagefright/AudioPlayer.cpp
@@ -38,6 +38,7 @@ AudioPlayer::AudioPlayer(const sp<MediaPlayerBase::AudioSink> &audioSink)
mPositionTimeRealUs(-1),
mSeeking(false),
mReachedEOS(false),
+ mFinalStatus(OK),
mStarted(false),
mAudioSink(audioSink) {
}
@@ -168,6 +169,7 @@ void AudioPlayer::stop() {
mPositionTimeRealUs = -1;
mSeeking = false;
mReachedEOS = false;
+ mFinalStatus = OK;
mStarted = false;
}
@@ -181,8 +183,11 @@ bool AudioPlayer::isSeeking() {
return mSeeking;
}
-bool AudioPlayer::reachedEOS() {
+bool AudioPlayer::reachedEOS(status_t *finalStatus) {
+ *finalStatus = OK;
+
Mutex::Autolock autoLock(mLock);
+ *finalStatus = mFinalStatus;
return mReachedEOS;
}
@@ -245,6 +250,7 @@ size_t AudioPlayer::fillBuffer(void *data, size_t size) {
if (err != OK) {
mReachedEOS = true;
+ mFinalStatus = err;
break;
}
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index b3a73b0..ab65b44 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -434,14 +434,22 @@ void AwesomePlayer::onStreamDone() {
}
mStreamDoneEventPending = false;
- if (mFlags & LOOPING) {
+ if (mStreamDoneStatus == ERROR_END_OF_STREAM && (mFlags & LOOPING)) {
seekTo_l(0);
if (mVideoSource != NULL) {
postVideoEvent_l();
}
} else {
- notifyListener_l(MEDIA_PLAYBACK_COMPLETE);
+ if (mStreamDoneStatus == ERROR_END_OF_STREAM) {
+ LOGV("MEDIA_PLAYBACK_COMPLETE");
+ notifyListener_l(MEDIA_PLAYBACK_COMPLETE);
+ } else {
+ LOGV("MEDIA_ERROR %d", mStreamDoneStatus);
+
+ notifyListener_l(
+ MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, mStreamDoneStatus);
+ }
pause_l();
@@ -802,7 +810,7 @@ void AwesomePlayer::onVideoEvent() {
continue;
}
- postStreamDoneEvent_l();
+ postStreamDoneEvent_l(err);
return;
}
@@ -904,11 +912,13 @@ void AwesomePlayer::postVideoEvent_l(int64_t delayUs) {
mQueue.postEventWithDelay(mVideoEvent, delayUs < 0 ? 10000 : delayUs);
}
-void AwesomePlayer::postStreamDoneEvent_l() {
+void AwesomePlayer::postStreamDoneEvent_l(status_t status) {
if (mStreamDoneEventPending) {
return;
}
mStreamDoneEventPending = true;
+
+ mStreamDoneStatus = status;
mQueue.postEvent(mStreamDoneEvent);
}
@@ -947,9 +957,10 @@ void AwesomePlayer::onCheckAudioStatus() {
notifyListener_l(MEDIA_SEEK_COMPLETE);
}
- if (mWatchForAudioEOS && mAudioPlayer->reachedEOS()) {
+ status_t finalStatus;
+ if (mWatchForAudioEOS && mAudioPlayer->reachedEOS(&finalStatus)) {
mWatchForAudioEOS = false;
- postStreamDoneEvent_l();
+ postStreamDoneEvent_l(finalStatus);
}
postCheckAudioStatusEvent_l();
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
index 16635d3..165ac09 100644
--- a/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/MPEG4Extractor.cpp
@@ -463,7 +463,10 @@ status_t MPEG4Extractor::parseChunk(off_t *offset, int depth) {
return err;
}
}
- CHECK_EQ(*offset, stop_offset);
+
+ if (*offset != stop_offset) {
+ return ERROR_MALFORMED;
+ }
return OK;
}
@@ -496,6 +499,23 @@ status_t MPEG4Extractor::parseChunk(off_t *offset, int depth) {
}
}
+ if (chunk_type == FOURCC('t', 'r', 'a', 'k')) {
+ Track *track = new Track;
+ track->next = NULL;
+ if (mLastTrack) {
+ mLastTrack->next = track;
+ } else {
+ mFirstTrack = track;
+ }
+ mLastTrack = track;
+
+ track->meta = new MetaData;
+ track->includes_expensive_metadata = false;
+ track->timescale = 0;
+ track->sampleTable = new SampleTable(mDataSource);
+ track->meta->setCString(kKeyMIMEType, "application/octet-stream");
+ }
+
off_t stop_offset = *offset + chunk_size;
*offset = data_offset;
while (*offset < stop_offset) {
@@ -504,9 +524,18 @@ status_t MPEG4Extractor::parseChunk(off_t *offset, int depth) {
return err;
}
}
- CHECK_EQ(*offset, stop_offset);
- if (chunk_type == FOURCC('m', 'o', 'o', 'v')) {
+ if (*offset != stop_offset) {
+ return ERROR_MALFORMED;
+ }
+
+ if (chunk_type == FOURCC('t', 'r', 'a', 'k')) {
+ status_t err = verifyTrack(mLastTrack);
+
+ if (err != OK) {
+ return err;
+ }
+ } else if (chunk_type == FOURCC('m', 'o', 'o', 'v')) {
mHaveMetadata = true;
return UNKNOWN_ERROR; // Return a dummy error.
@@ -516,7 +545,9 @@ status_t MPEG4Extractor::parseChunk(off_t *offset, int depth) {
case FOURCC('t', 'k', 'h', 'd'):
{
- CHECK(chunk_data_size >= 4);
+ if (chunk_data_size < 4) {
+ return ERROR_MALFORMED;
+ }
uint8_t version;
if (mDataSource->readAt(data_offset, &version, 1) < 1) {
@@ -562,21 +593,6 @@ status_t MPEG4Extractor::parseChunk(off_t *offset, int depth) {
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->includes_expensive_metadata = false;
- track->timescale = 0;
- track->sampleTable = new SampleTable(mDataSource);
- track->meta->setCString(kKeyMIMEType, "application/octet-stream");
-
*offset += chunk_size;
break;
}
@@ -670,7 +686,10 @@ status_t MPEG4Extractor::parseChunk(off_t *offset, int depth) {
}
uint8_t buffer[8];
- CHECK(chunk_data_size >= (off_t)sizeof(buffer));
+ if (chunk_data_size < (off_t)sizeof(buffer)) {
+ return ERROR_MALFORMED;
+ }
+
if (mDataSource->readAt(
data_offset, buffer, 8) < 8) {
return ERROR_IO;
@@ -696,7 +715,10 @@ status_t MPEG4Extractor::parseChunk(off_t *offset, int depth) {
return err;
}
}
- CHECK_EQ(*offset, stop_offset);
+
+ if (*offset != stop_offset) {
+ return ERROR_MALFORMED;
+ }
break;
}
@@ -748,7 +770,10 @@ status_t MPEG4Extractor::parseChunk(off_t *offset, int depth) {
return err;
}
}
- CHECK_EQ(*offset, stop_offset);
+
+ if (*offset != stop_offset) {
+ return ERROR_MALFORMED;
+ }
break;
}
@@ -792,7 +817,10 @@ status_t MPEG4Extractor::parseChunk(off_t *offset, int depth) {
return err;
}
}
- CHECK_EQ(*offset, stop_offset);
+
+ if (*offset != stop_offset) {
+ return ERROR_MALFORMED;
+ }
break;
}
@@ -942,7 +970,10 @@ status_t MPEG4Extractor::parseChunk(off_t *offset, int depth) {
case FOURCC('m', 'e', 't', 'a'):
{
uint8_t buffer[4];
- CHECK(chunk_data_size >= (off_t)sizeof(buffer));
+ if (chunk_data_size < (off_t)sizeof(buffer)) {
+ return ERROR_MALFORMED;
+ }
+
if (mDataSource->readAt(
data_offset, buffer, 4) < 4) {
return ERROR_IO;
@@ -961,7 +992,10 @@ status_t MPEG4Extractor::parseChunk(off_t *offset, int depth) {
return err;
}
}
- CHECK_EQ(*offset, stop_offset);
+
+ if (*offset != stop_offset) {
+ return ERROR_MALFORMED;
+ }
break;
}
@@ -995,8 +1029,9 @@ status_t MPEG4Extractor::parseChunk(off_t *offset, int depth) {
int64_t creationTime;
if (header[0] == 1) {
creationTime = U64_AT(&header[4]);
+ } else if (header[0] != 0) {
+ return ERROR_MALFORMED;
} else {
- CHECK_EQ(header[0], 0);
creationTime = U32_AT(&header[4]);
}
@@ -1174,6 +1209,30 @@ sp<MediaSource> MPEG4Extractor::getTrack(size_t index) {
track->meta, mDataSource, track->timescale, track->sampleTable);
}
+// static
+status_t MPEG4Extractor::verifyTrack(Track *track) {
+ const char *mime;
+ CHECK(track->meta->findCString(kKeyMIMEType, &mime));
+
+ uint32_t type;
+ const void *data;
+ size_t size;
+ if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)) {
+ if (!track->meta->findData(kKeyAVCC, &type, &data, &size)
+ || type != kTypeAVCC) {
+ return ERROR_MALFORMED;
+ }
+ } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4)
+ || !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)) {
+ if (!track->meta->findData(kKeyESDS, &type, &data, &size)
+ || type != kTypeESDS) {
+ return ERROR_MALFORMED;
+ }
+ }
+
+ return OK;
+}
+
status_t MPEG4Extractor::updateAudioTrackInfoFromESDS_MPEG4Audio(
const void *esds_data, size_t esds_size) {
ESDS esds(esds_data, esds_size);
@@ -1391,6 +1450,14 @@ status_t MPEG4Source::read(
&sampleIndex, SampleTable::kSyncSample_Flag);
if (err != OK) {
+ if (err == ERROR_OUT_OF_RANGE) {
+ // An attempt to seek past the end of the stream would
+ // normally cause this ERROR_OUT_OF_RANGE error. Propagating
+ // this all the way to the MediaPlayer would cause abnormal
+ // termination. Legacy behaviour appears to be to behave as if
+ // we had seeked to the end of stream, ending normally.
+ err = ERROR_END_OF_STREAM;
+ }
return err;
}
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index 6cf7cff..974413d 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -298,6 +298,10 @@ uint32_t OMXCodec::getComponentQuirks(const char *componentName) {
quirks |= kRequiresAllocateBufferOnOutputPorts;
}
+ if (!strcmp(componentName, "OMX.TI.Video.Decoder")) {
+ quirks |= kInputBufferSizesAreBogus;
+ }
+
return quirks;
}
@@ -561,7 +565,8 @@ void OMXCodec::setMinBufferSize(OMX_U32 portIndex, OMX_U32 size) {
mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
CHECK_EQ(err, OK);
- if (def.nBufferSize < size) {
+ if ((portIndex == kPortIndexInput && (mQuirks & kInputBufferSizesAreBogus))
+ || (def.nBufferSize < size)) {
def.nBufferSize = size;
}
@@ -574,7 +579,12 @@ void OMXCodec::setMinBufferSize(OMX_U32 portIndex, OMX_U32 size) {
CHECK_EQ(err, OK);
// Make sure the setting actually stuck.
- CHECK(def.nBufferSize >= size);
+ if (portIndex == kPortIndexInput
+ && (mQuirks & kInputBufferSizesAreBogus)) {
+ CHECK_EQ(def.nBufferSize, size);
+ } else {
+ CHECK(def.nBufferSize >= size);
+ }
}
status_t OMXCodec::setVideoPortFormatType(
@@ -1923,6 +1933,7 @@ void OMXCodec::drainInputBuffer(BufferInfo *info) {
CODEC_LOGV("signalling end of input stream.");
flags |= OMX_BUFFERFLAG_EOS;
+ mFinalStatus = err;
mSignalledEOS = true;
} else {
mNoMoreOutputData = false;
@@ -2401,7 +2412,7 @@ status_t OMXCodec::read(
}
if (mFilledBuffers.empty()) {
- return ERROR_END_OF_STREAM;
+ return mSignalledEOS ? mFinalStatus : ERROR_END_OF_STREAM;
}
if (mOutputPortSettingsHaveChanged) {
diff --git a/media/libstagefright/Prefetcher.cpp b/media/libstagefright/Prefetcher.cpp
index 363e121..9c73f4a 100644
--- a/media/libstagefright/Prefetcher.cpp
+++ b/media/libstagefright/Prefetcher.cpp
@@ -55,6 +55,7 @@ private:
size_t mIndex;
bool mStarted;
bool mReachedEOS;
+ status_t mFinalStatus;
int64_t mSeekTimeUs;
int64_t mCacheDurationUs;
bool mPrefetcherStopped;
@@ -306,7 +307,7 @@ status_t PrefetchedSource::read(
}
if (mCachedBuffers.empty()) {
- return ERROR_END_OF_STREAM;
+ return mReachedEOS ? mFinalStatus : ERROR_END_OF_STREAM;
}
*out = *mCachedBuffers.begin();
@@ -353,6 +354,7 @@ void PrefetchedSource::cacheMore() {
if (err != OK) {
mReachedEOS = true;
+ mFinalStatus = err;
mCondition.signal();
return;
diff --git a/media/libstagefright/codecs/mp3dec/MP3Decoder.cpp b/media/libstagefright/codecs/mp3dec/MP3Decoder.cpp
index f1f7194..6d6e408 100644
--- a/media/libstagefright/codecs/mp3dec/MP3Decoder.cpp
+++ b/media/libstagefright/codecs/mp3dec/MP3Decoder.cpp
@@ -160,14 +160,25 @@ status_t MP3Decoder::read(
mConfig->outputFrameSize = buffer->size() / sizeof(int16_t);
mConfig->pOutputBuffer = static_cast<int16_t *>(buffer->data());
- if (pvmp3_framedecoder(mConfig, mDecoderBuf) != NO_DECODING_ERROR) {
- buffer->release();
- buffer = NULL;
+ ERROR_CODE decoderErr;
+ if ((decoderErr = pvmp3_framedecoder(mConfig, mDecoderBuf))
+ != NO_DECODING_ERROR) {
+ LOGV("mp3 decoder returned error %d", decoderErr);
- mInputBuffer->release();
- mInputBuffer = NULL;
+ if (decoderErr != NO_ENOUGH_MAIN_DATA_ERROR) {
+ buffer->release();
+ buffer = NULL;
+
+ mInputBuffer->release();
+ mInputBuffer = NULL;
+
+ return UNKNOWN_ERROR;
+ }
- return UNKNOWN_ERROR;
+ // This is recoverable, just ignore the current frame and
+ // play silence instead.
+ memset(buffer->data(), 0, mConfig->outputFrameSize);
+ mConfig->inputBufferUsedLength = mInputBuffer->range_length();
}
buffer->set_range(
diff --git a/media/libstagefright/include/AwesomePlayer.h b/media/libstagefright/include/AwesomePlayer.h
index ce8eeae..3590987 100644
--- a/media/libstagefright/include/AwesomePlayer.h
+++ b/media/libstagefright/include/AwesomePlayer.h
@@ -145,10 +145,11 @@ private:
Condition mPreparedCondition;
bool mIsAsyncPrepare;
status_t mPrepareResult;
+ status_t mStreamDoneStatus;
void postVideoEvent_l(int64_t delayUs = -1);
void postBufferingEvent_l();
- void postStreamDoneEvent_l();
+ void postStreamDoneEvent_l(status_t status);
void postCheckAudioStatusEvent_l();
status_t getPosition_l(int64_t *positionUs);
status_t play_l();
diff --git a/media/libstagefright/include/MPEG4Extractor.h b/media/libstagefright/include/MPEG4Extractor.h
index 3a63e88..9d35e0c 100644
--- a/media/libstagefright/include/MPEG4Extractor.h
+++ b/media/libstagefright/include/MPEG4Extractor.h
@@ -68,6 +68,8 @@ private:
status_t updateAudioTrackInfoFromESDS_MPEG4Audio(
const void *esds_data, size_t esds_size);
+ static status_t verifyTrack(Track *track);
+
MPEG4Extractor(const MPEG4Extractor &);
MPEG4Extractor &operator=(const MPEG4Extractor &);
};
diff --git a/media/libstagefright/omx/OMX.cpp b/media/libstagefright/omx/OMX.cpp
index 9ca060d..ff8757d 100644
--- a/media/libstagefright/omx/OMX.cpp
+++ b/media/libstagefright/omx/OMX.cpp
@@ -401,6 +401,33 @@ void OMX::invalidateNodeID_l(node_id node) {
////////////////////////////////////////////////////////////////////////////////
+struct SharedVideoRenderer : public VideoRenderer {
+ SharedVideoRenderer(void *libHandle, VideoRenderer *obj)
+ : mLibHandle(libHandle),
+ mObj(obj) {
+ }
+
+ virtual ~SharedVideoRenderer() {
+ delete mObj;
+ mObj = NULL;
+
+ dlclose(mLibHandle);
+ mLibHandle = NULL;
+ }
+
+ virtual void render(
+ const void *data, size_t size, void *platformPrivate) {
+ return mObj->render(data, size, platformPrivate);
+ }
+
+private:
+ void *mLibHandle;
+ VideoRenderer *mObj;
+
+ SharedVideoRenderer(const SharedVideoRenderer &);
+ SharedVideoRenderer &operator=(const SharedVideoRenderer &);
+};
+
sp<IOMXRenderer> OMX::createRenderer(
const sp<ISurface> &surface,
const char *componentName,
@@ -411,11 +438,7 @@ sp<IOMXRenderer> OMX::createRenderer(
VideoRenderer *impl = NULL;
- static void *libHandle = NULL;
-
- if (!libHandle) {
- libHandle = dlopen("libstagefrighthw.so", RTLD_NOW);
- }
+ void *libHandle = dlopen("libstagefrighthw.so", RTLD_NOW);
if (libHandle) {
typedef VideoRenderer *(*CreateRendererFunc)(
@@ -434,6 +457,16 @@ sp<IOMXRenderer> OMX::createRenderer(
if (func) {
impl = (*func)(surface, componentName, colorFormat,
displayWidth, displayHeight, encodedWidth, encodedHeight);
+
+ if (impl) {
+ impl = new SharedVideoRenderer(libHandle, impl);
+ libHandle = NULL;
+ }
+ }
+
+ if (libHandle) {
+ dlclose(libHandle);
+ libHandle = NULL;
}
}
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaProfileReader.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaProfileReader.java
index 717f7ba..d7cf069 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaProfileReader.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaProfileReader.java
@@ -1,28 +1,35 @@
package com.android.mediaframeworktest;
import android.media.MediaRecorder;
+import android.media.EncoderCapabilities;
+import android.media.EncoderCapabilities.VideoEncoderCap;
+import android.media.EncoderCapabilities.AudioEncoderCap;
+import android.media.DecoderCapabilities;
+import android.media.DecoderCapabilities.VideoDecoder;
+import android.media.DecoderCapabilities.AudioDecoder;
+
import android.os.SystemProperties;
+import java.util.List;
import java.util.HashMap;
-public class MediaProfileReader {
+public class MediaProfileReader
+{
+ private static final List<VideoDecoder> videoDecoders = DecoderCapabilities.getVideoDecoders();
+ private static final List<AudioDecoder> audioDecoders = DecoderCapabilities.getAudioDecoders();
+ private static final List<VideoEncoderCap> videoEncoders = EncoderCapabilities.getVideoEncoders();
+ private static final List<AudioEncoderCap> audioEncoders = EncoderCapabilities.getAudioEncoders();
+ private static final HashMap<Integer, String> encoderMap = new HashMap<Integer, String>();
- public static final HashMap<String, Integer>
- OUTPUT_FORMAT_TABLE = new HashMap<String, Integer>();
- public static String MEDIA_ENC_VID = "ro.media.enc.vid.";
- public static String MEDIA_AUD_VID = "ro.media.enc.aud.";
- public static String[] VIDEO_ENCODER_PROPERTY = {".width", ".height", ".bps", ".fps",};
- public static String[] AUDIO_ENCODER_PROPERTY = {".bps", ".hz", ".ch",};
+ static {
+ initEncoderMap();
+ };
- public static String getVideoCodecProperty() {
- String s;
- s = SystemProperties.get("ro.media.enc.vid.codec");
- return s;
+ public static List<VideoEncoderCap> getVideoEncoders() {
+ return videoEncoders;
}
- public static String getAudioCodecProperty() {
- String s;
- s = SystemProperties.get("ro.media.enc.aud.codec");
- return s;
+ public static List<AudioEncoderCap> getAudioEncoders() {
+ return audioEncoders;
}
public static String getDeviceType() {
@@ -33,78 +40,56 @@ public class MediaProfileReader {
}
public static boolean getWMAEnable() {
- // push all the property into one big table
- int wmaEnable = 1;
- wmaEnable = SystemProperties.getInt("ro.media.dec.aud.wma.enabled",
- wmaEnable);
- if (wmaEnable == 1) {
- return true;
- } else {
- return false;
+ for (AudioDecoder decoder: audioDecoders) {
+ if (decoder == AudioDecoder.AUDIO_DECODER_WMA) {
+ return true;
+ }
}
+ return false;
}
public static boolean getWMVEnable(){
- int wmvEnable = 1;
- wmvEnable = SystemProperties.getInt("ro.media.dec.vid.wmv.enabled",
- wmvEnable);
- if (wmvEnable == 1) {
- return true;
- } else {
- return false;
+ for (VideoDecoder decoder: videoDecoders) {
+ if (decoder == VideoDecoder.VIDEO_DECODER_WMV) {
+ return true;
+ }
}
+ return false;
}
- public static void createVideoProfileTable() {
- // push all the property into one big table
- String encoderType = getVideoCodecProperty();
- if (encoderType.length() != 0) {
- String encoder[] = encoderType.split(",");
- for (int i = 0; i < encoder.length; i++) {
- for (int j = 0; j < VIDEO_ENCODER_PROPERTY.length; j++) {
- String propertyName = MEDIA_ENC_VID + encoder[i] + VIDEO_ENCODER_PROPERTY[j];
- String prop = SystemProperties.get(propertyName);
- // push to the table
- String propRange[] = prop.split(",");
- OUTPUT_FORMAT_TABLE.put((encoder[i] + VIDEO_ENCODER_PROPERTY[j] + "_low"),
- Integer.parseInt(propRange[0]));
- OUTPUT_FORMAT_TABLE.put((encoder[i] + VIDEO_ENCODER_PROPERTY[j] + "_high"),
- Integer.parseInt(propRange[1]));
- }
-
- }
+ public static String getVideoCodecName(int videoEncoder) {
+ if (videoEncoder != MediaRecorder.VideoEncoder.H263 &&
+ videoEncoder != MediaRecorder.VideoEncoder.H264 &&
+ videoEncoder != MediaRecorder.VideoEncoder.MPEG_4_SP) {
+ throw new IllegalArgumentException("Unsupported video encoder " + videoEncoder);
}
+ return encoderMap.get(videoEncoder);
}
- public static void createAudioProfileTable() {
- // push all the property into one big table
- String audioType = getAudioCodecProperty();
- String encoder[] = audioType.split(",");
- if (audioType.length() != 0) {
- for (int i = 0; i < encoder.length; i++) {
- for (int j = 0; j < AUDIO_ENCODER_PROPERTY.length; j++) {
- String propertyName = MEDIA_AUD_VID + encoder[i] + AUDIO_ENCODER_PROPERTY[j];
- String prop = SystemProperties.get(propertyName);
- // push to the table
- String propRange[] = prop.split(",");
- OUTPUT_FORMAT_TABLE.put((encoder[i] + AUDIO_ENCODER_PROPERTY[j] + "_low"),
- Integer.parseInt(propRange[0]));
- OUTPUT_FORMAT_TABLE.put((encoder[i] + AUDIO_ENCODER_PROPERTY[j] + "_high"),
- Integer.parseInt(propRange[1]));
- }
- }
+ public static String getAudioCodecName(int audioEncoder) {
+ if (audioEncoder != MediaRecorder.AudioEncoder.AMR_NB &&
+ audioEncoder != MediaRecorder.AudioEncoder.AMR_WB &&
+ audioEncoder != MediaRecorder.AudioEncoder.AAC &&
+ audioEncoder != MediaRecorder.AudioEncoder.AAC_PLUS &&
+ audioEncoder != MediaRecorder.AudioEncoder.EAAC_PLUS) {
+ throw new IllegalArgumentException("Unsupported audio encodeer " + audioEncoder);
}
+ return encoderMap.get(audioEncoder);
}
- public static void createEncoderTable(){
- OUTPUT_FORMAT_TABLE.put("h263", MediaRecorder.VideoEncoder.H263);
- OUTPUT_FORMAT_TABLE.put("h264", MediaRecorder.VideoEncoder.H264);
- OUTPUT_FORMAT_TABLE.put("m4v", MediaRecorder.VideoEncoder.MPEG_4_SP);
- OUTPUT_FORMAT_TABLE.put("amrnb", MediaRecorder.AudioEncoder.AMR_NB);
- OUTPUT_FORMAT_TABLE.put("amrwb", MediaRecorder.AudioEncoder.AMR_WB);
- OUTPUT_FORMAT_TABLE.put("aac", MediaRecorder.AudioEncoder.AAC);
- OUTPUT_FORMAT_TABLE.put("aacplus", MediaRecorder.AudioEncoder.AAC_PLUS);
- OUTPUT_FORMAT_TABLE.put("eaacplus",
- MediaRecorder.AudioEncoder.EAAC_PLUS);
+ private MediaProfileReader() {} // Don't call me
+
+ private static void initEncoderMap() {
+ // video encoders
+ encoderMap.put(MediaRecorder.VideoEncoder.H263, "h263");
+ encoderMap.put(MediaRecorder.VideoEncoder.H264, "h264");
+ encoderMap.put(MediaRecorder.VideoEncoder.MPEG_4_SP, "m4v");
+
+ // audio encoders
+ encoderMap.put(MediaRecorder.AudioEncoder.AMR_NB, "amrnb");
+ encoderMap.put(MediaRecorder.AudioEncoder.AMR_WB, "amrwb");
+ encoderMap.put(MediaRecorder.AudioEncoder.AAC, "aac");
+ encoderMap.put(MediaRecorder.AudioEncoder.AAC_PLUS, "aacplus");
+ encoderMap.put(MediaRecorder.AudioEncoder.EAAC_PLUS, "eaacplus");
}
}
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaRecorderTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaRecorderTest.java
index fdc5970..39caccd 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaRecorderTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaRecorderTest.java
@@ -25,6 +25,9 @@ import android.content.Context;
import android.hardware.Camera;
import android.media.MediaPlayer;
import android.media.MediaRecorder;
+import android.media.EncoderCapabilities;
+import android.media.EncoderCapabilities.VideoEncoderCap;
+import android.media.EncoderCapabilities.AudioEncoderCap;
import android.test.ActivityInstrumentationTestCase;
import android.util.Log;
import android.view.SurfaceHolder;
@@ -33,6 +36,7 @@ import com.android.mediaframeworktest.MediaProfileReader;
import android.test.suitebuilder.annotation.LargeTest;
import android.test.suitebuilder.annotation.Suppress;
+import java.util.List;
/**
@@ -99,31 +103,29 @@ public class MediaRecorderTest extends ActivityInstrumentationTestCase<MediaFram
}
}
- private boolean recordVideoWithPara(String encoder, String audio, String quality){
+ private boolean recordVideoWithPara(VideoEncoderCap videoCap, AudioEncoderCap audioCap, boolean highQuality){
boolean recordSuccess = false;
- int videoEncoder = MediaProfileReader.OUTPUT_FORMAT_TABLE.get(encoder);
- int audioEncoder = MediaProfileReader.OUTPUT_FORMAT_TABLE.get(audio);
- int videoWidth = MediaProfileReader.OUTPUT_FORMAT_TABLE.get(encoder + ".width_" + quality);
- int videoHeight =
- MediaProfileReader.OUTPUT_FORMAT_TABLE.get(encoder + ".height_" + quality);
- int videoFps = MediaProfileReader.OUTPUT_FORMAT_TABLE.get(encoder + ".fps_" + quality);
- int videoBitrate = MediaProfileReader.OUTPUT_FORMAT_TABLE.get(encoder + ".bps_" + quality);
- int audioBitrate = MediaProfileReader.OUTPUT_FORMAT_TABLE.get(audio + ".bps_" + quality);
- int audioChannels = MediaProfileReader.OUTPUT_FORMAT_TABLE.get(audio + ".ch_" + quality);
- int audioSamplingRate =
- MediaProfileReader.OUTPUT_FORMAT_TABLE.get(audio + ".hz_" + quality);
+ int videoEncoder = videoCap.mCodec;
+ int audioEncoder = audioCap.mCodec;
+ int videoWidth = highQuality? videoCap.mMaxFrameWidth: videoCap.mMinFrameWidth;
+ int videoHeight = highQuality? videoCap.mMaxFrameHeight: videoCap.mMinFrameHeight;
+ int videoFps = highQuality? videoCap.mMaxFrameRate: videoCap.mMinFrameRate;
+ int videoBitrate = highQuality? videoCap.mMaxBitRate: videoCap.mMinBitRate;
+ int audioBitrate = highQuality? audioCap.mMaxBitRate: audioCap.mMinBitRate;
+ int audioChannels = highQuality? audioCap.mMaxChannels: audioCap.mMinChannels ;
+ int audioSamplingRate = highQuality? audioCap.mMaxSampleRate: audioCap.mMinSampleRate;
if (videoFps < MIN_VIDEO_FPS) {
videoFps = MIN_VIDEO_FPS;
}
mSurfaceHolder = MediaFrameworkTest.mSurfaceView.getHolder();
- String filename = ("/sdcard/" + encoder + "_" + audio + "_" + quality + ".3gp");
+ String filename = ("/sdcard/" + videoEncoder + "_" + audioEncoder + "_" + highQuality + ".3gp");
try {
Log.v(TAG, "video encoder :" + videoEncoder);
Log.v(TAG, "audio encoder :" + audioEncoder);
- Log.v(TAG, "quality : " + quality);
- Log.v(TAG, "encoder : " + encoder);
- Log.v(TAG, "audio : " + audio);
+ Log.v(TAG, "quality : " + (highQuality?"high": "low"));
+ Log.v(TAG, "encoder : " + MediaProfileReader.getVideoCodecName(videoEncoder));
+ Log.v(TAG, "audio : " + MediaProfileReader.getAudioCodecName(audioEncoder));
Log.v(TAG, "videoWidth : " + videoWidth);
Log.v(TAG, "videoHeight : " + videoHeight);
Log.v(TAG, "videoFPS : " + videoFps);
@@ -434,35 +436,26 @@ public class MediaRecorderTest extends ActivityInstrumentationTestCase<MediaFram
boolean recordSuccess = false;
String deviceType = MediaProfileReader.getDeviceType();
Log.v(TAG, "deviceType = " + deviceType);
- // Test cases are device specified
- MediaProfileReader.createVideoProfileTable();
- MediaProfileReader.createAudioProfileTable();
- MediaProfileReader.createEncoderTable();
- String encoderType = MediaProfileReader.getVideoCodecProperty();
- String audioType = MediaProfileReader.getAudioCodecProperty();
- if ((encoderType.length() != 0) || (audioType.length() != 0)) {
- String audio[] = audioType.split(",");
- String encoder[] = encoderType.split(",");
- for (int k = 0; k < 2; k++) {
- for (int i = 0; i < encoder.length; i++) {
- for (int j = 0; j < audio.length; j++) {
- if (k == 0) {
- recordSuccess = recordVideoWithPara(encoder[i], audio[j], "high");
- } else {
- recordSuccess = recordVideoWithPara(encoder[i], audio[j], "low");
- }
- if (!recordSuccess) {
- Log.v(TAG, "testDeviceSpecificCodec failed");
- Log.v(TAG, "Encoder = " + encoder[i] + "Audio Encoder = " + audio[j]);
- noOfFailure++;
- }
- // assertTrue((encoder[i] + audio[j]), recordSuccess);
+ List<VideoEncoderCap> videoEncoders = MediaProfileReader.getVideoEncoders();
+ List<AudioEncoderCap> audioEncoders = MediaProfileReader.getAudioEncoders();
+ for (int k = 0; k < 2; k++) {
+ for (VideoEncoderCap videoEncoder: videoEncoders) {
+ for (AudioEncoderCap audioEncoder: audioEncoders) {
+ if (k == 0) {
+ recordSuccess = recordVideoWithPara(videoEncoder, audioEncoder, true);
+ } else {
+ recordSuccess = recordVideoWithPara(videoEncoder, audioEncoder, false);
+ }
+ if (!recordSuccess) {
+ Log.v(TAG, "testDeviceSpecificCodec failed");
+ Log.v(TAG, "Encoder = " + videoEncoder.mCodec + "Audio Encoder = " + audioEncoder.mCodec);
+ noOfFailure++;
}
}
}
- if (noOfFailure != 0) {
- assertTrue("testDeviceSpecificCodec", false);
- }
+ }
+ if (noOfFailure != 0) {
+ assertTrue("testDeviceSpecificCodec", false);
}
}
}
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaMetadataRetrieverTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaMetadataRetrieverTest.java
index 8750098..4c259f1 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaMetadataRetrieverTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaMetadataRetrieverTest.java
@@ -39,9 +39,8 @@ public class MediaMetadataRetrieverTest extends AndroidTestCase {
public static void testAlbumArt() throws Exception {
Log.v(TAG, "testAlbumArt starts.");
MediaMetadataRetriever retriever = new MediaMetadataRetriever();
- MediaProfileReader reader = new MediaProfileReader();
- boolean supportWMA = reader.getWMAEnable();
- boolean supportWMV = reader.getWMVEnable();
+ boolean supportWMA = MediaProfileReader.getWMAEnable();
+ boolean supportWMV = MediaProfileReader.getWMVEnable();
retriever.setMode(MediaMetadataRetriever.MODE_GET_METADATA_ONLY);
for (int i = 0, n = MediaNames.ALBUMART_TEST_FILES.length; i < n; ++i) {
try {
@@ -74,9 +73,8 @@ public class MediaMetadataRetrieverTest extends AndroidTestCase {
@LargeTest
public static void testThumbnailCapture() throws Exception {
MediaMetadataRetriever retriever = new MediaMetadataRetriever();
- MediaProfileReader reader = new MediaProfileReader();
- boolean supportWMA = reader.getWMAEnable();
- boolean supportWMV = reader.getWMVEnable();
+ boolean supportWMA = MediaProfileReader.getWMAEnable();
+ boolean supportWMV = MediaProfileReader.getWMVEnable();
Log.v(TAG, "Thumbnail processing starts");
long startedAt = System.currentTimeMillis();
for(int i = 0, n = MediaNames.THUMBNAIL_CAPTURE_TEST_FILES.length; i < n; ++i) {
@@ -110,9 +108,8 @@ public class MediaMetadataRetrieverTest extends AndroidTestCase {
@LargeTest
public static void testMetadataRetrieval() throws Exception {
- MediaProfileReader reader = new MediaProfileReader();
- boolean supportWMA = reader.getWMAEnable();
- boolean supportWMV = reader.getWMVEnable();
+ boolean supportWMA = MediaProfileReader.getWMAEnable();
+ boolean supportWMV = MediaProfileReader.getWMVEnable();
MediaMetadataRetriever retriever = new MediaMetadataRetriever();
retriever.setMode(MediaMetadataRetriever.MODE_GET_METADATA_ONLY);
for(int i = 0, n = MediaNames.METADATA_RETRIEVAL_TEST_FILES.length; i < n; ++i) {
diff --git a/mms-common/Android.mk b/mms-common/Android.mk
index de994c0..57f1ccc 100644
--- a/mms-common/Android.mk
+++ b/mms-common/Android.mk
@@ -20,6 +20,7 @@ LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := mms-common
LOCAL_SRC_FILES := $(call all-java-files-under, java)
+LOCAL_STATIC_JAVA_LIBRARIES += android-common
include $(BUILD_STATIC_JAVA_LIBRARY)
# Include this library in the build server's output directory
diff --git a/mms-common/java/com/android/mmscommon/telephony/TelephonyProvider.java b/mms-common/java/com/android/mmscommon/telephony/TelephonyProvider.java
index 0237bc2..87e4758 100644
--- a/mms-common/java/com/android/mmscommon/telephony/TelephonyProvider.java
+++ b/mms-common/java/com/android/mmscommon/telephony/TelephonyProvider.java
@@ -32,8 +32,8 @@ import android.telephony.SmsMessage;
import android.text.TextUtils;
import android.util.Config;
import android.util.Log;
+import android.util.Patterns;
-import com.android.common.Patterns;
import android.database.sqlite.SqliteWrapper;
/**
diff --git a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
index 95ab684..a79f0cd 100644
--- a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
+++ b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
@@ -39,7 +39,7 @@ import android.provider.Settings;
*/
public class DefaultContainerService extends IntentService {
private static final String TAG = "DefContainer";
- private static final boolean localLOGV = false;
+ private static final boolean localLOGV = true;
private IMediaContainerService.Stub mBinder = new IMediaContainerService.Stub() {
/*
@@ -211,6 +211,8 @@ public class DefaultContainerService extends IntentService {
if (PackageHelper.isContainerMounted(newCid)) {
if (localLOGV) Log.i(TAG, "Unmounting " + newCid +
" at path " + newCachePath + " after " + errMsg);
+ // Force a gc to avoid being killed.
+ Runtime.getRuntime().gc();
PackageHelper.unMountSdDir(newCid);
} else {
if (localLOGV) Log.i(TAG, "Container " + newCid + " not mounted");
@@ -328,8 +330,8 @@ public class DefaultContainerService extends IntentService {
boolean auto = true;
// To make final copy
long reqInstallSize = pkgLen;
- // For dex files
- long reqInternalSize = 1 * pkgLen;
+ // For dex files. Just ignore and fail when extracting. Max limit of 2Gig for now.
+ long reqInternalSize = 0;
boolean intThresholdOk = (pctNandFree >= LOW_NAND_FLASH_TRESHOLD);
boolean intAvailOk = ((reqInstallSize + reqInternalSize) < availInternalFlashSize);
boolean fitsOnSd = (reqInstallSize < availSDSize) && intThresholdOk &&
diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml
index 654ca32..1e9c312 100644
--- a/packages/SettingsProvider/res/values/defaults.xml
+++ b/packages/SettingsProvider/res/values/defaults.xml
@@ -60,14 +60,14 @@
<!-- user interface sound effects -->
<integer name="def_power_sounds_enabled">1</integer>
- <string name="def_low_battery_sound">/system/media/ui/LowBattery.ogg</string>
- <integer name="def_dock_sounds_enabled">1</integer>
- <string name="def_desk_dock_sound">/system/media/audio/ui/dock.ogg</string>
- <string name="def_desk_undock_sound">/system/media/audio/ui/undock.ogg</string>
- <string name="def_car_dock_sound">/system/media/audio/ui/Dock.ogg</string>
- <string name="def_car_undock_sound">/system/media/audio/ui/Undock.ogg</string>
- <integer name="def_lockscreen_sounds_enabled">1</integer>
- <string name="def_lock_sound">/system/media/audio/ui/Lock.ogg</string>
- <string name="def_unlock_sound">/system/media/audio/ui/Unlock.ogg</string>
+ <string name="def_low_battery_sound" translatable="false">/system/media/ui/LowBattery.ogg</string>
+ <integer name="def_dock_sounds_enabled">0</integer>
+ <string name="def_desk_dock_sound" translatable="false">/system/media/audio/ui/Dock.ogg</string>
+ <string name="def_desk_undock_sound" translatable="false">/system/media/audio/ui/Undock.ogg</string>
+ <string name="def_car_dock_sound" translatable="false">/system/media/audio/ui/Dock.ogg</string>
+ <string name="def_car_undock_sound" translatable="false">/system/media/audio/ui/Undock.ogg</string>
+ <integer name="def_lockscreen_sounds_enabled">0</integer>
+ <string name="def_lock_sound" translatable="false">/system/media/audio/ui/Lock.ogg</string>
+ <string name="def_unlock_sound" translatable="false">/system/media/audio/ui/Unlock.ogg</string>
</resources>
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index cf34d4e..18e247e 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -44,8 +44,8 @@ import android.text.TextUtils;
import android.util.Config;
import android.util.Log;
import android.util.Xml;
-import com.android.common.XmlUtils;
import com.android.internal.telephony.RILConstants;
+import com.android.internal.util.XmlUtils;
import com.android.internal.widget.LockPatternUtils;
import com.android.internal.widget.LockPatternView;
@@ -76,7 +76,7 @@ public class DatabaseHelper extends SQLiteOpenHelper {
// database gets upgraded properly. At a minimum, please confirm that 'upgradeVersion'
// is properly propagated through your change. Not doing so will result in a loss of user
// settings.
- private static final int DATABASE_VERSION = 50;
+ private static final int DATABASE_VERSION = 51;
private Context mContext;
@@ -618,18 +618,9 @@ public class DatabaseHelper extends SQLiteOpenHelper {
if (upgradeVersion == 48) {
/*
- * Adding a new setting for which voice recognition service to use.
+ * Default recognition service no longer initialized here,
+ * moved to RecognitionManagerService.
*/
- db.beginTransaction();
- try {
- SQLiteStatement stmt = db.compileStatement("INSERT OR IGNORE INTO secure(name,value)"
- + " VALUES(?,?);");
- loadVoiceRecognitionServiceSetting(stmt);
- stmt.close();
- db.setTransactionSuccessful();
- } finally {
- db.endTransaction();
- }
upgradeVersion = 49;
}
@@ -651,6 +642,25 @@ public class DatabaseHelper extends SQLiteOpenHelper {
upgradeVersion = 50;
}
+ if (upgradeVersion == 50) {
+ /*
+ * New settings for set install location UI.
+ */
+ db.beginTransaction();
+ try {
+ SQLiteStatement stmt = db.compileStatement("INSERT INTO system(name,value)"
+ + " VALUES(?,?);");
+ loadBooleanSetting(stmt, Settings.System.SET_INSTALL_LOCATION,
+ R.bool.set_install_location);
+ stmt.close();
+ db.setTransactionSuccessful();
+ } finally {
+ db.endTransaction();
+ }
+
+ upgradeVersion = 51;
+ }
+
if (upgradeVersion != currentVersion) {
Log.w(TAG, "Got stuck trying to upgrade from version " + upgradeVersion
+ ", must wipe the settings provider");
@@ -1028,8 +1038,6 @@ public class DatabaseHelper extends SQLiteOpenHelper {
loadBooleanSetting(stmt, Settings.Secure.MOUNT_UMS_NOTIFY_ENABLED,
R.bool.def_mount_ums_notify_enabled);
- loadVoiceRecognitionServiceSetting(stmt);
-
stmt.close();
}
@@ -1041,32 +1049,6 @@ public class DatabaseHelper extends SQLiteOpenHelper {
R.string.def_backup_transport);
}
- /**
- * Introduced in database version 49.
- */
- private void loadVoiceRecognitionServiceSetting(SQLiteStatement stmt) {
- String selectedService = null;
- List<ResolveInfo> availableRecognitionServices =
- mContext.getPackageManager().queryIntentServices(
- new Intent(RecognitionService.SERVICE_INTERFACE), 0);
- int numAvailable = availableRecognitionServices.size();
-
- if (numAvailable == 0) {
- Log.w(TAG, "no available voice recognition services found");
- } else {
- if (numAvailable > 1) {
- Log.w(TAG, "more than one voice recognition service found, picking first");
- }
-
- ServiceInfo serviceInfo = availableRecognitionServices.get(0).serviceInfo;
- selectedService =
- new ComponentName(serviceInfo.packageName, serviceInfo.name).flattenToString();
- }
-
- loadSetting(stmt, Settings.Secure.VOICE_RECOGNITION_SERVICE,
- selectedService == null ? "" : selectedService);
- }
-
private void loadSetting(SQLiteStatement stmt, String key, Object value) {
stmt.bindString(1, key);
stmt.bindString(2, value.toString());
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 4080a6a..db802d3 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -20,7 +20,6 @@ import java.io.FileNotFoundException;
import java.io.UnsupportedEncodingException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
-import java.util.Random;
import android.backup.BackupManager;
import android.content.ContentProvider;
@@ -30,14 +29,11 @@ import android.content.Context;
import android.content.pm.PackageManager;
import android.content.res.AssetFileDescriptor;
import android.database.Cursor;
-import android.database.SQLException;
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;
-import android.os.ServiceManager;
import android.os.SystemProperties;
import android.provider.DrmStore;
import android.provider.MediaStore;
diff --git a/packages/TtsService/jni/android_tts_SynthProxy.cpp b/packages/TtsService/jni/android_tts_SynthProxy.cpp
index 35b5675..2f5cfa3 100644
--- a/packages/TtsService/jni/android_tts_SynthProxy.cpp
+++ b/packages/TtsService/jni/android_tts_SynthProxy.cpp
@@ -45,6 +45,9 @@
#define USAGEMODE_PLAY_IMMEDIATELY 0
#define USAGEMODE_WRITE_TO_FILE 1
+#define SYNTHPLAYSTATE_IS_STOPPED 0
+#define SYNTHPLAYSTATE_IS_PLAYING 1
+
using namespace android;
// ----------------------------------------------------------------------------
@@ -154,6 +157,8 @@ class SynthProxyJniStorage {
TtsEngine* mNativeSynthInterface;
void* mEngineLibHandle;
AudioTrack* mAudioOut;
+ int8_t mPlayState;
+ Mutex mPlayLock;
AudioSystem::stream_type mStreamType;
uint32_t mSampleRate;
uint32_t mAudFormat;
@@ -166,6 +171,7 @@ class SynthProxyJniStorage {
mNativeSynthInterface = NULL;
mEngineLibHandle = NULL;
mAudioOut = NULL;
+ mPlayState = SYNTHPLAYSTATE_IS_STOPPED;
mStreamType = DEFAULT_TTS_STREAM_TYPE;
mSampleRate = DEFAULT_TTS_RATE;
mAudFormat = DEFAULT_TTS_FORMAT;
@@ -223,6 +229,7 @@ class SynthProxyJniStorage {
if (minBufCount < 2) minBufCount = 2;
int minFrameCount = (afFrameCount * rate * minBufCount)/afSampleRate;
+ mPlayLock.lock();
mAudioOut = new AudioTrack(mStreamType, rate, format,
(channel == 2) ? AudioSystem::CHANNEL_OUT_STEREO : AudioSystem::CHANNEL_OUT_MONO,
minFrameCount > 4096 ? minFrameCount : 4096,
@@ -237,6 +244,7 @@ class SynthProxyJniStorage {
mAudioOut->setVolume(1.0f, 1.0f);
LOGV("AudioTrack ready");
}
+ mPlayLock.unlock();
}
};
@@ -288,6 +296,12 @@ static tts_callback_status ttsSynthDoneCB(void *& userdata, uint32_t rate,
if (bufferSize > 0) {
prepAudioTrack(pJniData, pForAfter->streamType, rate, (AudioSystem::audio_format)format, channel);
if (pJniData->mAudioOut) {
+ pJniData->mPlayLock.lock();
+ if(pJniData->mAudioOut->stopped()
+ && (pJniData->mPlayState == SYNTHPLAYSTATE_IS_PLAYING)) {
+ pJniData->mAudioOut->start();
+ }
+ pJniData->mPlayLock.unlock();
if (bUseFilter) {
applyFilter((int16_t*)wav, bufferSize/2);
}
@@ -711,9 +725,9 @@ android_tts_SynthProxy_speak(JNIEnv *env, jobject thiz, jint jniData,
SynthProxyJniStorage* pSynthData = (SynthProxyJniStorage*)jniData;
- if (pSynthData->mAudioOut) {
- pSynthData->mAudioOut->start();
- }
+ pSynthData->mPlayLock.lock();
+ pSynthData->mPlayState = SYNTHPLAYSTATE_IS_PLAYING;
+ pSynthData->mPlayLock.unlock();
afterSynthData_t* pForAfter = new (afterSynthData_t);
pForAfter->jniStorage = jniData;
@@ -744,9 +758,13 @@ android_tts_SynthProxy_stop(JNIEnv *env, jobject thiz, jint jniData)
SynthProxyJniStorage* pSynthData = (SynthProxyJniStorage*)jniData;
+ pSynthData->mPlayLock.lock();
+ pSynthData->mPlayState = SYNTHPLAYSTATE_IS_STOPPED;
if (pSynthData->mAudioOut) {
pSynthData->mAudioOut->stop();
}
+ pSynthData->mPlayLock.unlock();
+
if (pSynthData->mNativeSynthInterface) {
result = pSynthData->mNativeSynthInterface->stop();
}
diff --git a/preloaded-classes b/preloaded-classes
index 092b539..9fc000f 100644
--- a/preloaded-classes
+++ b/preloaded-classes
@@ -1,850 +1,1039 @@
# Classes which are preloaded by com.android.internal.os.ZygoteInit.
+# Automatically generated by frameworks/base/tools/preload/WritePreloadedClassFile.java.
+# MIN_LOAD_TIME_MICROS=1250
android.R$styleable
+android.accounts.AccountManager
+android.accounts.AccountManager$4
+android.accounts.AccountManager$6
+android.accounts.AccountManager$AmsTask
+android.accounts.AccountManager$BaseFutureTask
+android.accounts.AccountManager$Future2Task
+android.accounts.AuthenticatorDescription
+android.accounts.IAccountAuthenticatorResponse$Stub
+android.accounts.IAccountManager$Stub
+android.accounts.IAccountManagerResponse$Stub
android.app.Activity
android.app.ActivityGroup
-android.app.ActivityManager$MemoryInfo$1
+android.app.ActivityManager$RunningAppProcessInfo
+android.app.ActivityManager$RunningServiceInfo
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.ApplicationLoaders
android.app.ApplicationThreadNative
android.app.ContextImpl
-android.app.ContextImpl$ApplicationContentResolver
android.app.ContextImpl$ApplicationPackageManager
-android.app.ContextImpl$ApplicationPackageManager$PackageRemovedReceiver
-android.app.ContextImpl$ApplicationPackageManager$ResourceName
-android.app.ContextImpl$SharedPreferencesImpl
+android.app.DatePickerDialog
android.app.Dialog
android.app.ExpandableListActivity
android.app.IActivityManager
-android.app.IActivityManager$ContentProviderHolder$1
+android.app.IActivityManager$ContentProviderHolder
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.ISearchManager$Stub$Proxy
+android.app.IDevicePolicyManager$Stub
+android.app.IStatusBar$Stub
+android.app.ITransientNotification$Stub
android.app.Instrumentation
-android.app.IntentReceiverLeaked
+android.app.IntentService
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.ResultInfo$1
android.app.SearchDialog
android.app.SearchDialog$SearchAutoComplete
+android.app.SearchDialog$SearchBar
+android.app.SearchableInfo
android.app.Service
-android.app.ServiceConnectionLeaked
+android.app.SuggestionsAdapter
+android.app.SuperNotCalledException
android.app.TabActivity
-android.content.BroadcastReceiver
-android.content.ComponentCallbacks
+android.app.TimePickerDialog
+android.appwidget.AppWidgetHost
+android.appwidget.AppWidgetHostView
+android.appwidget.AppWidgetHostView$ParcelableSparseArray
+android.appwidget.AppWidgetManager
+android.appwidget.AppWidgetProvider
+android.appwidget.AppWidgetProviderInfo
+android.backup.BackupDataInput
+android.backup.BackupDataInput$EntityHeader
+android.backup.BackupDataOutput
+android.backup.BackupHelperAgent
+android.backup.BackupHelperDispatcher
+android.backup.BackupHelperDispatcher$Header
+android.backup.FileBackupHelperBase
+android.backup.IBackupManager$Stub
+android.backup.RestoreSet
+android.bluetooth.BluetoothAdapter
+android.bluetooth.BluetoothAudioGateway
+android.bluetooth.BluetoothSocket
+android.bluetooth.BluetoothUuid
+android.bluetooth.HeadsetBase
+android.bluetooth.IBluetooth
+android.bluetooth.IBluetooth$Stub
+android.bluetooth.IBluetoothA2dp
+android.bluetooth.IBluetoothA2dp$Stub
+android.bluetooth.IBluetoothHeadset$Stub
+android.bluetooth.ScoSocket
android.content.ComponentName
-android.content.ComponentName$1
android.content.ContentProvider$Transport
-android.content.ContentProviderProxy
-android.content.ContentQueryMap
-android.content.ContentQueryMap$1
+android.content.ContentProviderOperation
+android.content.ContentProviderResult
android.content.ContentResolver
-android.content.ContentResolver$CursorWrapperInner
android.content.ContentValues
android.content.Context
android.content.ContextWrapper
-android.content.DialogInterface
-android.content.DialogInterface$OnCancelListener
-android.content.DialogInterface$OnDismissListener
-android.content.IContentProvider
-android.content.IContentService
android.content.IContentService$Stub
+android.content.ISyncContext$Stub
android.content.Intent
-android.content.Intent$1
android.content.IntentFilter
+android.content.IntentSender
android.content.SearchRecentSuggestionsProvider
android.content.SyncResult
android.content.SyncStats
android.content.UriMatcher
android.content.pm.ActivityInfo
-android.content.pm.ActivityInfo$1
android.content.pm.ApplicationInfo
-android.content.pm.ApplicationInfo$1
-android.content.pm.ComponentInfo
-android.content.pm.IPackageManager
+android.content.pm.ConfigurationInfo
+android.content.pm.IPackageDataObserver$Stub
android.content.pm.IPackageManager$Stub
android.content.pm.IPackageManager$Stub$Proxy
+android.content.pm.IPackageStatsObserver$Stub
android.content.pm.InstrumentationInfo
-android.content.pm.InstrumentationInfo$1
-android.content.pm.PackageItemInfo
+android.content.pm.PackageInfo
android.content.pm.PackageManager
android.content.pm.PackageManager$NameNotFoundException
+android.content.pm.PackageStats
android.content.pm.PermissionInfo
android.content.pm.ProviderInfo
-android.content.pm.ProviderInfo$1
-android.content.pm.ResolveInfo$1
-android.content.pm.ServiceInfo$1
+android.content.pm.ResolveInfo
+android.content.pm.ResolveInfo$DisplayNameComparator
+android.content.pm.Signature
+android.content.res.AssetFileDescriptor
+android.content.res.AssetFileDescriptor$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$Theme
+android.content.res.Resources$1
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.ContentObservable
-android.database.ContentObserver$Transport
-android.database.Cursor
+android.database.CharArrayBuffer
android.database.CursorToBulkCursorAdaptor
-android.database.CursorToBulkCursorAdaptor$ContentObserverProxy
android.database.CursorWindow
+android.database.CursorWindow$1
android.database.CursorWrapper
-android.database.DataSetObservable
-android.database.IContentObserver$Stub$Proxy
-android.database.MergeCursor
+android.database.MatrixCursor
+android.database.sqlite.SQLiteClosable
+android.database.sqlite.SQLiteCompiledSql
+android.database.sqlite.SQLiteContentHelper
android.database.sqlite.SQLiteCursor
android.database.sqlite.SQLiteDatabase
-android.database.sqlite.SQLiteDatabase$CursorFactory
-android.database.sqlite.SQLiteDirectCursorDriver
+android.database.sqlite.SQLiteDebug
+android.database.sqlite.SQLiteDebug$PagerStats
+android.database.sqlite.SQLiteProgram
android.database.sqlite.SQLiteQuery
+android.database.sqlite.SQLiteQueryBuilder
android.database.sqlite.SQLiteStatement
-android.ddm.DdmHandleAppName
+android.database.sqlite.SqliteWrapper
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.Canvas$VertexMode
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.Matrix$ScaleToFit
+android.graphics.Movie
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$Direction
+android.graphics.Path$FillType
+android.graphics.PathDashPathEffect
+android.graphics.PathEffect
+android.graphics.PathMeasure
android.graphics.Picture
-android.graphics.PorterDuff
+android.graphics.PixelFormat
+android.graphics.PixelXorXfermode
+android.graphics.Point
+android.graphics.PointF
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.TableMaskFilter
android.graphics.Typeface
android.graphics.Xfermode
+android.graphics.YuvImage
+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
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.graphics.utils.BoundaryPatch
+android.hardware.Camera
+android.hardware.Camera$Parameters
+android.hardware.GeomagneticField
android.hardware.SensorManager
-android.inputmethodservice.KeyboardView
+android.location.Address
+android.location.Criteria
+android.location.GeocoderParams
+android.location.IGpsStatusListener$Stub
android.location.ILocationManager$Stub
+android.location.ILocationManager$Stub$Proxy
android.location.Location
+android.location.LocationManager
+android.location.LocationProviderInterface
+android.media.AudioFormat
android.media.AudioManager
+android.media.AudioRecord
+android.media.AudioSystem
+android.media.AudioTrack
+android.media.ExifInterface
android.media.IAudioService$Stub
-android.media.IAudioService$Stub$Proxy
+android.media.JetPlayer
+android.media.MediaFile
+android.media.MediaMetadataRetriever
+android.media.MediaPlayer
+android.media.MediaScanner
+android.media.Metadata
+android.media.MiniThumbFile
+android.media.ThumbnailUtils
+android.media.ToneGenerator
+android.net.ConnectivityManager
+android.net.Credentials
+android.net.DhcpInfo
+android.net.DhcpInfo$1
+android.net.Downloads
+android.net.Downloads$ByUri
+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.NetworkInfo
android.net.NetworkInfo$DetailedState
+android.net.NetworkUtils
android.net.SSLCertificateSocketFactory
android.net.TrafficStats
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.CertificateChainValidator
+android.net.http.AndroidHttpClient
+android.net.http.AndroidHttpClientConnection
android.net.http.EventHandler
+android.net.http.Headers
android.net.http.HttpsConnection
+android.net.http.HttpDateTime
+android.net.http.Request
android.net.http.RequestQueue
+android.net.http.SslCertificate
android.net.http.SslError
android.net.wifi.IWifiManager$Stub
+android.net.wifi.ScanResult
android.net.wifi.SupplicantState
android.net.wifi.WifiConfiguration
android.net.wifi.WifiInfo
-android.opengl.Material
+android.net.wifi.WifiManager
+android.net.wifi.WifiNative
+android.opengl.ETC1
+android.opengl.GLES10
+android.opengl.GLES10Ext
+android.opengl.GLES11
+android.opengl.GLES11Ext
+android.opengl.GLES20
+android.opengl.GLSurfaceView
+android.opengl.GLSurfaceView$ComponentSizeChooser
+android.opengl.GLUtils
+android.opengl.Matrix
+android.opengl.Visibility
android.os.Binder
android.os.BinderProxy
android.os.Build
+android.os.Build$VERSION
android.os.Bundle
-android.os.Bundle$1
+android.os.Debug
+android.os.Debug$MemoryInfo
+android.os.Debug$MemoryInfo$1
+android.os.DropBoxManager$Entry
android.os.Environment
+android.os.FileObserver$ObserverThread
android.os.FileUtils
+android.os.FileUtils$FileStatus
android.os.Handler
-android.os.HandlerThread
android.os.IBinder
+android.os.IInterface
android.os.IPowerManager$Stub
-android.os.IPowerManager$Stub$Proxy
-android.os.IServiceManager
-android.os.IVibratorService$Stub
-android.os.IVibratorService$Stub$Proxy
android.os.Looper
+android.os.MemoryFile
android.os.Message
-android.os.Message$1
-android.os.MessageQueue
-android.os.MessageQueue$IdleHandler
android.os.Parcel
-android.os.PatternMatcher
-android.os.PatternMatcher$1
-android.os.PowerManager
-android.os.PowerManager$WakeLock
-android.os.PowerManager$WakeLock$1
+android.os.Parcel$1
+android.os.ParcelFileDescriptor
+android.os.ParcelFileDescriptor$1
+android.os.ParcelUuid
+android.os.Parcelable
+android.os.Parcelable$Creator
+android.os.Power
android.os.Process
-android.os.ServiceManager
-android.os.ServiceManagerNative
-android.os.ServiceManagerProxy
-android.os.Vibrator
-android.preference.CheckBoxPreference
+android.os.RecoverySystem
+android.os.ResultReceiver
+android.os.StatFs
+android.os.SystemClock
+android.os.SystemProperties
+android.os.UEventObserver
+android.os.storage.IMountService$Stub
+android.os.storage.IMountService$Stub$Proxy
+android.pim.EventRecurrence
+android.pim.RecurrenceSet
+android.preference.CheckBoxPreference$SavedState
android.preference.DialogPreference
-android.preference.EditTextPreference
android.preference.ListPreference
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.sax.RootElement
+android.preference.VolumePreference
+android.preference.VolumePreference$SeekBarVolumizer
+android.provider.Browser
+android.provider.Calendar
+android.provider.Calendar$Attendees
+android.provider.Calendar$CalendarAlerts
+android.provider.Calendar$Calendars
+android.provider.Calendar$EventDays
+android.provider.Calendar$Events
+android.provider.Calendar$Reminders
+android.provider.Contacts
+android.provider.Contacts$ContactMethods
+android.provider.ContactsContract
+android.provider.ContactsContract$CommonDataKinds$Email
+android.provider.ContactsContract$CommonDataKinds$Phone
+android.provider.ContactsContract$CommonDataKinds$StructuredPostal
+android.provider.ContactsContract$Contacts
+android.provider.ContactsContract$Data
+android.provider.ContactsContract$DataColumnsWithJoins
+android.provider.ContactsContract$PhoneLookup
+android.provider.ContactsContract$RawContacts
+android.provider.ContactsContract$RawContacts$EntityIteratorImpl
+android.provider.ContactsContract$RawContactsEntity
+android.provider.Downloads
+android.provider.Downloads$Impl
+android.provider.MediaStore
+android.provider.MediaStore$Audio$Artists
+android.provider.MediaStore$Audio$Media
+android.provider.MediaStore$Images$Media
+android.provider.MediaStore$Images$Thumbnails
+android.provider.MediaStore$Video$Media
+android.provider.SearchRecentSuggestions
+android.provider.Settings$Secure
+android.provider.Settings$System
+android.provider.UserDictionary$Words
+android.security.KeyStore
+android.security.Md5MessageDigest
+android.security.MessageDigest
+android.security.Sha1MessageDigest
+android.server.BluetoothA2dpService
+android.server.BluetoothEventLoop
+android.server.BluetoothService
+android.speech.tts.ITts$Stub
+android.speech.tts.ITts$Stub$Proxy
+android.speech.tts.ITtsCallback$Stub
+android.speech.tts.TextToSpeech
android.telephony.PhoneNumberUtils
-android.telephony.PhoneStateListener
android.telephony.ServiceState
-android.telephony.TelephonyManager
-android.telephony.SmsManager
+android.telephony.SignalStrength
android.telephony.SmsMessage
-android.text.AutoText
+android.telephony.SmsMessage$MessageClass
+android.telephony.TelephonyManager
+android.text.AndroidCharacter
android.text.BoringLayout
-android.text.BoringLayout$Metrics
android.text.DynamicLayout
-android.text.DynamicLayout$ChangeWatcher
-android.text.Editable
-android.text.Editable$Factory
-android.text.GetChars
-android.text.GraphicsOperations
android.text.Html$HtmlParser
-android.text.InputFilter
+android.text.HtmlToSpannedConverter
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.KeyListener
+android.text.method.DigitsKeyListener
+android.text.method.LinkMovementMethod
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.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.ImageSpan
+android.text.style.RelativeSizeSpan
+android.text.style.ScaleXSpan
android.text.style.StyleSpan
-android.text.style.URLSpan
-android.text.style.UpdateAppearance
-android.text.style.UpdateLayout
-android.text.style.WrapTogetherSpan
+android.text.style.TextAppearanceSpan
android.text.util.Linkify
android.util.AttributeSet
android.util.DisplayMetrics
+android.util.EventLog
+android.util.EventLog$Event
android.util.FloatMath
+android.util.Log
+android.util.LongSparseArray
+android.util.MonthDisplayHelper
+android.util.Patterns
android.util.SparseArray
+android.util.StateSet
android.util.TypedValue
-android.util.Xml$XmlSerializerFactory
+android.util.Xml
+android.util.Xml$Encoding
+android.util.base64.Base64$Encoder
android.view.AbsSavedState
-android.view.ContextMenu
-android.view.ContextMenu$ContextMenuInfo
android.view.ContextThemeWrapper
android.view.Display
android.view.FocusFinder
-android.view.FocusFinder$1
-android.view.GestureDetector$SimpleOnGestureListener
-android.view.Gravity
-android.view.IWindow
+android.view.GestureDetector
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.LayoutInflater$Factory
-android.view.Menu
-android.view.MenuInflater
-android.view.MenuItem
android.view.MotionEvent
-android.view.MotionEvent$1
+android.view.ScaleGestureDetector
android.view.Surface
-android.view.SurfaceHolder
+android.view.Surface$1
+android.view.SurfaceSession
android.view.SurfaceView
-android.view.TouchDelegate
+android.view.SurfaceView$MyWindow
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.ViewGroup$LayoutParams
-android.view.ViewGroup$MarginLayoutParams
-android.view.ViewManager
+android.view.ViewParent
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.animation.AccelerateDecelerateInterpolator
-android.view.animation.AlphaAnimation
+android.view.accessibility.AccessibilityEvent
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.CacheManager
android.webkit.CallbackProxy
+android.webkit.ConsoleMessage$MessageLevel
android.webkit.CookieManager
android.webkit.CookieSyncManager
+android.webkit.DownloadListener
+android.webkit.FileLoader
+android.webkit.GeolocationPermissions
+android.webkit.GeolocationService
+android.webkit.HTML5VideoViewProxy
android.webkit.JWebCoreJavaBridge
android.webkit.LoadListener
-android.webkit.MimeTypeMap
+android.webkit.PluginManager
android.webkit.URLUtil
-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.WebIconDatabase$IconListener
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.WebStorage
android.webkit.WebTextView
android.webkit.WebView
-android.webkit.WebView$ExtendedZoomControls
-android.webkit.WebView$PrivateHandler
+android.webkit.WebView$DragTrackerHandler
+android.webkit.WebView$ScaleDetectorListener
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.WebViewCore$4
+android.webkit.WebViewCore$TextSelectionData
+android.webkit.WebViewCore$TouchEventData
+android.webkit.WebViewCore$TouchUpData
android.webkit.WebViewDatabase
android.widget.AbsListView
-android.widget.AbsListView$CheckForLongPress
-android.widget.AbsListView$CheckForTap
-android.widget.AbsListView$LayoutParams
+android.widget.AbsListView$3
+android.widget.AbsListView$CheckForKeyLongPress
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.AdapterView$AdapterDataSetObserver
android.widget.ArrayAdapter
android.widget.AutoCompleteTextView
android.widget.AutoCompleteTextView$DropDownItemClickListener
android.widget.AutoCompleteTextView$DropDownListView
android.widget.BaseAdapter
-android.widget.Button
+android.widget.BaseExpandableListAdapter
android.widget.CheckBox
-android.widget.Checkable
-android.widget.CheckedTextView
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.ExpandableListView
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.ListView$SavedState$1
+android.widget.MediaController
+android.widget.MediaController$4
+android.widget.MultiAutoCompleteTextView
+android.widget.NumberPicker
android.widget.PopupWindow
+android.widget.PopupWindow$PopupViewContainer
android.widget.ProgressBar
-android.widget.RadioGroup
+android.widget.ProgressBar$SavedState
+android.widget.QuickContactBadge
android.widget.RatingBar
android.widget.RelativeLayout
-android.widget.RelativeLayout$LayoutParams
+android.widget.RelativeLayout$DependencyGraph$Node
android.widget.RemoteViews
+android.widget.ResourceCursorAdapter
android.widget.ScrollBarDrawable
android.widget.ScrollView
-android.widget.Scroller
android.widget.SeekBar
android.widget.SimpleCursorAdapter
android.widget.SlidingDrawer
android.widget.Spinner
-android.widget.Spinner$DropDownAdapter
android.widget.TabHost
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$ChangeWatcher
-android.widget.TextView$CharWrapper
-android.widget.TextView$Drawables
-android.widget.TextView$InputContentType
-android.widget.TextView$InputMethodState
+android.widget.TextView$CommitSelectionReceiver
android.widget.TextView$Marquee
-android.widget.TextView$MenuHandler
-android.widget.TextView$SavedState
-android.widget.TextView$SavedState$1
-android.widget.ToggleButton
+android.widget.TimePicker
android.widget.TwoLineListItem
+android.widget.VideoView
android.widget.ViewAnimator
android.widget.ViewSwitcher
android.widget.ZoomButton
+android.widget.ZoomButtonsController
android.widget.ZoomControls
-com.android.common.ArrayListCursor
-com.android.common.FastXmlSerializer
-com.android.common.NetworkConnectivityListener
-com.android.common.NetworkConnectivityListener$State
-com.android.common.XmlUtils
-com.android.internal.database.SortCursor
+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$RecycleListView
+com.android.internal.app.ChooserActivity
+com.android.internal.app.ResolverActivity
+com.android.internal.app.ResolverActivity$ResolveListAdapter
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.content.SyncStateContentProviderHelper
+com.android.internal.graphics.NativeUtils
+com.android.internal.location.DummyLocationProvider
+com.android.internal.location.GpsLocationProvider
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.IResultReceiver$Stub
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.RuntimeInit$UncaughtHandler
-com.android.internal.os.ZygoteInit$MethodAndArgsCaller
-com.android.internal.policy.IPolicy
+com.android.internal.os.SamplingProfilerIntegration
+com.android.internal.os.ZygoteConnection
+com.android.internal.os.ZygoteConnection$Arguments
+com.android.internal.os.ZygoteInit
+com.android.internal.net.DomainNameValidator
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.PhoneWindow$PanelFeatureState$SavedState$1
+com.android.internal.policy.impl.PhoneWindowManager
com.android.internal.policy.impl.Policy
-com.android.internal.telephony.Connection$DisconnectCause
-com.android.internal.telephony.Connection$PostDialState
-com.android.internal.telephony.IPhoneStateListener$Stub
+com.android.internal.telephony.GsmAlphabet
com.android.internal.telephony.ITelephony$Stub
-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.ITelephony$Stub$Proxy
+com.android.internal.telephony.ITelephonyRegistry$Stub
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.telephony.Phone$State
+com.android.internal.telephony.SmsAddress
+com.android.internal.telephony.SmsMessageBase
+com.android.internal.telephony.gsm.GsmSmsAddress
+com.android.internal.telephony.gsm.SmsMessage
+com.android.internal.telephony.gsm.SmsMessage$PduParser
+com.android.internal.util.ArrayUtils
+com.android.internal.util.FastMath
+com.android.internal.util.FastXmlSerializer
+com.android.internal.util.HanziToPinyin
+com.android.internal.util.XmlUtils
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.ContextMenuBuilder
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.RotarySelector
-com.android.internal.widget.Smileys
-com.google.android.gles_jni.EGLDisplayImpl
+com.android.internal.widget.ContactHeaderWidget
+com.android.internal.widget.DialogTitle
+com.android.internal.widget.EditableInputConnection
+com.android.internal.widget.LinearLayoutWithDefaultTouchRecepient
+com.android.internal.widget.LockPatternUtils
+com.android.internal.widget.LockPatternView
+com.android.internal.widget.LockPatternView$Cell
com.google.android.gles_jni.EGLImpl
com.google.android.gles_jni.GLImpl
com.ibm.icu4jni.charset.CharsetDecoderICU
com.ibm.icu4jni.charset.CharsetEncoderICU
com.ibm.icu4jni.charset.CharsetICU
-com.ibm.icu4jni.text.CollationAttribute
+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.Collator
+com.ibm.icu4jni.text.NativeBreakIterator
+com.ibm.icu4jni.text.NativeCollation
com.ibm.icu4jni.text.NativeDecimalFormat
com.ibm.icu4jni.text.RuleBasedCollator
+com.ibm.icu4jni.text.RuleBasedNumberFormat
+com.ibm.icu4jni.util.Resources
com.ibm.icu4jni.util.Resources$DefaultTimeZones
-dalvik.system.DexFile
+dalvik.system.DalvikLogHandler
+dalvik.system.DalvikLogging
+dalvik.system.NativeStart
dalvik.system.PathClassLoader
+dalvik.system.SamplingProfiler
+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.ByteArrayInputStream
-java.io.ByteArrayOutputStream
+java.io.Closeable
+java.io.DataInput
+java.io.DataOutput
+java.io.DataOutputStream
java.io.File
java.io.FileDescriptor
java.io.FileInputStream
java.io.FileInputStream$RepositioningLock
java.io.FileNotFoundException
+java.io.FileOutputStream
java.io.FilterInputStream
+java.io.FilterOutputStream
+java.io.Flushable
java.io.IOException
+java.io.InputStream
+java.io.InputStreamReader
+java.io.InterruptedIOException
+java.io.ObjectInput
+java.io.ObjectInputStream
+java.io.ObjectOutput
+java.io.ObjectOutputStream
java.io.ObjectStreamClass
+java.io.ObjectStreamClass$OSCThreadLocalCache
+java.io.ObjectStreamConstants
+java.io.ObjectStreamException
+java.io.ObjectStreamField
+java.io.OutputStream
+java.io.OutputStreamWriter
+java.io.PrintStream
java.io.PrintWriter
+java.io.PushbackReader
java.io.RandomAccessFile
java.io.RandomAccessFile$RepositionLock
-java.io.StringWriter
-java.io.Writer
+java.io.Reader
+java.io.Serializable
+java.io.StreamCorruptedException
+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.lang.Character$UnicodeBlock
java.lang.Class
java.lang.ClassCache
-java.lang.ClassNotFoundException
+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.IllegalArgumentException
-java.lang.IllegalStateException
+java.lang.IndexOutOfBoundsException
java.lang.Integer
+java.lang.InternalError
+java.lang.InterruptedException
+java.lang.Iterable
+java.lang.LangAccessImpl
java.lang.LinkageError
java.lang.Long
+java.lang.Math
java.lang.NoClassDefFoundError
+java.lang.NoSuchMethodError
+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.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.PhantomReference
+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.AddressCache
+java.net.AddressCache$1
+java.net.ConnectException
java.net.ContentHandler
+java.net.DatagramPacket
+java.net.Inet4Address
java.net.InetAddress
+java.net.InetAddress$1
+java.net.InetAddress$2
java.net.InetAddress$WaitReachable
+java.net.InetSocketAddress
java.net.JarURLConnection
java.net.NetPermission
-java.net.ProxySelectorImpl
-java.net.Socket$ConnectLock
+java.net.NetworkInterface
+java.net.ServerSocket
+java.net.Socket
+java.net.SocketException
+java.net.SocketImpl
+java.net.SocketOptions
java.net.URI
java.net.URL
java.net.URLConnection
java.net.URLConnection$DefaultContentHandler
java.net.URLStreamHandler
+java.nio.BaseByteBuffer
+java.nio.Buffer
+java.nio.BufferFactory
+java.nio.ByteBuffer
java.nio.ByteOrder
+java.nio.CharArrayBuffer
+java.nio.CharBuffer
java.nio.CharSequenceAdapter
+java.nio.CharToByteBufferAdapter
java.nio.DirectByteBuffer
+java.nio.FloatToByteBufferAdapter
+java.nio.HeapByteBuffer
+java.nio.IntToByteBufferAdapter
+java.nio.LongBuffer
+java.nio.LongToByteBufferAdapter
+java.nio.NIOAccess
+java.nio.ReadWriteCharArrayBuffer
java.nio.ReadWriteDirectByteBuffer
-java.nio.ReadWriteIntArrayBuffer
-java.nio.ReadWriteShortArrayBuffer
-java.nio.ShortBuffer
+java.nio.ReadWriteHeapByteBuffer
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.channels.spi.AbstractInterruptibleChannel$2
+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.AccessControlContext
-java.security.GeneralSecurityException
+java.security.AccessController
+java.security.BasicPermission
+java.security.Guard
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.CertPathValidator
-java.security.cert.CertificateFactory
-java.security.cert.PKIXParameters
-java.security.cert.TrustAnchor
-java.security.cert.X509CertSelector
java.security.cert.X509Certificate
+java.text.AttributedCharacterIterator$Attribute
java.text.Collator
+java.text.Collator$1
java.text.DateFormat
java.text.DateFormat$Field
java.text.DecimalFormat
java.text.DecimalFormatSymbols
-java.text.MessageFormat
+java.text.Format
java.text.NumberFormat
-java.text.RuleBasedCollator
java.text.SimpleDateFormat
-java.util.AbstractList$FullListIterator
-java.util.AbstractList$SimpleListIterator
+java.util.AbstractCollection
+java.util.AbstractList
+java.util.AbstractMap
+java.util.AbstractSet
java.util.ArrayList
+java.util.ArrayList$ArrayListIterator
java.util.Arrays
java.util.Arrays$ArrayList
+java.util.BitSet
java.util.Calendar
-java.util.Collections$SynchronizedCollection
-java.util.Collections$UnmodifiableList
-java.util.Collections$UnmodifiableMap
-java.util.Collections$UnmodifiableMap$UnmodifiableEntrySet$1
+java.util.Collection
+java.util.Collections
+java.util.Collections$EmptyList
+java.util.Collections$EmptyMap
+java.util.Collections$EmptySet
+java.util.Collections$SingletonSet
+java.util.Collections$UnmodifiableCollection
+java.util.Collections$UnmodifiableCollection$1
+java.util.Collections$UnmodifiableRandomAccessList
+java.util.Collections$UnmodifiableSet
+java.util.Comparator
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$HashIterator
+java.util.HashMap$HashMapEntry
+java.util.HashMap$KeyIterator
+java.util.HashMap$KeySet
+java.util.HashMap$Values
java.util.HashSet
java.util.Hashtable
+java.util.Hashtable$HashIterator
+java.util.Hashtable$HashtableEntry
+java.util.Hashtable$KeyEnumeration
+java.util.Hashtable$ValueIterator
+java.util.Hashtable$Values
java.util.IdentityHashMap
+java.util.Iterator
java.util.LinkedHashMap
+java.util.LinkedHashMap$LinkedEntry
+java.util.LinkedHashMap$LinkedHashIterator
+java.util.LinkedHashMap$ValueIterator
java.util.LinkedList
-java.util.LinkedList$Link
java.util.List
+java.util.ListIterator
java.util.Locale
+java.util.Map
+java.util.Map$Entry
+java.util.MiniEnumSet
java.util.Properties
-java.util.Random
+java.util.PropertyPermission
+java.util.RandomAccess
java.util.ResourceBundle
+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.TreeMap
-java.util.TreeMap$MapEntry
java.util.TreeSet
+java.util.UUID
java.util.Vector
java.util.WeakHashMap
java.util.WeakHashMap$Entry
java.util.concurrent.ConcurrentHashMap
java.util.concurrent.ConcurrentLinkedQueue
-java.util.concurrent.DelayQueue
+java.util.concurrent.ConcurrentLinkedQueue$Node
+java.util.concurrent.CopyOnWriteArrayList
+java.util.concurrent.CopyOnWriteArrayList$COWIterator
+java.util.concurrent.Executors$DelegatedExecutorService
+java.util.concurrent.FutureTask
java.util.concurrent.LinkedBlockingQueue
-java.util.concurrent.ScheduledThreadPoolExecutor
-java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue
+java.util.concurrent.Semaphore
+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.AbstractOwnableSynchronizer
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
@@ -852,25 +1041,25 @@ 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.LogManager$4
java.util.logging.Logger
+java.util.logging.Logger$1
java.util.logging.LoggingPermission
-java.util.logging.SimpleFormatter
+java.util.regex.MatchResult
java.util.regex.Matcher
java.util.regex.Pattern
-java.util.zip.DeflaterOutputStream
+java.util.zip.Adler32
+java.util.zip.CRC32
+java.util.zip.Checksum
+java.util.zip.Deflater
java.util.zip.Inflater
java.util.zip.InflaterInputStream
java.util.zip.ZipConstants
@@ -879,63 +1068,90 @@ java.util.zip.ZipEntry$LittleEndianReader
java.util.zip.ZipFile
java.util.zip.ZipFile$2
java.util.zip.ZipFile$RAFStream
-javax.microedition.khronos.egl.EGLContext
+java.util.zip.ZipFile$ZipInflaterInputStream
+javax.crypto.Cipher
+javax.crypto.Mac
+javax.crypto.spec.IvParameterSpec
+javax.microedition.khronos.egl.EGL
+javax.microedition.khronos.egl.EGL10
+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.SSLHandshakeException
+javax.net.ssl.SSLServerSocket
+javax.net.ssl.SSLSession
+javax.net.ssl.SSLSocket
+javax.net.ssl.SSLSocketFactory
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.archive.util.Util
-org.apache.harmony.dalvik.ddmc.Chunk
+org.apache.harmony.dalvik.NativeTestTarget
org.apache.harmony.dalvik.ddmc.ChunkHandler
org.apache.harmony.dalvik.ddmc.DdmServer
-org.apache.harmony.dalvik.ddmc.DdmVmInternal
+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.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.JarURLConnectionImpl
-org.apache.harmony.luni.internal.net.www.protocol.jar.JarURLConnectionImpl$1
org.apache.harmony.luni.internal.net.www.protocol.jar.JarURLConnectionImpl$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.Endianness
+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.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.util.TwoKeyHashMap
+org.apache.harmony.luni.platform.PlatformAddressFactory
+org.apache.harmony.luni.util.FloatingPointParser
+org.apache.harmony.luni.util.InputStreamHelper
+org.apache.harmony.luni.util.InputStreamHelper$1
+org.apache.harmony.luni.util.InputStreamHelper$ExposedByteArrayInputStream
+org.apache.harmony.luni.util.LocaleCache
+org.apache.harmony.luni.util.Msg
+org.apache.harmony.luni.util.NumberConverter
+org.apache.harmony.luni.util.PriviAction
+org.apache.harmony.luni.util.ThreadLocalCache
+org.apache.harmony.luni.util.ThreadLocalCache$1
+org.apache.harmony.luni.util.ThreadLocalCache$2
+org.apache.harmony.luni.util.ThreadLocalCache$3
+org.apache.harmony.luni.util.ThreadLocalCache$4
+org.apache.harmony.luni.util.ThreadLocalCache$5
+org.apache.harmony.luni.util.Util
+org.apache.harmony.nio.FileChannelFactory
+org.apache.harmony.nio.internal.DirectBuffer
+org.apache.harmony.nio.internal.FileChannelImpl
org.apache.harmony.nio.internal.FileChannelImpl$RepositioningLock
+org.apache.harmony.nio.internal.FileLockImpl
org.apache.harmony.nio.internal.LockManager
org.apache.harmony.nio.internal.LockManager$1
-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.nio.internal.WriteOnlyFileChannel
org.apache.harmony.security.asn1.ASN1GeneralizedTime
-org.apache.harmony.security.asn1.ASN1Implicit
-org.apache.harmony.security.asn1.ASN1Integer
-org.apache.harmony.security.asn1.ASN1OctetString
-org.apache.harmony.security.asn1.ASN1SetOf
+org.apache.harmony.security.asn1.ASN1Oid
org.apache.harmony.security.asn1.ASN1StringType
-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.asn1.DerInputStream
+org.apache.harmony.security.asn1.DerOutputStream
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
@@ -943,183 +1159,111 @@ org.apache.harmony.security.provider.crypto.RandomBitsSupplier
org.apache.harmony.security.provider.crypto.SHA1PRNG_SecureRandomImpl
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.Certificate$1
+org.apache.harmony.security.x509.EDIPartyName
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.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.security.x509.Validity$1
+org.apache.harmony.text.BidiWrapper
+org.apache.harmony.xml.ExpatAttributes
org.apache.harmony.xml.ExpatParser
org.apache.harmony.xml.ExpatPullParser
-org.apache.harmony.xml.ExpatReader
-org.apache.harmony.xnet.provider.jsse.ClientSessionContext
+org.apache.harmony.xml.parsers.SAXParserFactoryImpl
+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.OpenSSLSessionImpl
org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl
org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl$Finalizer
-org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl$SSLInputStream
-org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl$SSLOutputStream
+org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl$LoggerHolder
+org.apache.harmony.xnet.provider.jsse.ProtocolVersion
org.apache.harmony.xnet.provider.jsse.SSLContextImpl
org.apache.harmony.xnet.provider.jsse.SSLParameters
-org.apache.harmony.xnet.provider.jsse.TrustManagerFactoryImpl
-org.apache.harmony.xnet.provider.jsse.TrustManagerImpl
-org.apache.http.HttpHost
-org.apache.http.HttpRequestInterceptor
+org.apache.harmony.xnet.provider.jsse.ServerSessionContext
org.apache.http.HttpVersion
-org.apache.http.auth.AuthSchemeRegistry
-org.apache.http.client.HttpClient
-org.apache.http.client.RequestDirector
+org.apache.http.client.methods.HttpEntityEnclosingRequestBase
+org.apache.http.client.methods.HttpGet
+org.apache.http.client.methods.HttpPost
org.apache.http.client.methods.HttpRequestBase
-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.BasicManagedEntity
+org.apache.http.conn.params.ConnManagerParams
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.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.AbstractVerifier
org.apache.http.conn.ssl.SSLSocketFactory
-org.apache.http.conn.ssl.StrictHostnameVerifier
org.apache.http.conn.util.InetAddressUtils
-org.apache.http.cookie.CookieSpecRegistry
-org.apache.http.impl.DefaultConnectionReuseStrategy
-org.apache.http.impl.DefaultHttpResponseFactory
+org.apache.http.impl.AbstractHttpClientConnection
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.BasicCookieStore
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.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.SingleClientConnManager
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.BestMatchSpecFactory
-org.apache.http.impl.cookie.BrowserCompatSpecFactory
+org.apache.http.impl.cookie.BrowserCompatSpec
org.apache.http.impl.cookie.DateUtils
-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.cookie.DateUtils$DateFormatHolder
+org.apache.http.impl.cookie.RFC2109Spec
org.apache.http.impl.io.SocketInputBuffer
-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.BasicNameValuePair
+org.apache.http.message.BasicTokenIterator
org.apache.http.params.BasicHttpParams
org.apache.http.protocol.BasicHttpProcessor
org.apache.http.protocol.HTTP
-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.DERNull
org.bouncycastle.asn1.DERObject
org.bouncycastle.asn1.DERObjectIdentifier
-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.iana.IANAObjectIdentifiers
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.asn1.x509.X509NameElementList
-org.bouncycastle.asn1.x9.X9ObjectIdentifiers
+org.bouncycastle.crypto.digests.SHA1Digest
org.bouncycastle.crypto.engines.AESFastEngine
+org.bouncycastle.crypto.macs.HMac
+org.bouncycastle.jce.provider.BouncyCastleProvider
org.bouncycastle.jce.provider.CertPathValidatorUtilities
-org.bouncycastle.jce.provider.JCEBlockCipher$AES
-org.bouncycastle.jce.provider.JCERSAPublicKey
-org.bouncycastle.jce.provider.JDKKeyFactory$RSA
+org.bouncycastle.jce.provider.JCEBlockCipher
org.bouncycastle.jce.provider.JDKKeyStore
-org.bouncycastle.jce.provider.JDKKeyStore$StoreEntry
+org.bouncycastle.jce.provider.JDKX509CertificateFactory
org.bouncycastle.jce.provider.PKIXCertPathValidatorSpi
-org.bouncycastle.jce.provider.RSAUtil
+org.bouncycastle.jce.provider.WrapCipherSpi
org.bouncycastle.jce.provider.X509CertificateObject
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.InputSource
+org.xml.sax.helpers.AttributesImpl
org.xml.sax.helpers.DefaultHandler
-org.xml.sax.helpers.NewInstance
+org.xmlpull.v1.XmlPullParser
org.xmlpull.v1.XmlPullParserFactory
-org.xmlpull.v1.sax2.Driver
sun.misc.Unsafe
diff --git a/sax/tests/saxtests/src/android/sax/SafeSaxTest.java b/sax/tests/saxtests/src/android/sax/SafeSaxTest.java
index bee3938..e8cf2f7 100644
--- a/sax/tests/saxtests/src/android/sax/SafeSaxTest.java
+++ b/sax/tests/saxtests/src/android/sax/SafeSaxTest.java
@@ -29,7 +29,7 @@ import android.test.suitebuilder.annotation.SmallTest;
import android.text.format.Time;
import android.util.Log;
import android.util.Xml;
-import com.android.common.XmlUtils;
+import com.android.internal.util.XmlUtils;
import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException;
diff --git a/services/java/com/android/server/AccessibilityManagerService.java b/services/java/com/android/server/AccessibilityManagerService.java
index 477ea0c..c55dcb3 100644
--- a/services/java/com/android/server/AccessibilityManagerService.java
+++ b/services/java/com/android/server/AccessibilityManagerService.java
@@ -16,6 +16,7 @@
package com.android.server;
+import com.android.internal.content.PackageMonitor;
import com.android.internal.os.HandlerCaller;
import com.android.internal.os.HandlerCaller.SomeArgs;
@@ -56,6 +57,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -145,13 +147,58 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
private void registerPackageChangeAndBootCompletedBroadcastReceiver() {
Context context = mContext;
- BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
+ PackageMonitor monitor = new PackageMonitor() {
@Override
- public void onReceive(Context context, Intent intent) {
+ public void onSomePackagesChanged() {
synchronized (mLock) {
populateAccessibilityServiceListLocked();
+ manageServicesLocked();
+ }
+ }
+
+ @Override
+ public boolean onHandleForceStop(Intent intent, String[] packages,
+ int uid, boolean doit) {
+ synchronized (mLock) {
+ boolean changed = false;
+ Iterator<ComponentName> it = mEnabledServices.iterator();
+ while (it.hasNext()) {
+ ComponentName comp = it.next();
+ String compPkg = comp.getPackageName();
+ for (String pkg : packages) {
+ if (compPkg.equals(pkg)) {
+ if (!doit) {
+ return true;
+ }
+ it.remove();
+ changed = true;
+ }
+ }
+ }
+ if (changed) {
+ it = mEnabledServices.iterator();
+ StringBuilder str = new StringBuilder();
+ while (it.hasNext()) {
+ if (str.length() > 0) {
+ str.append(':');
+ }
+ str.append(it.next().flattenToShortString());
+ }
+ Settings.Secure.putString(mContext.getContentResolver(),
+ Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
+ str.toString());
+ manageServicesLocked();
+ }
+ return false;
+ }
+ }
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (intent.getAction() == Intent.ACTION_BOOT_COMPLETED) {
+ synchronized (mLock) {
+ populateAccessibilityServiceListLocked();
- if (intent.getAction() == Intent.ACTION_BOOT_COMPLETED) {
// get the accessibility enabled setting on boot
mIsEnabled = Settings.Secure.getInt(mContext.getContentResolver(),
Settings.Secure.ACCESSIBILITY_ENABLED, 0) == 1;
@@ -160,29 +207,23 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
if (mIsEnabled) {
updateClientsLocked();
}
- }
- manageServicesLocked();
+ manageServicesLocked();
+ }
+
+ return;
}
+
+ super.onReceive(context, intent);
}
};
// package changes
- IntentFilter packageFilter = new IntentFilter();
- packageFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
- packageFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
- packageFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
- packageFilter.addDataScheme("package");
- context.registerReceiver(broadcastReceiver, packageFilter);
- // Register for events related to sdcard installation.
- IntentFilter sdFilter = new IntentFilter();
- sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
- sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
- mContext.registerReceiver(broadcastReceiver, sdFilter);
+ monitor.register(context, true);
// boot completed
IntentFilter bootFiler = new IntentFilter(Intent.ACTION_BOOT_COMPLETED);
- mContext.registerReceiver(broadcastReceiver, bootFiler);
+ mContext.registerReceiver(monitor, bootFiler);
}
/**
@@ -529,8 +570,14 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
TextUtils.SimpleStringSplitter splitter = mStringColonSplitter;
splitter.setString(servicesValue);
while (splitter.hasNext()) {
- ComponentName enabledService = ComponentName.unflattenFromString(splitter.next());
- enabledServices.add(enabledService);
+ String str = splitter.next();
+ if (str == null || str.length() <= 0) {
+ continue;
+ }
+ ComponentName enabledService = ComponentName.unflattenFromString(str);
+ if (enabledService != null) {
+ enabledServices.add(enabledService);
+ }
}
}
}
diff --git a/services/java/com/android/server/AlarmManagerService.java b/services/java/com/android/server/AlarmManagerService.java
index 44cc0bb..f480209 100644
--- a/services/java/com/android/server/AlarmManagerService.java
+++ b/services/java/com/android/server/AlarmManagerService.java
@@ -16,6 +16,7 @@
package com.android.server;
+import android.app.Activity;
import android.app.ActivityManagerNative;
import android.app.AlarmManager;
import android.app.IAlarmManager;
@@ -344,6 +345,22 @@ class AlarmManagerService extends IAlarmManager.Stub {
}
}
+ public boolean lookForPackageLocked(String packageName) {
+ return lookForPackageLocked(mRtcWakeupAlarms, packageName)
+ || lookForPackageLocked(mRtcAlarms, packageName)
+ || lookForPackageLocked(mElapsedRealtimeWakeupAlarms, packageName)
+ || lookForPackageLocked(mElapsedRealtimeAlarms, packageName);
+ }
+
+ private boolean lookForPackageLocked(ArrayList<Alarm> alarmList, String packageName) {
+ for (int i=alarmList.size()-1; i>=0; i--) {
+ if (alarmList.get(i).operation.getTargetPackage().equals(packageName)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
private ArrayList<Alarm> getAlarmList(int type) {
switch (type) {
case AlarmManager.RTC_WAKEUP: return mRtcWakeupAlarms;
@@ -778,6 +795,7 @@ class AlarmManagerService extends IAlarmManager.Stub {
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
filter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
+ filter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
filter.addDataScheme("package");
mContext.registerReceiver(this, filter);
// Register for events related to sdcard installation.
@@ -791,7 +809,16 @@ class AlarmManagerService extends IAlarmManager.Stub {
synchronized (mLock) {
String action = intent.getAction();
String pkgList[] = null;
- if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) {
+ if (Intent.ACTION_QUERY_PACKAGE_RESTART.equals(action)) {
+ pkgList = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES);
+ for (String packageName : pkgList) {
+ if (lookForPackageLocked(packageName)) {
+ setResultCode(Activity.RESULT_OK);
+ return;
+ }
+ }
+ return;
+ } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) {
pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
} else {
Uri data = intent.getData();
diff --git a/services/java/com/android/server/AppWidgetService.java b/services/java/com/android/server/AppWidgetService.java
index 0b466f1..a5b0db9 100644
--- a/services/java/com/android/server/AppWidgetService.java
+++ b/services/java/com/android/server/AppWidgetService.java
@@ -57,7 +57,7 @@ import java.util.HashSet;
import com.android.internal.appwidget.IAppWidgetService;
import com.android.internal.appwidget.IAppWidgetHost;
-import com.android.common.FastXmlSerializer;
+import com.android.internal.util.FastXmlSerializer;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java
index f79a02a..d4b28e2 100644
--- a/services/java/com/android/server/BackupManagerService.java
+++ b/services/java/com/android/server/BackupManagerService.java
@@ -1647,11 +1647,22 @@ class BackupManagerService extends IBackupManager.Stub {
}
if (metaInfo.versionCode > packageInfo.versionCode) {
- String message = "Version " + metaInfo.versionCode
- + " > installed version " + packageInfo.versionCode;
- Log.w(TAG, "Package " + packageName + ": " + message);
- EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE, packageName, message);
- continue;
+ // Data is from a "newer" version of the app than we have currently
+ // installed. If the app has not declared that it is prepared to
+ // handle this case, we do not attempt the restore.
+ if ((packageInfo.applicationInfo.flags
+ & ApplicationInfo.FLAG_RESTORE_ANY_VERSION) == 0) {
+ String message = "Version " + metaInfo.versionCode
+ + " > installed version " + packageInfo.versionCode;
+ Log.w(TAG, "Package " + packageName + ": " + message);
+ EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE,
+ packageName, message);
+ continue;
+ } else {
+ if (DEBUG) Log.v(TAG, "Version " + metaInfo.versionCode
+ + " > installed " + packageInfo.versionCode
+ + " but restoreAnyVersion");
+ }
}
if (!signaturesMatch(metaInfo.signatures, packageInfo)) {
@@ -1695,8 +1706,10 @@ class BackupManagerService extends IBackupManager.Stub {
// The agent was probably running with a stub Application object,
// which isn't a valid run mode for the main app logic. Shut
// down the app so that next time it's launched, it gets the
- // usual full initialization.
- if ((packageInfo.applicationInfo.flags
+ // usual full initialization. Note that this is only done for
+ // full-system restores: when a single app has requested a restore,
+ // it is explicitly not killed following that operation.
+ if (mTargetPackage == null && (packageInfo.applicationInfo.flags
& ApplicationInfo.FLAG_KILL_AFTER_RESTORE) != 0) {
if (DEBUG) Log.d(TAG, "Restore complete, killing host process of "
+ packageInfo.applicationInfo.processName);
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index 108246d..19f4b8a 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -289,6 +289,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
* the number of different network types is not going
* to change very often.
*/
+ boolean noMobileData = !getMobileDataEnabled();
for (int netType : mPriorityList) {
switch (mNetAttributes[netType].mRadio) {
case ConnectivityManager.TYPE_WIFI:
@@ -306,6 +307,10 @@ public class ConnectivityService extends IConnectivityManager.Stub {
mNetTrackers[netType] = new MobileDataStateTracker(context, mHandler,
netType, mNetAttributes[netType].mName);
mNetTrackers[netType].startMonitoring();
+ if (noMobileData) {
+ if (DBG) Log.d(TAG, "tearing down Mobile networks due to setting");
+ mNetTrackers[netType].teardown();
+ }
break;
default:
Log.e(TAG, "Trying to create a DataStateTracker for an unknown radio type " +
@@ -530,6 +535,10 @@ public class ConnectivityService extends IConnectivityManager.Stub {
// TODO - move this into the MobileDataStateTracker
int usedNetworkType = networkType;
if(networkType == ConnectivityManager.TYPE_MOBILE) {
+ if (!getMobileDataEnabled()) {
+ if (DBG) Log.d(TAG, "requested special network with data disabled - rejected");
+ return Phone.APN_TYPE_NOT_AVAILABLE;
+ }
if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_MMS)) {
usedNetworkType = ConnectivityManager.TYPE_MOBILE_MMS;
} else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_SUPL)) {
@@ -767,6 +776,46 @@ public class ConnectivityService extends IConnectivityManager.Stub {
mContext.sendBroadcast(broadcast);
}
+ /**
+ * @see ConnectivityManager#getMobileDataEnabled()
+ */
+ public boolean getMobileDataEnabled() {
+ enforceAccessPermission();
+ boolean retVal = Settings.Secure.getInt(mContext.getContentResolver(),
+ Settings.Secure.MOBILE_DATA, 1) == 1;
+ if (DBG) Log.d(TAG, "getMobileDataEnabled returning " + retVal);
+ return retVal;
+ }
+
+ /**
+ * @see ConnectivityManager#setMobileDataEnabled(boolean)
+ */
+ public synchronized void setMobileDataEnabled(boolean enabled) {
+ enforceChangePermission();
+ if (DBG) Log.d(TAG, "setMobileDataEnabled(" + enabled + ")");
+
+ if (getMobileDataEnabled() == enabled) return;
+
+ Settings.Secure.putInt(mContext.getContentResolver(),
+ Settings.Secure.MOBILE_DATA, enabled ? 1 : 0);
+
+ if (enabled) {
+ if (mNetTrackers[ConnectivityManager.TYPE_MOBILE] != null) {
+ if (DBG) Log.d(TAG, "starting up " + mNetTrackers[ConnectivityManager.TYPE_MOBILE]);
+ mNetTrackers[ConnectivityManager.TYPE_MOBILE].reconnect();
+ }
+ } else {
+ for (NetworkStateTracker nt : mNetTrackers) {
+ if (nt == null) continue;
+ int netType = nt.getNetworkInfo().getType();
+ if (mNetAttributes[netType].mRadio == ConnectivityManager.TYPE_MOBILE) {
+ if (DBG) Log.d(TAG, "tearing down " + nt);
+ nt.teardown();
+ }
+ }
+ }
+ }
+
private int getNumConnectedNetworks() {
int numConnectedNets = 0;
@@ -885,9 +934,18 @@ public class ConnectivityService extends IConnectivityManager.Stub {
int newType = -1;
int newPriority = -1;
+ boolean noMobileData = !getMobileDataEnabled();
for (int checkType=0; checkType <= ConnectivityManager.MAX_NETWORK_TYPE; checkType++) {
if (checkType == prevNetType) continue;
if (mNetAttributes[checkType] == null) continue;
+ if (mNetAttributes[checkType].mRadio == ConnectivityManager.TYPE_MOBILE &&
+ noMobileData) {
+ if (DBG) {
+ Log.d(TAG, "not failing over to mobile type " + checkType +
+ " because Mobile Data Disabled");
+ }
+ 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
diff --git a/services/java/com/android/server/DevicePolicyManagerService.java b/services/java/com/android/server/DevicePolicyManagerService.java
index a267e0f..9899e99 100644
--- a/services/java/com/android/server/DevicePolicyManagerService.java
+++ b/services/java/com/android/server/DevicePolicyManagerService.java
@@ -16,7 +16,9 @@
package com.android.server;
-import com.android.common.FastXmlSerializer;
+import com.android.internal.content.PackageMonitor;
+import com.android.internal.util.FastXmlSerializer;
+import com.android.internal.util.XmlUtils;
import com.android.internal.widget.LockPatternUtils;
import org.xmlpull.v1.XmlPullParser;
@@ -34,6 +36,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
+import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Binder;
import android.os.IBinder;
import android.os.IPowerManager;
@@ -58,9 +61,10 @@ import java.util.List;
* Implementation of the device policy APIs.
*/
public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
- private static final String TAG = "DevicePolicyManagerService";
+ static final String TAG = "DevicePolicyManagerService";
- private final Context mContext;
+ final Context mContext;
+ final MyPackageMonitor mMonitor;
IPowerManager mIPowerManager;
@@ -89,6 +93,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
void writeToXml(XmlSerializer out)
throws IllegalArgumentException, IllegalStateException, IOException {
+ out.startTag(null, "policies");
+ info.writePoliciesToXml(out);
+ out.endTag(null, "policies");
if (passwordQuality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
out.startTag(null, "password-quality");
out.attribute(null, "value", Integer.toString(passwordQuality));
@@ -121,7 +128,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
continue;
}
String tag = parser.getName();
- if ("password-quality".equals(tag)) {
+ if ("policies".equals(tag)) {
+ info.readPoliciesFromXml(parser);
+ } else if ("password-quality".equals(tag)) {
passwordQuality = Integer.parseInt(
parser.getAttributeValue(null, "value"));
} else if ("min-password-length".equals(tag)) {
@@ -133,6 +142,35 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
} else if ("max-failed-password-wipe".equals(tag)) {
maximumFailedPasswordsForWipe = Integer.parseInt(
parser.getAttributeValue(null, "value"));
+ } else {
+ Log.w(TAG, "Unknown admin tag: " + tag);
+ }
+ XmlUtils.skipCurrentTag(parser);
+ }
+ }
+ }
+
+ class MyPackageMonitor extends PackageMonitor {
+ public void onSomePackagesChanged() {
+ synchronized (DevicePolicyManagerService.this) {
+ for (int i=mAdminList.size()-1; i>=0; i--) {
+ ActiveAdmin aa = mAdminList.get(i);
+ int change = isPackageDisappearing(aa.info.getPackageName());
+ if (change == PACKAGE_PERMANENT_CHANGE
+ || change == PACKAGE_TEMPORARY_CHANGE) {
+ Log.w(TAG, "Admin unexpectedly uninstalled: "
+ + aa.info.getComponent());
+ mAdminList.remove(i);
+ } else if (isPackageModified(aa.info.getPackageName())) {
+ try {
+ mContext.getPackageManager().getReceiverInfo(
+ aa.info.getComponent(), 0);
+ } catch (NameNotFoundException e) {
+ Log.w(TAG, "Admin package change removed component: "
+ + aa.info.getComponent());
+ mAdminList.remove(i);
+ }
+ }
}
}
}
@@ -143,6 +181,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
*/
public DevicePolicyManagerService(Context context) {
mContext = context;
+ mMonitor = new MyPackageMonitor();
+ mMonitor.register(context, true);
}
private IPowerManager getIPowerManager() {
@@ -336,6 +376,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
} else if ("failed-password-attempts".equals(tag)) {
mFailedPasswordAttempts = Integer.parseInt(
parser.getAttributeValue(null, "value"));
+ XmlUtils.skipCurrentTag(parser);
+ } else {
+ Log.w(TAG, "Unknown tag: " + tag);
+ XmlUtils.skipCurrentTag(parser);
}
}
} catch (NullPointerException e) {
@@ -420,6 +464,18 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
}
+ public boolean packageHasActiveAdmins(String packageName) {
+ synchronized (this) {
+ final int N = mAdminList.size();
+ for (int i=0; i<N; i++) {
+ if (mAdminList.get(i).info.getPackageName().equals(packageName)) {
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+
public void removeActiveAdmin(ComponentName adminReceiver) {
synchronized (this) {
ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver);
diff --git a/services/java/com/android/server/DockObserver.java b/services/java/com/android/server/DockObserver.java
index 4791718..a0c850f 100644
--- a/services/java/com/android/server/DockObserver.java
+++ b/services/java/com/android/server/DockObserver.java
@@ -41,6 +41,7 @@ import android.location.LocationListener;
import android.location.LocationManager;
import android.location.LocationProvider;
import android.os.Binder;
+import android.media.AudioManager;
import android.media.Ringtone;
import android.media.RingtoneManager;
import android.net.Uri;
@@ -304,6 +305,14 @@ class DockObserver extends UEventObserver {
(KeyguardManager)mContext.getSystemService(Context.KEYGUARD_SERVICE);
mKeyguardLock = keyguardManager.newKeyguardLock(TAG);
+ final boolean enableCarMode = mDockState == Intent.EXTRA_DOCK_STATE_CAR;
+ if (enableCarMode) {
+ try {
+ setCarMode(enableCarMode);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Unable to change car mode.", e);
+ }
+ }
// don't bother broadcasting undocked here
if (mDockState != Intent.EXTRA_DOCK_STATE_UNDOCKED) {
update();
@@ -379,7 +388,10 @@ class DockObserver extends UEventObserver {
final Uri soundUri = Uri.parse("file://" + soundPath);
if (soundUri != null) {
final Ringtone sfx = RingtoneManager.getRingtone(mContext, soundUri);
- if (sfx != null) sfx.play();
+ if (sfx != null) {
+ sfx.setStreamType(AudioManager.STREAM_SYSTEM);
+ sfx.play();
+ }
}
}
}
@@ -412,7 +424,7 @@ class DockObserver extends UEventObserver {
mLocationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER,
LOCATION_UPDATE_MS, LOCATION_UPDATE_DISTANCE_METER, mLocationListener);
retrieveLocation();
- if (mLocation != null) {
+ if (mCarModeEnabled && mLocation != null && mNightMode == MODE_NIGHT_AUTO) {
try {
DockObserver.this.updateTwilight();
} catch (RemoteException e) {
@@ -458,8 +470,8 @@ class DockObserver extends UEventObserver {
if (location == null) {
Time currentTime = new Time();
currentTime.set(System.currentTimeMillis());
- double lngOffset = FACTOR_GMT_OFFSET_LONGITUDE * currentTime.gmtoff
- - (currentTime.isDst > 0 ? 3600 : 0);
+ double lngOffset = FACTOR_GMT_OFFSET_LONGITUDE *
+ (currentTime.gmtoff - (currentTime.isDst > 0 ? 3600 : 0));
location = new Location("fake");
location.setLongitude(lngOffset);
location.setLatitude(59.95);
@@ -583,20 +595,26 @@ class DockObserver extends UEventObserver {
}
// schedule next update
- final int mLastTwilightState = tw.mState;
- // add some extra time to be on the save side.
- long nextUpdate = DateUtils.MINUTE_IN_MILLIS;
- if (currentTime > tw.mSunset) {
- // next update should be on the following day
- tw.calculateTwilight(currentTime
- + DateUtils.DAY_IN_MILLIS, mLocation.getLatitude(),
- mLocation.getLongitude());
- }
-
- if (mLastTwilightState == TwilightCalculator.NIGHT) {
- nextUpdate += tw.mSunrise;
+ long nextUpdate = 0;
+ if (tw.mSunrise == -1 || tw.mSunset == -1) {
+ // In the case the day or night never ends the update is scheduled 12 hours later.
+ nextUpdate = currentTime + 12 * DateUtils.HOUR_IN_MILLIS;
} else {
- nextUpdate += tw.mSunset;
+ final int mLastTwilightState = tw.mState;
+ // add some extra time to be on the save side.
+ nextUpdate += DateUtils.MINUTE_IN_MILLIS;
+ if (currentTime > tw.mSunset) {
+ // next update should be on the following day
+ tw.calculateTwilight(currentTime
+ + DateUtils.DAY_IN_MILLIS, mLocation.getLatitude(),
+ mLocation.getLongitude());
+ }
+
+ if (mLastTwilightState == TwilightCalculator.NIGHT) {
+ nextUpdate += tw.mSunrise;
+ } else {
+ nextUpdate += tw.mSunset;
+ }
}
Intent updateIntent = new Intent(ACTION_UPDATE_NIGHT_MODE);
@@ -605,8 +623,11 @@ class DockObserver extends UEventObserver {
mAlarmManager.cancel(pendingIntent);
mAlarmManager.set(AlarmManager.RTC_WAKEUP, nextUpdate, pendingIntent);
- // set current mode
- setMode(Configuration.UI_MODE_TYPE_CAR, nightMode << 4);
+ // Make sure that we really set the new mode only if we're in car mode and
+ // automatic switching is enables.
+ if (mCarModeEnabled && mNightMode == MODE_NIGHT_AUTO) {
+ setMode(Configuration.UI_MODE_TYPE_CAR, nightMode << 4);
+ }
}
}
diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java
index 5e96a2f..59d4c9b 100644
--- a/services/java/com/android/server/InputMethodManagerService.java
+++ b/services/java/com/android/server/InputMethodManagerService.java
@@ -16,6 +16,7 @@
package com.android.server;
+import com.android.internal.content.PackageMonitor;
import com.android.internal.os.HandlerCaller;
import com.android.internal.view.IInputContext;
import com.android.internal.view.IInputMethod;
@@ -48,7 +49,6 @@ import android.content.pm.ServiceInfo;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.database.ContentObserver;
-import android.net.Uri;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
@@ -332,51 +332,68 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
}
}
- class PackageReceiver extends android.content.BroadcastReceiver {
+ class MyPackageMonitor extends PackageMonitor {
+
@Override
- public void onReceive(Context context, Intent intent) {
- String action = intent.getAction();
- String pkgList[] = null;
- if (Intent.ACTION_PACKAGE_ADDED.equals(action) ||
- Intent.ACTION_PACKAGE_REMOVED.equals(action)) {
- Uri uri = intent.getData();
- String pkg = uri != null ? uri.getSchemeSpecificPart() : null;
- if (pkg != null) {
- pkgList = new String[] { pkg };
+ public boolean onHandleForceStop(Intent intent, String[] packages, int uid, boolean doit) {
+ synchronized (mMethodMap) {
+ String curInputMethodId = Settings.Secure.getString(mContext
+ .getContentResolver(), Settings.Secure.DEFAULT_INPUT_METHOD);
+ final int N = mMethodList.size();
+ if (curInputMethodId != null) {
+ for (int i=0; i<N; i++) {
+ InputMethodInfo imi = mMethodList.get(i);
+ if (imi.getId().equals(curInputMethodId)) {
+ for (String pkg : packages) {
+ if (imi.getPackageName().equals(pkg)) {
+ if (!doit) {
+ return true;
+ }
+
+ Settings.Secure.putString(mContext.getContentResolver(),
+ Settings.Secure.DEFAULT_INPUT_METHOD, "");
+ chooseNewDefaultIMELocked();
+ return true;
+ }
+ }
+ }
+ }
}
- } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(action) ||
- Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) {
- pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
}
- if (pkgList == null || pkgList.length == 0) {
- return;
- }
- synchronized (mMethodMap) {
- buildInputMethodListLocked(mMethodList, mMethodMap);
+ return false;
+ }
+ @Override
+ public void onSomePackagesChanged() {
+ synchronized (mMethodMap) {
InputMethodInfo curIm = null;
- String curInputMethodId = Settings.Secure.getString(context
+ String curInputMethodId = Settings.Secure.getString(mContext
.getContentResolver(), Settings.Secure.DEFAULT_INPUT_METHOD);
final int N = mMethodList.size();
if (curInputMethodId != null) {
for (int i=0; i<N; i++) {
- if (mMethodList.get(i).getId().equals(curInputMethodId)) {
- curIm = mMethodList.get(i);
+ InputMethodInfo imi = mMethodList.get(i);
+ if (imi.getId().equals(curInputMethodId)) {
+ curIm = imi;
+ }
+ int change = isPackageDisappearing(imi.getPackageName());
+ if (change == PACKAGE_TEMPORARY_CHANGE
+ || change == PACKAGE_PERMANENT_CHANGE) {
+ Log.i(TAG, "Input method uninstalled, disabling: "
+ + imi.getComponent());
+ setInputMethodEnabledLocked(imi.getId(), false);
}
}
}
+ buildInputMethodListLocked(mMethodList, mMethodMap);
+
boolean changed = false;
if (curIm != null) {
- boolean foundPkg = false;
- for (String pkg : pkgList) {
- if (curIm.getPackageName().equals(pkg)) {
- foundPkg = true;
- break;
- }
- }
- if (foundPkg) {
+ int change = isPackageDisappearing(curIm.getPackageName());
+ if (change == PACKAGE_TEMPORARY_CHANGE
+ || change == PACKAGE_PERMANENT_CHANGE) {
ServiceInfo si = null;
try {
si = mContext.getPackageManager().getServiceInfo(
@@ -387,7 +404,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
// Uh oh, current input method is no longer around!
// Pick another one...
Log.i(TAG, "Current input method removed: " + curInputMethodId);
- if (!chooseNewDefaultIME()) {
+ if (!chooseNewDefaultIMELocked()) {
changed = true;
curIm = null;
curInputMethodId = "";
@@ -397,16 +414,17 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
curInputMethodId);
}
}
-
- } else if (curIm == null) {
- // We currently don't have a default input method... is
- // one now available?
- changed = chooseNewDefaultIME();
}
+ }
+
+ if (curIm == null) {
+ // We currently don't have a default input method... is
+ // one now available?
+ changed = chooseNewDefaultIMELocked();
+ }
- if (changed) {
- updateFromSettingsLocked();
- }
+ if (changed) {
+ updateFromSettingsLocked();
}
}
}
@@ -438,19 +456,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
}
});
- PackageReceiver mBroadcastReceiver = new PackageReceiver();
- IntentFilter packageFilt = new IntentFilter();
- packageFilt.addAction(Intent.ACTION_PACKAGE_ADDED);
- packageFilt.addAction(Intent.ACTION_PACKAGE_CHANGED);
- packageFilt.addAction(Intent.ACTION_PACKAGE_REMOVED);
- packageFilt.addAction(Intent.ACTION_PACKAGE_RESTARTED);
- packageFilt.addDataScheme("package");
- mContext.registerReceiver(mBroadcastReceiver, packageFilt);
- // Register for events related to sdcard installation.
- IntentFilter sdFilter = new IntentFilter();
- sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
- sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
- mContext.registerReceiver(mBroadcastReceiver, sdFilter);
+ (new MyPackageMonitor()).register(mContext, true);
IntentFilter screenOnOffFilt = new IntentFilter();
screenOnOffFilt.addAction(Intent.ACTION_SCREEN_ON);
@@ -1385,7 +1391,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
& ApplicationInfo.FLAG_SYSTEM) != 0;
}
- private boolean chooseNewDefaultIME() {
+ private boolean chooseNewDefaultIMELocked() {
List<InputMethodInfo> enabled = getEnabledInputMethodListLocked();
if (enabled != null && enabled.size() > 0) {
Settings.Secure.putString(mContext.getContentResolver(),
@@ -1446,7 +1452,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
String defaultIme = Settings.Secure.getString(mContext
.getContentResolver(), Settings.Secure.DEFAULT_INPUT_METHOD);
if (!map.containsKey(defaultIme)) {
- if (chooseNewDefaultIME()) {
+ if (chooseNewDefaultIMELocked()) {
updateFromSettingsLocked();
}
}
@@ -1557,90 +1563,94 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
"Requires permission "
+ android.Manifest.permission.WRITE_SECURE_SETTINGS);
}
-
+
long ident = Binder.clearCallingIdentity();
try {
- // Make sure this is a valid input method.
- InputMethodInfo imm = mMethodMap.get(id);
- if (imm == null) {
- if (imm == null) {
- throw new IllegalArgumentException("Unknown id: " + mCurMethodId);
- }
- }
+ return setInputMethodEnabledLocked(id, enabled);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+ }
+
+ boolean setInputMethodEnabledLocked(String id, boolean enabled) {
+ // Make sure this is a valid input method.
+ InputMethodInfo imm = mMethodMap.get(id);
+ if (imm == null) {
+ if (imm == null) {
+ throw new IllegalArgumentException("Unknown id: " + mCurMethodId);
+ }
+ }
- StringBuilder builder = new StringBuilder(256);
-
- boolean removed = false;
- String firstId = null;
-
- // Look through the currently enabled input methods.
- String enabledStr = Settings.Secure.getString(mContext.getContentResolver(),
- Settings.Secure.ENABLED_INPUT_METHODS);
- if (enabledStr != null) {
- final TextUtils.SimpleStringSplitter splitter = mStringColonSplitter;
- splitter.setString(enabledStr);
- while (splitter.hasNext()) {
- String curId = splitter.next();
- if (curId.equals(id)) {
- if (enabled) {
- // We are enabling this input method, but it is
- // already enabled. Nothing to do. The previous
- // state was enabled.
- return true;
- }
- // We are disabling this input method, and it is
- // currently enabled. Skip it to remove from the
- // new list.
- removed = true;
- } else if (!enabled) {
- // We are building a new list of input methods that
- // doesn't contain the given one.
- if (firstId == null) firstId = curId;
- if (builder.length() > 0) builder.append(':');
- builder.append(curId);
- }
- }
- }
+ StringBuilder builder = new StringBuilder(256);
- if (!enabled) {
- if (!removed) {
- // We are disabling the input method but it is already
- // disabled. Nothing to do. The previous state was
- // disabled.
- return false;
- }
- // Update the setting with the new list of input methods.
- Settings.Secure.putString(mContext.getContentResolver(),
- Settings.Secure.ENABLED_INPUT_METHODS, builder.toString());
- // We the disabled input method is currently selected, switch
- // to another one.
- String selId = Settings.Secure.getString(mContext.getContentResolver(),
- Settings.Secure.DEFAULT_INPUT_METHOD);
- if (id.equals(selId)) {
- Settings.Secure.putString(mContext.getContentResolver(),
- Settings.Secure.DEFAULT_INPUT_METHOD,
- firstId != null ? firstId : "");
- }
- // Previous state was enabled.
- return true;
- }
+ boolean removed = false;
+ String firstId = null;
- // Add in the newly enabled input method.
- if (enabledStr == null || enabledStr.length() == 0) {
- enabledStr = id;
- } else {
- enabledStr = enabledStr + ':' + id;
+ // Look through the currently enabled input methods.
+ String enabledStr = Settings.Secure.getString(mContext.getContentResolver(),
+ Settings.Secure.ENABLED_INPUT_METHODS);
+ if (enabledStr != null) {
+ final TextUtils.SimpleStringSplitter splitter = mStringColonSplitter;
+ splitter.setString(enabledStr);
+ while (splitter.hasNext()) {
+ String curId = splitter.next();
+ if (curId.equals(id)) {
+ if (enabled) {
+ // We are enabling this input method, but it is
+ // already enabled. Nothing to do. The previous
+ // state was enabled.
+ return true;
+ }
+ // We are disabling this input method, and it is
+ // currently enabled. Skip it to remove from the
+ // new list.
+ removed = true;
+ } else if (!enabled) {
+ // We are building a new list of input methods that
+ // doesn't contain the given one.
+ if (firstId == null) firstId = curId;
+ if (builder.length() > 0) builder.append(':');
+ builder.append(curId);
}
+ }
+ }
- Settings.Secure.putString(mContext.getContentResolver(),
- Settings.Secure.ENABLED_INPUT_METHODS, enabledStr);
-
- // Previous state was disabled.
+ if (!enabled) {
+ if (!removed) {
+ // We are disabling the input method but it is already
+ // disabled. Nothing to do. The previous state was
+ // disabled.
return false;
- } finally {
- Binder.restoreCallingIdentity(ident);
}
+ // Update the setting with the new list of input methods.
+ Settings.Secure.putString(mContext.getContentResolver(),
+ Settings.Secure.ENABLED_INPUT_METHODS, builder.toString());
+ // We the disabled input method is currently selected, switch
+ // to another one.
+ String selId = Settings.Secure.getString(mContext.getContentResolver(),
+ Settings.Secure.DEFAULT_INPUT_METHOD);
+ if (id.equals(selId)) {
+ Settings.Secure.putString(mContext.getContentResolver(),
+ Settings.Secure.DEFAULT_INPUT_METHOD,
+ firstId != null ? firstId : "");
+ }
+ // Previous state was enabled.
+ return true;
+ }
+
+ // Add in the newly enabled input method.
+ if (enabledStr == null || enabledStr.length() == 0) {
+ enabledStr = id;
+ } else {
+ enabledStr = enabledStr + ':' + id;
}
+
+ Settings.Secure.putString(mContext.getContentResolver(),
+ Settings.Secure.ENABLED_INPUT_METHODS, enabledStr);
+
+ // Previous state was disabled.
+ return false;
}
// ----------------------------------------------------------------------
diff --git a/services/java/com/android/server/KeyInputQueue.java b/services/java/com/android/server/KeyInputQueue.java
index 2640cfb..1bb897b 100644
--- a/services/java/com/android/server/KeyInputQueue.java
+++ b/services/java/com/android/server/KeyInputQueue.java
@@ -32,7 +32,7 @@ import android.view.RawInputEvent;
import android.view.Surface;
import android.view.WindowManagerPolicy;
-import com.android.common.XmlUtils;
+import com.android.internal.util.XmlUtils;
import org.xmlpull.v1.XmlPullParser;
diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java
index 004fcf1..c0dcdf9 100644
--- a/services/java/com/android/server/LocationManagerService.java
+++ b/services/java/com/android/server/LocationManagerService.java
@@ -27,6 +27,7 @@ import java.util.Observable;
import java.util.Observer;
import java.util.Set;
+import android.app.Activity;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
@@ -484,14 +485,17 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
super();
mContext = context;
- Thread thread = new Thread(null, this, "LocationManagerService");
- thread.start();
-
if (LOCAL_LOGV) {
Log.v(TAG, "Constructed LocationManager Service");
}
}
+ void systemReady() {
+ // we defer starting up the service until the system is ready
+ Thread thread = new Thread(null, this, "LocationManagerService");
+ thread.start();
+ }
+
private void initialize() {
// Create a wake lock, needs to be done before calling loadProviders() below
PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
@@ -506,6 +510,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
// Register for Package Manager updates
intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
intentFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
+ intentFilter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
mContext.registerReceiver(mBroadcastReceiver, intentFilter);
IntentFilter sdFilter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
mContext.registerReceiver(mBroadcastReceiver, sdFilter);
@@ -1539,8 +1544,9 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
-
- if (action.equals(Intent.ACTION_PACKAGE_REMOVED)
+ boolean queryRestart = action.equals(Intent.ACTION_QUERY_PACKAGE_RESTART);
+ if (queryRestart
+ || action.equals(Intent.ACTION_PACKAGE_REMOVED)
|| action.equals(Intent.ACTION_PACKAGE_RESTARTED)
|| action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) {
synchronized (mLock) {
@@ -1560,6 +1566,10 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
for (int j=i.size()-1; j>=0; j--) {
UpdateRecord ur = i.get(j);
if (ur.mReceiver.isPendingIntent() && ur.mUid == uid) {
+ if (queryRestart) {
+ setResultCode(Activity.RESULT_OK);
+ return;
+ }
if (removedRecs == null) {
removedRecs = new ArrayList<Receiver>();
}
@@ -1572,6 +1582,10 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
ArrayList<ProximityAlert> removedAlerts = null;
for (ProximityAlert i : mProximityAlerts.values()) {
if (i.mUid == uid) {
+ if (queryRestart) {
+ setResultCode(Activity.RESULT_OK);
+ return;
+ }
if (removedAlerts == null) {
removedAlerts = new ArrayList<ProximityAlert>();
}
diff --git a/services/java/com/android/server/MountService.java b/services/java/com/android/server/MountService.java
index 2a78806..4485c79 100644
--- a/services/java/com/android/server/MountService.java
+++ b/services/java/com/android/server/MountService.java
@@ -16,32 +16,29 @@
package com.android.server;
+import com.android.server.am.ActivityManagerService;
+
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
-import android.content.res.Resources;
import android.net.Uri;
import android.os.storage.IMountService;
import android.os.storage.IMountServiceListener;
import android.os.storage.StorageResultCode;
+import android.os.Handler;
+import android.os.Message;
import android.os.RemoteException;
import android.os.IBinder;
import android.os.Environment;
import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.SystemProperties;
-import android.os.UEventObserver;
-import android.os.Handler;
-import android.text.TextUtils;
import android.util.Log;
import java.util.ArrayList;
import java.util.HashSet;
-import java.io.File;
-import java.io.FileReader;
-
/**
* MountService implements back-end services for platform storage
* management.
@@ -115,14 +112,119 @@ class MountService extends IMountService.Stub
private PackageManagerService mPms;
private boolean mUmsEnabling;
private ArrayList<MountServiceBinderListener> mListeners;
- private boolean mBooted;
- private boolean mReady;
+ private boolean mBooted = false;
+ private boolean mReady = false;
+ private boolean mSendUmsConnectedOnBoot = false;
/**
* Private hash of currently mounted secure containers.
*/
private HashSet<String> mAsecMountSet = new HashSet<String>();
+ private static final int H_UNMOUNT_PM_UPDATE = 1;
+ private static final int H_UNMOUNT_PM_DONE = 2;
+ private static final int H_UNMOUNT_MS = 3;
+ private static final int RETRY_UNMOUNT_DELAY = 30; // in ms
+ private static final int MAX_UNMOUNT_RETRIES = 4;
+
+ private IntentFilter mPmFilter = new IntentFilter(
+ Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
+ private BroadcastReceiver mPmReceiver = new BroadcastReceiver() {
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) {
+ mHandler.sendEmptyMessage(H_UNMOUNT_PM_DONE);
+ }
+ }
+ };
+
+ class UnmountCallBack {
+ String path;
+ int retries;
+ boolean force;
+
+ UnmountCallBack(String path, boolean force) {
+ retries = 0;
+ this.path = path;
+ this.force = force;
+ }
+ }
+
+ final private Handler mHandler = new Handler() {
+ ArrayList<UnmountCallBack> mForceUnmounts = new ArrayList<UnmountCallBack>();
+
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case H_UNMOUNT_PM_UPDATE: {
+ UnmountCallBack ucb = (UnmountCallBack) msg.obj;
+ mForceUnmounts.add(ucb);
+ mContext.registerReceiver(mPmReceiver, mPmFilter);
+ boolean hasExtPkgs = mPms.updateExternalMediaStatus(false);
+ if (!hasExtPkgs) {
+ // Unregister right away
+ mHandler.sendEmptyMessage(H_UNMOUNT_PM_DONE);
+ }
+ break;
+ }
+ case H_UNMOUNT_PM_DONE: {
+ // Unregister receiver
+ mContext.unregisterReceiver(mPmReceiver);
+ UnmountCallBack ucb = mForceUnmounts.get(0);
+ if (ucb == null || ucb.path == null) {
+ // Just ignore
+ return;
+ }
+ String path = ucb.path;
+ boolean done = false;
+ if (!ucb.force) {
+ done = true;
+ } else {
+ int pids[] = getStorageUsers(path);
+ if (pids == null || pids.length == 0) {
+ done = true;
+ } else {
+ // Kill processes holding references first
+ ActivityManagerService ams = (ActivityManagerService)
+ ServiceManager.getService("activity");
+ // Eliminate system process here?
+ boolean ret = ams.killPidsForMemory(pids);
+ if (ret) {
+ // Confirm if file references have been freed.
+ pids = getStorageUsers(path);
+ if (pids == null || pids.length == 0) {
+ done = true;
+ }
+ }
+ }
+ }
+ if (done) {
+ mForceUnmounts.remove(0);
+ mHandler.sendMessage(mHandler.obtainMessage(H_UNMOUNT_MS,
+ ucb));
+ } else {
+ if (ucb.retries >= MAX_UNMOUNT_RETRIES) {
+ Log.i(TAG, "Cannot unmount inspite of " +
+ MAX_UNMOUNT_RETRIES + " to unmount media");
+ // Send final broadcast indicating failure to unmount.
+ } else {
+ mHandler.sendMessageDelayed(
+ mHandler.obtainMessage(H_UNMOUNT_PM_DONE,
+ ucb.retries++),
+ RETRY_UNMOUNT_DELAY);
+ }
+ }
+ break;
+ }
+ case H_UNMOUNT_MS : {
+ UnmountCallBack ucb = (UnmountCallBack) msg.obj;
+ String path = ucb.path;
+ doUnmountVolume(path, true);
+ break;
+ }
+ }
+ }
+ };
+
private void waitForReady() {
while (mReady == false) {
for (int retries = 5; retries > 0; retries--) {
@@ -162,6 +264,14 @@ class MountService extends IMountService.Stub
Log.e(TAG, String.format("Boot-time mount failed (%d)", rc));
}
}
+ /*
+ * If UMS is connected in boot, send the connected event
+ * now that we're up.
+ */
+ if (mSendUmsConnectedOnBoot) {
+ sendUmsIntent(true);
+ mSendUmsConnectedOnBoot = false;
+ }
} catch (Exception ex) {
Log.e(TAG, "Boot-time mount exception", ex);
}
@@ -202,7 +312,7 @@ class MountService extends IMountService.Stub
String vs = getVolumeState(path);
if (enable && vs.equals(Environment.MEDIA_MOUNTED)) {
mUmsEnabling = enable; // Override for isUsbMassStorageEnabled()
- int rc = doUnmountVolume(path, false);
+ int rc = doUnmountVolume(path, true);
mUmsEnabling = false; // Clear override
if (rc != StorageResultCode.OperationSucceeded) {
Log.e(TAG, String.format("Failed to unmount before enabling UMS (%d)", rc));
@@ -545,14 +655,28 @@ class MountService extends IMountService.Stub
return rc;
}
+ /*
+ * If force is not set, we do not unmount if there are
+ * processes holding references to the volume about to be unmounted.
+ * If force is set, all the processes holding references need to be
+ * killed via the ActivityManager before actually unmounting the volume.
+ * This might even take a while and might be retried after timed delays
+ * to make sure we dont end up in an instable state and kill some core
+ * processes.
+ */
private int doUnmountVolume(String path, boolean force) {
if (!getVolumeState(path).equals(Environment.MEDIA_MOUNTED)) {
return VoldResponseCode.OpFailedVolNotMounted;
}
+ // We unmounted the volume. No of the asec containers are available now.
+ synchronized (mAsecMountSet) {
+ mAsecMountSet.clear();
+ }
// Notify PackageManager of potential media removal and deal with
// return code later on. The caller of this api should be aware or have been
// notified that the applications installed on the media will be killed.
+ // Redundant probably. But no harm in updating state again.
mPms.updateExternalMediaStatus(false);
try {
mConnector.doCommand(String.format(
@@ -636,16 +760,17 @@ class MountService extends IMountService.Stub
}
if (mBooted == true) {
- Intent intent;
- if (avail) {
- intent = new Intent(Intent.ACTION_UMS_CONNECTED);
- } else {
- intent = new Intent(Intent.ACTION_UMS_DISCONNECTED);
- }
- mContext.sendBroadcast(intent);
+ sendUmsIntent(avail);
+ } else {
+ mSendUmsConnectedOnBoot = avail;
}
}
+ private void sendUmsIntent(boolean c) {
+ mContext.sendBroadcast(
+ new Intent((c ? Intent.ACTION_UMS_CONNECTED : Intent.ACTION_UMS_DISCONNECTED)));
+ }
+
private void validatePermission(String perm) {
if (mContext.checkCallingOrSelfPermission(perm) != PackageManager.PERMISSION_GRANTED) {
throw new SecurityException(String.format("Requires %s permission", perm));
@@ -804,11 +929,12 @@ class MountService extends IMountService.Stub
return doMountVolume(path);
}
- public int unmountVolume(String path, boolean force) {
+ public void unmountVolume(String path, boolean force) {
validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
waitForReady();
- return doUnmountVolume(path, force);
+ UnmountCallBack ucb = new UnmountCallBack(path, force);
+ mHandler.sendMessage(mHandler.obtainMessage(H_UNMOUNT_PM_UPDATE, ucb));
}
public int formatVolume(String path) {
@@ -1003,7 +1129,11 @@ class MountService extends IMountService.Stub
warnOnNotMounted();
synchronized (mAsecMountSet) {
- if (mAsecMountSet.contains(oldId)) {
+ /*
+ * Because a mounted container has active internal state which cannot be
+ * changed while active, we must ensure both ids are not currently mounted.
+ */
+ if (mAsecMountSet.contains(oldId) || mAsecMountSet.contains(newId)) {
return StorageResultCode.OperationFailedStorageMounted;
}
}
@@ -1015,6 +1145,13 @@ class MountService extends IMountService.Stub
} catch (NativeDaemonConnectorException e) {
rc = StorageResultCode.OperationFailedInternalError;
}
+ if (rc == StorageResultCode.OperationSucceeded) {
+ synchronized (mAsecMountSet) {
+ if (!mAsecMountSet.contains(newId)) {
+ mAsecMountSet.add(newId);
+ }
+ }
+ }
return rc;
}
diff --git a/services/java/com/android/server/NetworkManagementService.java b/services/java/com/android/server/NetworkManagementService.java
index 958d089..7c555e2 100644
--- a/services/java/com/android/server/NetworkManagementService.java
+++ b/services/java/com/android/server/NetworkManagementService.java
@@ -256,14 +256,14 @@ class NetworkManagementService extends INetworkManagementService.Stub {
Log.e(TAG, "Failed to parse netmask", uhe);
cfg.netmask = 0;
}
- cfg.interfaceFlags = st.nextToken("]");
+ cfg.interfaceFlags = st.nextToken("]").trim() +"]";
Log.d(TAG, String.format("flags <%s>", cfg.interfaceFlags));
return cfg;
}
public void setInterfaceConfig(
String iface, InterfaceConfiguration cfg) throws IllegalStateException {
- String cmd = String.format("interface setcfg %s %s %s", iface,
+ String cmd = String.format("interface setcfg %s %s %s %s", iface,
intToIpString(cfg.ipAddr), intToIpString(cfg.netmask), cfg.interfaceFlags);
mConnector.doCommand(cmd);
}
diff --git a/services/java/com/android/server/NotificationManagerService.java b/services/java/com/android/server/NotificationManagerService.java
index 3657133..3c43352 100755
--- a/services/java/com/android/server/NotificationManagerService.java
+++ b/services/java/com/android/server/NotificationManagerService.java
@@ -307,6 +307,8 @@ class NotificationManagerService extends INotificationManager.Stub
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
+ boolean queryRestart = false;
+
if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {
boolean batteryCharging = (intent.getIntExtra("plugged", 0) != 0);
int level = intent.getIntExtra("level", -1);
@@ -330,10 +332,13 @@ class NotificationManagerService extends INotificationManager.Stub
updateAdbNotification();
} else if (action.equals(Intent.ACTION_PACKAGE_REMOVED)
|| action.equals(Intent.ACTION_PACKAGE_RESTARTED)
+ || (queryRestart=action.equals(Intent.ACTION_QUERY_PACKAGE_RESTART))
|| action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) {
String pkgList[] = null;
if (action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) {
pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
+ } else if (queryRestart) {
+ pkgList = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES);
} else {
Uri uri = intent.getData();
if (uri == null) {
@@ -347,7 +352,7 @@ class NotificationManagerService extends INotificationManager.Stub
}
if (pkgList != null && (pkgList.length > 0)) {
for (String pkgName : pkgList) {
- cancelAllNotificationsInt(pkgName, 0, 0);
+ cancelAllNotificationsInt(pkgName, 0, 0, !queryRestart);
}
}
} else if (action.equals(Intent.ACTION_SCREEN_ON)) {
@@ -436,11 +441,15 @@ class NotificationManagerService extends INotificationManager.Stub
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);
filter.addAction(Intent.ACTION_SCREEN_ON);
filter.addAction(Intent.ACTION_SCREEN_OFF);
mContext.registerReceiver(mIntentReceiver, filter);
+ IntentFilter pkgFilter = new IntentFilter();
+ pkgFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+ pkgFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
+ pkgFilter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
+ pkgFilter.addDataScheme("package");
+ mContext.registerReceiver(mIntentReceiver, pkgFilter);
IntentFilter sdFilter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
mContext.registerReceiver(mIntentReceiver, sdFilter);
@@ -920,8 +929,8 @@ class NotificationManagerService extends INotificationManager.Stub
* Cancels all notifications from a given package that have all of the
* {@code mustHaveFlags}.
*/
- void cancelAllNotificationsInt(String pkg, int mustHaveFlags,
- int mustNotHaveFlags) {
+ boolean cancelAllNotificationsInt(String pkg, int mustHaveFlags,
+ int mustNotHaveFlags, boolean doit) {
EventLog.writeEvent(EventLogTags.NOTIFICATION_CANCEL_ALL, pkg, mustHaveFlags);
synchronized (mNotificationList) {
@@ -938,13 +947,17 @@ class NotificationManagerService extends INotificationManager.Stub
if (!r.pkg.equals(pkg)) {
continue;
}
+ canceledSomething = true;
+ if (!doit) {
+ return true;
+ }
mNotificationList.remove(i);
cancelNotificationLocked(r);
- canceledSomething = true;
}
if (canceledSomething) {
updateLightsLocked();
}
+ return canceledSomething;
}
}
@@ -966,7 +979,7 @@ class NotificationManagerService extends INotificationManager.Stub
// Calling from user space, don't allow the canceling of actively
// running foreground services.
- cancelAllNotificationsInt(pkg, 0, Notification.FLAG_FOREGROUND_SERVICE);
+ cancelAllNotificationsInt(pkg, 0, Notification.FLAG_FOREGROUND_SERVICE, true);
}
void checkIncomingCall(String pkg) {
diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java
index 38d8615..63fdaef 100644
--- a/services/java/com/android/server/PackageManagerService.java
+++ b/services/java/com/android/server/PackageManagerService.java
@@ -18,9 +18,9 @@ package com.android.server;
import com.android.internal.app.IMediaContainerService;
import com.android.internal.app.ResolverActivity;
-import com.android.common.FastXmlSerializer;
-import com.android.common.XmlUtils;
import com.android.internal.content.PackageHelper;
+import com.android.internal.util.FastXmlSerializer;
+import com.android.internal.util.XmlUtils;
import com.android.server.JournaledFile;
import org.xmlpull.v1.XmlPullParser;
@@ -28,7 +28,9 @@ import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;
import android.app.ActivityManagerNative;
+import android.app.DevicePolicyManager;
import android.app.IActivityManager;
+import android.app.IDevicePolicyManager;
import android.backup.IBackupManager;
import android.content.ComponentName;
import android.content.Context;
@@ -4856,42 +4858,67 @@ class PackageManagerService extends IPackageManager.Stub {
String oldCodePath) {
String newCacheId = getNextCodePath(oldCodePath, pkgName, "/" + RES_FILE_NAME);
String newCachePath = null;
- final int RENAME_FAILED = 1;
- final int MOUNT_FAILED = 2;
- final int PASS = 4;
- int errCode = RENAME_FAILED;
- String errMsg = "RENAME_FAILED";
- boolean mounted = PackageHelper.isContainerMounted(cid);
- if (mounted) {
- // Unmount the container
- if (!PackageHelper.unMountSdDir(cid)) {
- Log.i(TAG, "Failed to unmount " + cid + " before renaming");
+ boolean enableRename = false;
+ if (enableRename) {
+ if (PackageHelper.isContainerMounted(cid)) {
+ // Unmount the container
+ if (!PackageHelper.unMountSdDir(cid)) {
+ Log.i(TAG, "Failed to unmount " + cid + " before renaming");
+ return false;
+ }
+ }
+ if (!PackageHelper.renameSdDir(cid, newCacheId)) {
+ Log.e(TAG, "Failed to rename " + cid + " to " + newCacheId);
return false;
}
- mounted = false;
- }
- if (PackageHelper.renameSdDir(cid, newCacheId)) {
- errCode = MOUNT_FAILED;
- errMsg = "MOUNT_FAILED";
- if ((newCachePath = PackageHelper.mountSdDir(newCacheId,
- getEncryptKey(), Process.SYSTEM_UID)) != null) {
- errCode = PASS;
- errMsg = "PASS";
+ if (!PackageHelper.isContainerMounted(newCacheId)) {
+ Log.w(TAG, "Mounting container " + newCacheId);
+ newCachePath = PackageHelper.mountSdDir(newCacheId,
+ getEncryptKey(), Process.SYSTEM_UID);
+ } else {
+ newCachePath = PackageHelper.getSdDir(newCacheId);
+ }
+ if (newCachePath == null) {
+ Log.w(TAG, "Failed to get cache path for " + newCacheId);
+ return false;
}
- }
- if (errCode != PASS) {
- Log.i(TAG, "Failed to rename " + cid + " to " + newCacheId +
- " at path: " + cachePath + " to new path: " + newCachePath +
- "err = " + errMsg);
// Mount old container?
- return false;
+ Log.i(TAG, "Succesfully renamed " + cid +
+ " at path: " + cachePath + " to " + newCacheId +
+ " at new path: " + newCachePath);
+ cid = newCacheId;
+ cachePath = newCachePath;
+ return true;
} else {
- Log.i(TAG, "Succesfully renamed " + cid + " to " + newCacheId +
- " at path: " + cachePath + " to new path: " + newCachePath);
+ // STOPSHIP work around for rename
+ Log.i(TAG, "Copying instead of renaming");
+ File srcFile = new File(getCodePath());
+ // Create new container
+ newCachePath = PackageHelper.createSdDir(srcFile, newCacheId,
+ getEncryptKey(), Process.SYSTEM_UID);
+ Log.i(TAG, "Created rename container " + newCacheId);
+ File destFile = new File(newCachePath + "/" + RES_FILE_NAME);
+ if (!FileUtils.copyFile(srcFile, destFile)) {
+ Log.e(TAG, "Failed to copy " + srcFile + " to " + destFile);
+ return false;
+ }
+ Log.i(TAG, "Successfully copied resource to " + newCachePath);
+ if (!PackageHelper.finalizeSdDir(newCacheId)) {
+ Log.e(TAG, "Failed to finalize " + newCacheId);
+ PackageHelper.destroySdDir(newCacheId);
+ return false;
+ }
+ Log.i(TAG, "Finalized " + newCacheId);
+ Runtime.getRuntime().gc();
+ // Unmount first
+ PackageHelper.unMountSdDir(cid);
+ // Delete old container
+ PackageHelper.destroySdDir(cid);
+ // Dont have to mount. Already mounted.
+ cid = newCacheId;
+ cachePath = newCachePath;
+ return true;
}
- cid = newCacheId;
- cachePath = newCachePath;
- return true;
}
int doPostInstall(int status) {
@@ -5401,6 +5428,7 @@ class PackageManagerService extends IPackageManager.Stub {
res.returnCode = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
return;
}
+
if (!args.doRename(res.returnCode, pkgName, oldCodePath)) {
res.returnCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
return;
@@ -5594,6 +5622,16 @@ class PackageManagerService extends IPackageManager.Stub {
PackageRemovedInfo info = new PackageRemovedInfo();
boolean res;
+ IDevicePolicyManager dpm = IDevicePolicyManager.Stub.asInterface(
+ ServiceManager.getService(Context.DEVICE_POLICY_SERVICE));
+ try {
+ if (dpm != null && dpm.packageHasActiveAdmins(packageName)) {
+ Log.w(TAG, "Not removing package " + packageName + ": has active device admin");
+ return false;
+ }
+ } catch (RemoteException e) {
+ }
+
synchronized (mInstallLock) {
res = deletePackageLI(packageName, deleteCodeAndResources, flags, info);
}
@@ -5692,6 +5730,18 @@ class PackageManagerService extends IPackageManager.Stub {
// remove permissions associated with package
mSettings.updateSharedUserPermsLP(deletedPs, mGlobalGids);
}
+ if (deletedPs != null) {
+ // remove from preferred activities.
+ ArrayList<PreferredActivity> removed = new ArrayList<PreferredActivity>();
+ for (PreferredActivity pa : mSettings.mPreferredActivities.filterSet()) {
+ if (pa.mActivity.getPackageName().equals(deletedPs.name)) {
+ removed.add(pa);
+ }
+ }
+ for (PreferredActivity pa : removed) {
+ mSettings.mPreferredActivities.removeFilter(pa);
+ }
+ }
// Save settings now
mSettings.writeLP();
}
@@ -7449,9 +7499,9 @@ class PackageManagerService extends IPackageManager.Stub {
Log.w(TAG, "Trying to update system app code path from " +
p.codePathString + " to " + codePath.toString());
} else {
- // Let the app continue with previous uid if code path changes.
- reportSettingsProblem(Log.WARN,
- "Package " + name + " codePath changed from " + p.codePath
+ // Just a change in the code path is not an issue, but
+ // let's log a message about it.
+ Log.i(TAG, "Package " + name + " codePath changed from " + p.codePath
+ " to " + codePath + "; Retaining data and using new");
}
}
@@ -8785,7 +8835,7 @@ class PackageManagerService extends IPackageManager.Stub {
}
static String getTempContainerId() {
- String prefix = "smdl1tmp";
+ String prefix = "smdl2tmp";
int tmpIdx = 1;
String list[] = PackageHelper.getSecureContainerList();
if (list != null) {
@@ -8827,30 +8877,56 @@ class PackageManagerService extends IPackageManager.Stub {
return prefix + tmpIdx;
}
- public void updateExternalMediaStatus(final boolean mediaStatus) {
+ /*
+ * Return true if PackageManager does have packages to be updated.
+ */
+ public boolean updateExternalMediaStatus(final boolean mediaStatus) {
synchronized (mPackages) {
if (DEBUG_SD_INSTALL) Log.i(TAG, "updateExternalMediaStatus:: mediaStatus=" +
mediaStatus+", mMediaMounted=" + mMediaMounted);
if (mediaStatus == mMediaMounted) {
- return;
+ return false;
}
mMediaMounted = mediaStatus;
+ boolean ret = false;
+ synchronized (mPackages) {
+ Set<String> appList = mSettings.findPackagesWithFlag(ApplicationInfo.FLAG_ON_SDCARD);
+ ret = appList != null && appList.size() > 0;
+ }
+ if (!ret) {
+ // No packages will be effected by the sdcard update. Just return.
+ return false;
+ }
// Queue up an async operation since the package installation may take a little while.
mHandler.post(new Runnable() {
public void run() {
mHandler.removeCallbacks(this);
- updateExternalMediaStatusInner(mediaStatus);
+ // If we are up here that means there are packages to be
+ // enabled or disabled.
+ final HashMap<SdInstallArgs, String> processCids =
+ new HashMap<SdInstallArgs, String>();
+ final int[] uidArr = getExternalMediaPackages(mediaStatus, processCids);
+ if (mediaStatus) {
+ if (DEBUG_SD_INSTALL) Log.i(TAG, "Loading packages");
+ loadMediaPackages(processCids, uidArr);
+ startCleaningPackages();
+ } else {
+ if (DEBUG_SD_INSTALL) Log.i(TAG, "Unloading packages");
+ unloadMediaPackages(processCids, uidArr);
+ }
}
});
+ return true;
}
}
- void updateExternalMediaStatusInner(boolean mediaStatus) {
+ private int[] getExternalMediaPackages(boolean mediaStatus,
+ Map<SdInstallArgs, String> processCids) {
final String list[] = PackageHelper.getSecureContainerList();
if (list == null || list.length == 0) {
- return;
+ return null;
}
- HashMap<SdInstallArgs, String> processCids = new HashMap<SdInstallArgs, String>();
+
int uidList[] = new int[list.length];
int num = 0;
synchronized (mPackages) {
@@ -8892,14 +8968,7 @@ class PackageManagerService extends IPackageManager.Stub {
}
}
}
- if (mediaStatus) {
- if (DEBUG_SD_INSTALL) Log.i(TAG, "Loading packages");
- loadMediaPackages(processCids, uidArr);
- startCleaningPackages();
- } else {
- if (DEBUG_SD_INSTALL) Log.i(TAG, "Unloading packages");
- unloadMediaPackages(processCids, uidArr);
- }
+ return uidArr;
}
private void sendResourcesChangedBroadcast(boolean mediaStatus,
@@ -8919,7 +8988,7 @@ class PackageManagerService extends IPackageManager.Stub {
}
}
- void loadMediaPackages(HashMap<SdInstallArgs, String> processCids, int uidArr[]) {
+ private void loadMediaPackages(HashMap<SdInstallArgs, String> processCids, int uidArr[]) {
ArrayList<String> pkgList = new ArrayList<String>();
Set<SdInstallArgs> keys = processCids.keySet();
for (SdInstallArgs args : keys) {
@@ -8961,15 +9030,15 @@ class PackageManagerService extends IPackageManager.Stub {
}
args.doPostInstall(retCode);
}
- // Send broadcasts first
+ // Send a broadcast to let everyone know we are done processing
+ sendResourcesChangedBroadcast(true, pkgList, uidArr);
if (pkgList.size() > 0) {
- sendResourcesChangedBroadcast(true, pkgList, uidArr);
Runtime.getRuntime().gc();
// If something failed do we clean up here or next install?
}
}
- void unloadMediaPackages(HashMap<SdInstallArgs, String> processCids, int uidArr[]) {
+ private void unloadMediaPackages(HashMap<SdInstallArgs, String> processCids, int uidArr[]) {
if (DEBUG_SD_INSTALL) Log.i(TAG, "unloading media packages");
ArrayList<String> pkgList = new ArrayList<String>();
ArrayList<SdInstallArgs> failedList = new ArrayList<SdInstallArgs>();
@@ -8991,9 +9060,9 @@ class PackageManagerService extends IPackageManager.Stub {
}
}
}
+ sendResourcesChangedBroadcast(false, pkgList, uidArr);
// Send broadcasts
if (pkgList.size() > 0) {
- sendResourcesChangedBroadcast(false, pkgList, uidArr);
Runtime.getRuntime().gc();
}
// Do clean up. Just unmount
diff --git a/services/java/com/android/server/RecognitionManagerService.java b/services/java/com/android/server/RecognitionManagerService.java
new file mode 100644
index 0000000..7305b07
--- /dev/null
+++ b/services/java/com/android/server/RecognitionManagerService.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+import com.android.internal.content.PackageMonitor;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.os.Binder;
+import android.provider.Settings;
+import android.speech.RecognitionService;
+import android.text.TextUtils;
+import android.util.Log;
+
+import java.util.List;
+
+public class RecognitionManagerService extends Binder {
+ final static String TAG = "RecognitionManagerService";
+
+ final Context mContext;
+ final MyPackageMonitor mMonitor;
+
+ class MyPackageMonitor extends PackageMonitor {
+ public void onSomePackagesChanged() {
+ ComponentName comp = getCurRecognizer();
+ if (comp == null) {
+ if (anyPackagesAppearing()) {
+ comp = findAvailRecognizer(null);
+ if (comp != null) {
+ setCurRecognizer(comp);
+ }
+ }
+ return;
+ }
+
+ int change = isPackageDisappearing(comp.getPackageName());
+ if (change == PACKAGE_PERMANENT_CHANGE
+ || change == PACKAGE_TEMPORARY_CHANGE) {
+ setCurRecognizer(findAvailRecognizer(null));
+
+ } else if (isPackageModified(comp.getPackageName())) {
+ setCurRecognizer(findAvailRecognizer(comp.getPackageName()));
+ }
+ }
+ }
+
+ RecognitionManagerService(Context context) {
+ mContext = context;
+ mMonitor = new MyPackageMonitor();
+ mMonitor.register(context, true);
+ }
+
+ public void systemReady() {
+ ComponentName comp = getCurRecognizer();
+ if (comp != null) {
+ // See if the current recognizer is no longer available.
+ try {
+ mContext.getPackageManager().getServiceInfo(comp, 0);
+ } catch (NameNotFoundException e) {
+ setCurRecognizer(null);
+ }
+ } else {
+ comp = findAvailRecognizer(null);
+ if (comp != null) {
+ setCurRecognizer(comp);
+ }
+ }
+ }
+
+ ComponentName findAvailRecognizer(String prefPackage) {
+ List<ResolveInfo> available =
+ mContext.getPackageManager().queryIntentServices(
+ new Intent(RecognitionService.SERVICE_INTERFACE), 0);
+ int numAvailable = available.size();
+
+ if (numAvailable == 0) {
+ Log.w(TAG, "no available voice recognition services found");
+ return null;
+ } else {
+ if (prefPackage != null) {
+ for (int i=0; i<numAvailable; i++) {
+ ServiceInfo serviceInfo = available.get(i).serviceInfo;
+ if (prefPackage.equals(serviceInfo.packageName)) {
+ return new ComponentName(serviceInfo.packageName, serviceInfo.name);
+ }
+ }
+ }
+ if (numAvailable > 1) {
+ Log.w(TAG, "more than one voice recognition service found, picking first");
+ }
+
+ ServiceInfo serviceInfo = available.get(0).serviceInfo;
+ return new ComponentName(serviceInfo.packageName, serviceInfo.name);
+ }
+ }
+
+ ComponentName getCurRecognizer() {
+ String curRecognizer = Settings.Secure.getString(
+ mContext.getContentResolver(),
+ Settings.Secure.VOICE_RECOGNITION_SERVICE);
+ if (TextUtils.isEmpty(curRecognizer)) {
+ return null;
+ }
+ return ComponentName.unflattenFromString(curRecognizer);
+ }
+
+ void setCurRecognizer(ComponentName comp) {
+ Settings.Secure.putString(mContext.getContentResolver(),
+ Settings.Secure.VOICE_RECOGNITION_SERVICE,
+ comp != null ? comp.flattenToShortString() : "");
+ }
+}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index a09896a..1f46faf 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -97,6 +97,7 @@ class ServerThread extends Thread {
BluetoothA2dpService bluetoothA2dp = null;
HeadsetObserver headset = null;
DockObserver dock = null;
+ RecognitionManagerService recognition = null;
// Critical services...
try {
@@ -208,6 +209,7 @@ class ServerThread extends Thread {
AppWidgetService appWidget = null;
NotificationManagerService notification = null;
WallpaperManagerService wallpaper = null;
+ LocationManagerService location = null;
if (factoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
try {
@@ -302,8 +304,8 @@ class ServerThread extends Thread {
try {
Log.i(TAG, "Location Manager");
- ServiceManager.addService(Context.LOCATION_SERVICE,
- new LocationManagerService(context));
+ location = new LocationManagerService(context);
+ ServiceManager.addService(Context.LOCATION_SERVICE, location);
} catch (Throwable e) {
Log.e(TAG, "Failure starting Location Manager", e);
}
@@ -377,6 +379,13 @@ class ServerThread extends Thread {
}
try {
+ Log.i(TAG, "Recognition Service");
+ recognition = new RecognitionManagerService(context);
+ } catch (Throwable e) {
+ Log.e(TAG, "Failure starting Recognition Service", e);
+ }
+
+ try {
com.android.server.status.StatusBarPolicy.installIcons(context, statusBar);
} catch (Throwable e) {
Log.e(TAG, "Failure installing status bar icons", e);
@@ -435,6 +444,8 @@ class ServerThread extends Thread {
final AppWidgetService appWidgetF = appWidget;
final WallpaperManagerService wallpaperF = wallpaper;
final InputMethodManagerService immF = imm;
+ final RecognitionManagerService recognitionF = recognition;
+ final LocationManagerService locationF = location;
// We now tell the activity manager it is okay to run third party
// code. It will call back into us once it has gotten to the state
@@ -449,6 +460,7 @@ class ServerThread extends Thread {
if (batteryF != null) batteryF.systemReady();
if (connectivityF != null) connectivityF.systemReady();
if (dockF != null) dockF.systemReady();
+ if (recognitionF != null) recognitionF.systemReady();
Watchdog.getInstance().start();
// It is now okay to let the various system services start their
@@ -457,6 +469,7 @@ class ServerThread extends Thread {
if (appWidgetF != null) appWidgetF.systemReady(safeMode);
if (wallpaperF != null) wallpaperF.systemReady();
if (immF != null) immF.systemReady();
+ if (locationF != null) locationF.systemReady();
}
});
diff --git a/services/java/com/android/server/TwilightCalculator.java b/services/java/com/android/server/TwilightCalculator.java
index a8f67d8..a5c93b5 100644
--- a/services/java/com/android/server/TwilightCalculator.java
+++ b/services/java/com/android/server/TwilightCalculator.java
@@ -46,10 +46,16 @@ public class TwilightCalculator {
// Java time on Jan 1, 2000 12:00 UTC.
private static final long UTC_2000 = 946728000000L;
- /** Time of sunset (civil twilight) in milliseconds. */
+ /**
+ * Time of sunset (civil twilight) in milliseconds or -1 in the case the day
+ * or night never ends.
+ */
public long mSunset;
- /** Time of sunrise (civil twilight) in milliseconds. */
+ /**
+ * Time of sunrise (civil twilight) in milliseconds or -1 in the case the
+ * day or night never ends.
+ */
public long mSunrise;
/** Current state */
@@ -85,10 +91,24 @@ public class TwilightCalculator {
double solarDec = Math.asin(FloatMath.sin(solarLng) * FloatMath.sin(OBLIQUITY));
final double latRad = latiude * DEGREES_TO_RADIANS;
- float hourAngle = (float) (Math
- .acos((FloatMath.sin(ALTIDUTE_CORRECTION_CIVIL_TWILIGHT) - Math.sin(latRad)
- * Math.sin(solarDec))
- / (Math.cos(latRad) * Math.cos(solarDec))) / (2 * Math.PI));
+
+ double cosHourAngle = (FloatMath.sin(ALTIDUTE_CORRECTION_CIVIL_TWILIGHT) - Math.sin(latRad)
+ * Math.sin(solarDec)) / (Math.cos(latRad) * Math.cos(solarDec));
+ // The day or night never ends for the given date and location, if this value is out of
+ // range.
+ if (cosHourAngle >= 1) {
+ mState = NIGHT;
+ mSunset = -1;
+ mSunrise = -1;
+ return;
+ } else if (cosHourAngle <= -1) {
+ mState = DAY;
+ mSunset = -1;
+ mSunrise = -1;
+ return;
+ }
+
+ float hourAngle = (float) (Math.acos(cosHourAngle) / (2 * Math.PI));
mSunset = Math.round((solarTransitJ2000 + hourAngle) * DateUtils.DAY_IN_MILLIS) + UTC_2000;
mSunrise = Math.round((solarTransitJ2000 - hourAngle) * DateUtils.DAY_IN_MILLIS) + UTC_2000;
diff --git a/services/java/com/android/server/WallpaperManagerService.java b/services/java/com/android/server/WallpaperManagerService.java
index 81255ee..aebb0ff 100644
--- a/services/java/com/android/server/WallpaperManagerService.java
+++ b/services/java/com/android/server/WallpaperManagerService.java
@@ -65,8 +65,11 @@ import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;
+import com.android.internal.content.PackageMonitor;
import com.android.internal.service.wallpaper.ImageWallpaper;
-import com.android.common.FastXmlSerializer;
+import com.android.internal.util.FastXmlSerializer;
+import com.android.server.DevicePolicyManagerService.ActiveAdmin;
+import com.android.server.DevicePolicyManagerService.MyPackageMonitor;
class WallpaperManagerService extends IWallpaperManager.Stub {
static final String TAG = "WallpaperService";
@@ -122,6 +125,7 @@ class WallpaperManagerService extends IWallpaperManager.Stub {
final Context mContext;
final IWindowManager mIWindowManager;
+ final MyPackageMonitor mMonitor;
int mWidth = -1;
int mHeight = -1;
@@ -150,6 +154,7 @@ class WallpaperManagerService extends IWallpaperManager.Stub {
WallpaperConnection mWallpaperConnection;
long mLastDiedTime;
+ boolean mWallpaperUpdating;
class WallpaperConnection extends IWallpaperConnection.Stub
implements ServiceConnection {
@@ -165,6 +170,7 @@ class WallpaperManagerService extends IWallpaperManager.Stub {
public void onServiceConnected(ComponentName name, IBinder service) {
synchronized (mLock) {
if (mWallpaperConnection == this) {
+ mLastDiedTime = SystemClock.uptimeMillis();
mService = IWallpaperService.Stub.asInterface(service);
attachServiceLocked(this);
// XXX should probably do saveSettingsLocked() later
@@ -182,8 +188,8 @@ class WallpaperManagerService extends IWallpaperManager.Stub {
mEngine = null;
if (mWallpaperConnection == this) {
Log.w(TAG, "Wallpaper service gone: " + mWallpaperComponent);
- if ((mLastDiedTime+MIN_WALLPAPER_CRASH_TIME)
- < SystemClock.uptimeMillis()) {
+ if (!mWallpaperUpdating && (mLastDiedTime+MIN_WALLPAPER_CRASH_TIME)
+ > SystemClock.uptimeMillis()) {
Log.w(TAG, "Reverting to built-in wallpaper!");
bindWallpaperComponentLocked(null);
}
@@ -205,11 +211,92 @@ class WallpaperManagerService extends IWallpaperManager.Stub {
}
}
+ class MyPackageMonitor extends PackageMonitor {
+ @Override
+ public void onPackageUpdateFinished(String packageName, int uid) {
+ synchronized (mLock) {
+ if (mWallpaperComponent != null &&
+ mWallpaperComponent.getPackageName().equals(packageName)) {
+ mWallpaperUpdating = false;
+ ComponentName comp = mWallpaperComponent;
+ clearWallpaperComponentLocked();
+ bindWallpaperComponentLocked(comp);
+ }
+ }
+ }
+
+ @Override
+ public void onPackageUpdateStarted(String packageName, int uid) {
+ synchronized (mLock) {
+ if (mWallpaperComponent != null &&
+ mWallpaperComponent.getPackageName().equals(packageName)) {
+ mWallpaperUpdating = true;
+ }
+ }
+ }
+
+ @Override
+ public boolean onHandleForceStop(Intent intent, String[] packages, int uid, boolean doit) {
+ return doPackagesChanged(doit);
+ }
+
+ @Override
+ public void onSomePackagesChanged() {
+ doPackagesChanged(true);
+ }
+
+ boolean doPackagesChanged(boolean doit) {
+ boolean changed = false;
+ synchronized (mLock) {
+ if (mWallpaperComponent != null) {
+ int change = isPackageDisappearing(mWallpaperComponent.getPackageName());
+ if (change == PACKAGE_PERMANENT_CHANGE
+ || change == PACKAGE_TEMPORARY_CHANGE) {
+ changed = true;
+ if (doit) {
+ Log.w(TAG, "Wallpaper uninstalled, removing: " + mWallpaperComponent);
+ clearWallpaperLocked();
+ }
+ }
+ }
+ if (mNextWallpaperComponent != null) {
+ int change = isPackageDisappearing(mNextWallpaperComponent.getPackageName());
+ if (change == PACKAGE_PERMANENT_CHANGE
+ || change == PACKAGE_TEMPORARY_CHANGE) {
+ mNextWallpaperComponent = null;
+ }
+ }
+ if (mWallpaperComponent != null
+ && isPackageModified(mWallpaperComponent.getPackageName())) {
+ try {
+ mContext.getPackageManager().getServiceInfo(
+ mWallpaperComponent, 0);
+ } catch (NameNotFoundException e) {
+ Log.w(TAG, "Wallpaper component gone, removing: " + mWallpaperComponent);
+ clearWallpaperLocked();
+ }
+ }
+ if (mNextWallpaperComponent != null
+ && isPackageModified(mNextWallpaperComponent.getPackageName())) {
+ try {
+ mContext.getPackageManager().getServiceInfo(
+ mNextWallpaperComponent, 0);
+ } catch (NameNotFoundException e) {
+ mNextWallpaperComponent = null;
+ }
+ }
+ }
+ return changed;
+ }
+ }
+
public WallpaperManagerService(Context context) {
if (DEBUG) Log.v(TAG, "WallpaperService startup");
mContext = context;
mIWindowManager = IWindowManager.Stub.asInterface(
ServiceManager.getService(Context.WINDOW_SERVICE));
+ mMonitor = new MyPackageMonitor();
+ mMonitor.register(context, true);
WALLPAPER_DIR.mkdirs();
loadSettingsLocked();
mWallpaperObserver.startWatching();
@@ -241,16 +328,20 @@ class WallpaperManagerService extends IWallpaperManager.Stub {
public void clearWallpaper() {
if (DEBUG) Log.v(TAG, "clearWallpaper");
synchronized (mLock) {
- File f = WALLPAPER_FILE;
- if (f.exists()) {
- f.delete();
- }
- final long ident = Binder.clearCallingIdentity();
- try {
- bindWallpaperComponentLocked(null);
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
+ clearWallpaperLocked();
+ }
+ }
+
+ public void clearWallpaperLocked() {
+ File f = WALLPAPER_FILE;
+ if (f.exists()) {
+ f.delete();
+ }
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ bindWallpaperComponentLocked(null);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
}
}
@@ -499,7 +590,9 @@ class WallpaperManagerService extends IWallpaperManager.Stub {
mWidth, mHeight);
} catch (RemoteException e) {
Log.w(TAG, "Failed attaching wallpaper; clearing", e);
- bindWallpaperComponentLocked(null);
+ if (!mWallpaperUpdating) {
+ bindWallpaperComponentLocked(null);
+ }
}
}
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 45c3f00..7b64704 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -47,6 +47,7 @@ import android.app.ResultInfo;
import android.app.Service;
import android.backup.IBackupManager;
import android.content.ActivityNotFoundException;
+import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
@@ -93,7 +94,6 @@ import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.provider.Settings;
-import android.text.TextUtils;
import android.util.Config;
import android.util.EventLog;
import android.util.Log;
@@ -107,7 +107,6 @@ import android.view.WindowManagerPolicy;
import java.io.File;
import java.io.FileDescriptor;
-import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintWriter;
@@ -136,6 +135,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
static final boolean DEBUG_VISBILITY = localLOGV || false;
static final boolean DEBUG_PROCESSES = localLOGV || false;
static final boolean DEBUG_PROVIDER = localLOGV || false;
+ static final boolean DEBUG_URI_PERMISSION = localLOGV || false;
static final boolean DEBUG_USER_LEAVING = localLOGV || false;
static final boolean DEBUG_RESULTS = localLOGV || false;
static final boolean DEBUG_BACKUP = localLOGV || false;
@@ -296,12 +296,6 @@ 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.
static final int EMPTY_APP_MEM;
static final int HIDDEN_APP_MEM;
@@ -975,6 +969,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
static final int PROC_START_TIMEOUT_MSG = 20;
static final int DO_PENDING_ACTIVITY_LAUNCHES_MSG = 21;
static final int KILL_APPLICATION_MSG = 22;
+ static final int FINALIZE_PENDING_INTENT_MSG = 23;
AlertDialog mUidAlert;
@@ -1193,9 +1188,12 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
int uid = msg.arg1;
boolean restart = (msg.arg2 == 1);
String pkg = (String) msg.obj;
- forceStopPackageLocked(pkg, uid, restart, false);
+ forceStopPackageLocked(pkg, uid, restart, false, true);
}
} break;
+ case FINALIZE_PENDING_INTENT_MSG: {
+ ((PendingIntentRecord)msg.obj).completeFinalize();
+ } break;
}
}
};
@@ -1396,7 +1394,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
GL_ES_VERSION = SystemProperties.getInt("ro.opengles.version",
ConfigurationInfo.GL_ES_VERSION_UNDEFINED);
- mConfiguration.makeDefault();
+ mConfiguration.setToDefaults();
+ mConfiguration.locale = Locale.getDefault();
mProcessStats.init();
// Add ourself to the Watchdog monitors.
@@ -3605,10 +3604,18 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
synchronized(this) {
+ int callingPid;
+ int callingUid;
+ if (caller == null) {
+ callingPid = Binder.getCallingPid();
+ callingUid = Binder.getCallingUid();
+ } else {
+ callingPid = callingUid = -1;
+ }
final long origId = Binder.clearCallingIdentity();
int res = startActivityLocked(caller, intent, resolvedType,
grantedUriPermissions, grantedMode, aInfo,
- resultTo, resultWho, requestCode, -1, -1,
+ resultTo, resultWho, requestCode, callingPid, callingUid,
onlyIfNeeded, componentSpecified);
Binder.restoreCallingIdentity(origId);
return res;
@@ -4846,7 +4853,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
return;
}
killPackageProcessesLocked(packageName, pkgUid,
- SECONDARY_SERVER_ADJ, false);
+ SECONDARY_SERVER_ADJ, false, true);
}
} finally {
Binder.restoreCallingIdentity(callingId);
@@ -4988,7 +4995,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
private void forceStopPackageLocked(final String packageName, int uid) {
- forceStopPackageLocked(packageName, uid, false, false);
+ forceStopPackageLocked(packageName, uid, false, false, true);
Intent intent = new Intent(Intent.ACTION_PACKAGE_RESTARTED,
Uri.fromParts("package", packageName, null));
intent.putExtra(Intent.EXTRA_UID, uid);
@@ -4997,8 +5004,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
false, false, MY_PID, Process.SYSTEM_UID);
}
- private final void killPackageProcessesLocked(String packageName, int uid,
- int minOomAdj, boolean callerWillRestart) {
+ private final boolean killPackageProcessesLocked(String packageName, int uid,
+ int minOomAdj, boolean callerWillRestart, boolean doit) {
ArrayList<ProcessRecord> procs = new ArrayList<ProcessRecord>();
// Remove all processes this package may have touched: all with the
@@ -5010,11 +5017,16 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
for (int ia=0; ia<NA; ia++) {
ProcessRecord app = apps.valueAt(ia);
if (app.removed) {
- procs.add(app);
+ if (doit) {
+ procs.add(app);
+ }
} else if ((uid > 0 && uid != Process.SYSTEM_UID && app.info.uid == uid)
|| app.processName.equals(packageName)
|| app.processName.startsWith(procNamePrefix)) {
if (app.setAdj >= minOomAdj) {
+ if (!doit) {
+ return true;
+ }
app.removed = true;
procs.add(app);
}
@@ -5026,10 +5038,11 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
for (int i=0; i<N; i++) {
removeProcessLocked(procs.get(i), callerWillRestart);
}
+ return N > 0;
}
- private final void forceStopPackageLocked(String name, int uid,
- boolean callerWillRestart, boolean purgeCache) {
+ private final boolean forceStopPackageLocked(String name, int uid,
+ boolean callerWillRestart, boolean purgeCache, boolean doit) {
int i, N;
if (uid < 0) {
@@ -5039,21 +5052,28 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
}
- Log.i(TAG, "Force stopping package " + name + " uid=" + uid);
+ if (doit) {
+ Log.i(TAG, "Force stopping package " + name + " uid=" + uid);
- Iterator<SparseArray<Long>> badApps = mProcessCrashTimes.getMap().values().iterator();
- while (badApps.hasNext()) {
- SparseArray<Long> ba = badApps.next();
- if (ba.get(uid) != null) {
- badApps.remove();
+ Iterator<SparseArray<Long>> badApps = mProcessCrashTimes.getMap().values().iterator();
+ while (badApps.hasNext()) {
+ SparseArray<Long> ba = badApps.next();
+ if (ba.get(uid) != null) {
+ badApps.remove();
+ }
}
}
-
- killPackageProcessesLocked(name, uid, -100, callerWillRestart);
+
+ boolean didSomething = killPackageProcessesLocked(name, uid, -100,
+ callerWillRestart, doit);
for (i=mHistory.size()-1; i>=0; i--) {
HistoryRecord r = (HistoryRecord)mHistory.get(i);
if (r.packageName.equals(name)) {
+ if (!doit) {
+ return true;
+ }
+ didSomething = true;
Log.i(TAG, " Force finishing activity " + r);
if (r.app != null) {
r.app.removed = true;
@@ -5066,6 +5086,10 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
ArrayList<ServiceRecord> services = new ArrayList<ServiceRecord>();
for (ServiceRecord service : mServices.values()) {
if (service.packageName.equals(name)) {
+ if (!doit) {
+ return true;
+ }
+ didSomething = true;
Log.i(TAG, " Force stopping service " + service);
if (service.app != null) {
service.app.removed = true;
@@ -5080,13 +5104,17 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
bringDownServiceLocked(services.get(i), true);
}
- resumeTopActivityLocked(null);
- if (purgeCache) {
- AttributeCache ac = AttributeCache.instance();
- if (ac != null) {
- ac.removePackage(name);
+ if (doit) {
+ if (purgeCache) {
+ AttributeCache ac = AttributeCache.instance();
+ if (ac != null) {
+ ac.removePackage(name);
+ }
}
+ resumeTopActivityLocked(null);
}
+
+ return didSomething;
}
private final boolean removeProcessLocked(ProcessRecord app, boolean callerWillRestart) {
@@ -5583,19 +5611,38 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
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);
+ IntentFilter pkgFilter = new IntentFilter();
+ pkgFilter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
+ pkgFilter.addDataScheme("package");
+ mContext.registerReceiver(new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String[] pkgs = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES);
+ if (pkgs != null) {
+ for (String pkg : pkgs) {
+ if (forceStopPackageLocked(pkg, -1, false, false, false)) {
+ setResultCode(Activity.RESULT_OK);
+ return;
+ }
+ }
+ }
}
- }
- if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
- // Tell anyone interested that we are done booting!
- synchronized (this) {
+ }, pkgFilter);
+
+ synchronized (this) {
+ // 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!
broadcastIntentLocked(null, null,
new Intent(Intent.ACTION_BOOT_COMPLETED, null),
null, null, 0, null, null,
@@ -6132,10 +6179,15 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
return;
}
+ if (DEBUG_URI_PERMISSION) Log.v(TAG,
+ "Requested grant " + targetPkg + " permission to " + uri);
+
final IPackageManager pm = ActivityThread.getPackageManager();
// If this is not a content: uri, we can't do anything with it.
if (!ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
+ if (DEBUG_URI_PERMISSION) Log.v(TAG,
+ "Can't grant URI permission for non-content URI: " + uri);
return;
}
@@ -6161,6 +6213,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
try {
targetUid = pm.getPackageUid(targetPkg);
if (targetUid < 0) {
+ if (DEBUG_URI_PERMISSION) Log.v(TAG,
+ "Can't grant URI permission no uid for: " + targetPkg);
return;
}
} catch (RemoteException ex) {
@@ -6170,17 +6224,12 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// First... does the target actually need this permission?
if (checkHoldingPermissionsLocked(pm, pi, targetUid, modeFlags)) {
// No need to grant the target this permission.
+ if (DEBUG_URI_PERMISSION) Log.v(TAG,
+ "Target " + targetPkg + " already has full permission to " + uri);
return;
}
- // Second... maybe someone else has already granted the
- // permission?
- if (checkUriPermissionLocked(uri, targetUid, modeFlags)) {
- // No need to grant the target this permission.
- return;
- }
-
- // Third... is the provider allowing granting of URI permissions?
+ // Second... is the provider allowing granting of URI permissions?
if (!pi.grantUriPermissions) {
throw new SecurityException("Provider " + pi.packageName
+ "/" + pi.name
@@ -6205,7 +6254,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
}
- // Fourth... does the caller itself have permission to access
+ // Third... does the caller itself have permission to access
// this uri?
if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
@@ -6218,6 +6267,9 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// to the uri, and the target doesn't. Let's now give this to
// the target.
+ if (DEBUG_URI_PERMISSION) Log.v(TAG,
+ "Granting " + targetPkg + " permission to " + uri);
+
HashMap<Uri, UriPermission> targetUris
= mGrantedUriPermissions.get(targetUid);
if (targetUris == null) {
@@ -6291,6 +6343,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
HashMap<Uri, UriPermission> perms
= mGrantedUriPermissions.get(perm.uid);
if (perms != null) {
+ if (DEBUG_URI_PERMISSION) Log.v(TAG,
+ "Removing " + perm.uid + " permission to " + perm.uri);
perms.remove(perm.uri);
if (perms.size() == 0) {
mGrantedUriPermissions.remove(perm.uid);
@@ -6330,6 +6384,9 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
return;
}
+ if (DEBUG_URI_PERMISSION) Log.v(TAG,
+ "Revoking all granted permissions to " + uri);
+
final IPackageManager pm = ActivityThread.getPackageManager();
final String authority = uri.getAuthority();
@@ -6388,6 +6445,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
continue toploop;
}
}
+ if (DEBUG_URI_PERMISSION) Log.v(TAG,
+ "Revoking " + perm.uid + " permission to " + perm.uri);
perm.clearModes(modeFlags);
if (perm.modeFlags == 0) {
it.remove();
@@ -7556,6 +7615,15 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
? cpi.readPermission : cpi.writePermission);
}
+ if (!mSystemReady && !mDidUpdate && !mWaitingUpdate
+ && !cpi.processName.equals("system")) {
+ // If this content provider does not run in the system
+ // process, and the system is not yet ready to run other
+ // processes, then fail fast instead of hanging.
+ throw new IllegalArgumentException(
+ "Attempt to launch content provider before system ready");
+ }
+
cpr = (ContentProviderRecord)mProvidersByClass.get(cpi.name);
final boolean firstClass = cpr == null;
if (firstClass) {
@@ -7803,6 +7871,16 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
public static final void installSystemProviders() {
ProcessRecord app = mSelf.mProcessNames.get("system", Process.SYSTEM_UID);
List providers = mSelf.generateApplicationProvidersLocked(app);
+ if (providers != null) {
+ for (int i=providers.size()-1; i>=0; i--) {
+ ProviderInfo pi = (ProviderInfo)providers.get(i);
+ if ((pi.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) == 0) {
+ Log.w(TAG, "Not installing system proc provider " + pi.name
+ + ": not system .apk");
+ providers.remove(i);
+ }
+ }
+ }
mSystemThread.installSystemProviders(providers);
}
@@ -8050,7 +8128,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
mDebugTransient = !persistent;
if (packageName != null) {
final long origId = Binder.clearCallingIdentity();
- forceStopPackageLocked(packageName, -1, false, false);
+ forceStopPackageLocked(packageName, -1, false, false, true);
Binder.restoreCallingIdentity(origId);
}
}
@@ -8339,7 +8417,6 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
mAlwaysFinishActivities = alwaysFinishActivities;
// This happens before any activities are started, so we can
// change mConfiguration in-place.
- mConfiguration.locale = Locale.getDefault();
mConfiguration.updateFrom(configuration);
mConfigurationSeq = mConfiguration.seq = 1;
if (DEBUG_CONFIGURATION) Log.v(TAG, "Initial config: " + mConfiguration);
@@ -8537,73 +8614,6 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
return handleAppCrashLocked(app);
}
- private ComponentName getErrorReportReceiver(ProcessRecord app) {
- // check if error reporting is enabled in secure settings
- int enabled = Settings.Secure.getInt(mContext.getContentResolver(),
- Settings.Secure.SEND_ACTION_APP_ERROR, 0);
- if (enabled == 0) {
- return null;
- }
-
- IPackageManager pm = ActivityThread.getPackageManager();
-
- try {
- // 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;
- }
-
- // 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;
- }
- }
-
- // 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) {
- // should not happen
- Log.e(TAG, "error talking to PackageManager", e);
- 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);
- }
-
private void makeAppNotRespondingLocked(ProcessRecord app,
String activity, String shortMsg, String longMsg) {
app.notResponding = true;
@@ -8717,7 +8727,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
void startAppProblemLocked(ProcessRecord app) {
- app.errorReportReceiver = getErrorReportReceiver(app);
+ app.errorReportReceiver = ApplicationErrorReport.getErrorReportReceiver(
+ mContext, app.info.packageName, app.info.flags);
skipCurrentReceiverLocked(app);
}
@@ -11951,7 +11962,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
String list[] = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
if (list != null && (list.length > 0)) {
for (String pkg : list) {
- forceStopPackageLocked(pkg, -1, false, true);
+ forceStopPackageLocked(pkg, -1, false, true, true);
}
}
} else {
@@ -11960,7 +11971,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
if (data != null && (ssp=data.getSchemeSpecificPart()) != null) {
if (!intent.getBooleanExtra(Intent.EXTRA_DONT_KILL_APP, false)) {
forceStopPackageLocked(ssp,
- intent.getIntExtra(Intent.EXTRA_UID, -1), false, true);
+ intent.getIntExtra(Intent.EXTRA_UID, -1), false, true, true);
}
}
}
@@ -12931,7 +12942,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
final long origId = Binder.clearCallingIdentity();
- forceStopPackageLocked(ii.targetPackage, -1, true, false);
+ forceStopPackageLocked(ii.targetPackage, -1, true, false, true);
ProcessRecord app = addAppLocked(ai);
app.instrumentationClass = className;
app.instrumentationInfo = ai;
@@ -12986,7 +12997,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
app.instrumentationProfileFile = null;
app.instrumentationArguments = null;
- forceStopPackageLocked(app.processName, -1, false, false);
+ forceStopPackageLocked(app.processName, -1, false, false, true);
}
public void finishInstrumentation(IApplicationThread target,
diff --git a/services/java/com/android/server/am/PendingIntentRecord.java b/services/java/com/android/server/am/PendingIntentRecord.java
index b3086d5..fac47d7 100644
--- a/services/java/com/android/server/am/PendingIntentRecord.java
+++ b/services/java/com/android/server/am/PendingIntentRecord.java
@@ -145,8 +145,9 @@ class PendingIntentRecord extends IIntentSender.Stub {
public String toString() {
return "Key{" + typeName() + " pkg=" + packageName
- + " intent=" + requestIntent.toShortString(true, false) + " flags=0x"
- + Integer.toHexString(flags) + "}";
+ + " intent="
+ + (requestIntent != null ? requestIntent.toShortString(true, false) : "<null>")
+ + " flags=0x" + Integer.toHexString(flags) + "}";
}
String typeName() {
@@ -262,17 +263,26 @@ class PendingIntentRecord extends IIntentSender.Stub {
}
protected void finalize() throws Throwable {
- if (!canceled) {
- synchronized(owner) {
- WeakReference<PendingIntentRecord> current =
- owner.mIntentSenderRecords.get(key);
- if (current == ref) {
- owner.mIntentSenderRecords.remove(key);
- }
+ try {
+ if (!canceled) {
+ owner.mHandler.sendMessage(owner.mHandler.obtainMessage(
+ ActivityManagerService.FINALIZE_PENDING_INTENT_MSG, this));
}
+ } finally {
+ super.finalize();
}
}
+ public void completeFinalize() {
+ synchronized(owner) {
+ WeakReference<PendingIntentRecord> current =
+ owner.mIntentSenderRecords.get(key);
+ if (current == ref) {
+ owner.mIntentSenderRecords.remove(key);
+ }
+ }
+ }
+
void dump(PrintWriter pw, String prefix) {
pw.print(prefix); pw.print("uid="); pw.print(uid);
pw.print(" packageName="); pw.print(key.packageName);
@@ -286,8 +296,10 @@ class PendingIntentRecord extends IIntentSender.Stub {
pw.print(prefix); pw.print("requestCode="); pw.print(key.requestCode);
pw.print(" requestResolvedType="); pw.println(key.requestResolvedType);
}
- pw.print(prefix); pw.print("requestIntent=");
- pw.println(key.requestIntent.toShortString(true, true));
+ if (key.requestIntent != null) {
+ pw.print(prefix); pw.print("requestIntent=");
+ pw.println(key.requestIntent.toShortString(true, true));
+ }
if (sent || canceled) {
pw.print(prefix); pw.print("sent="); pw.print(sent);
pw.print(" canceled="); pw.println(canceled);
diff --git a/services/java/com/android/server/am/ServiceRecord.java b/services/java/com/android/server/am/ServiceRecord.java
index 2f2cc32..5a02c40 100644
--- a/services/java/com/android/server/am/ServiceRecord.java
+++ b/services/java/com/android/server/am/ServiceRecord.java
@@ -269,8 +269,12 @@ class ServiceRecord extends Binder {
inm.enqueueNotification(localPackageName, localForegroundId,
localForegroundNoti, outId);
} catch (RuntimeException e) {
- Log.w(ActivityManagerService.TAG, "Error showing notification for service",
- e);
+ Log.w(ActivityManagerService.TAG,
+ "Error showing notification for service", e);
+ // If it gave us a garbage notification, it doesn't
+ // get to be foreground.
+ ams.setServiceForeground(name, ServiceRecord.this,
+ localForegroundId, null, true);
} catch (RemoteException e) {
}
}
@@ -293,8 +297,8 @@ class ServiceRecord extends Binder {
try {
inm.cancelNotification(localPackageName, localForegroundId);
} catch (RuntimeException e) {
- Log.w(ActivityManagerService.TAG, "Error canceling notification for"
- + " service", e);
+ Log.w(ActivityManagerService.TAG,
+ "Error canceling notification for service", e);
} catch (RemoteException e) {
}
}
diff --git a/services/java/com/android/server/connectivity/Tethering.java b/services/java/com/android/server/connectivity/Tethering.java
index 1d20074..16638bc 100644
--- a/services/java/com/android/server/connectivity/Tethering.java
+++ b/services/java/com/android/server/connectivity/Tethering.java
@@ -27,6 +27,7 @@ import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.net.ConnectivityManager;
+import android.net.InterfaceConfiguration;
import android.net.IConnectivityManager;
import android.net.INetworkManagementEventObserver;
import android.net.NetworkInfo;
@@ -56,6 +57,7 @@ import java.util.Set;
*
* TODO - look for parent classes and code sharing
*/
+
public class Tethering extends INetworkManagementEventObserver.Stub {
private Notification mTetheringNotification;
@@ -74,12 +76,23 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
private BroadcastReceiver mStateReceiver;
+ private static final String USB_NEAR_IFACE_ADDR = "169.254.2.1";
+
private String[] mDhcpRange;
+ private static final String DHCP_DEFAULT_RANGE_START = "169.254.2.10";
+ private static final String DHCP_DEFAULT_RANGE_STOP = "169.254.2.64";
private String[] mDnsServers;
+ private static final String DNS_DEFAULT_SERVER1 = "8.8.8.8";
+ private static final String DNS_DEFAULT_SERVER2 = "4.2.2.2";
private String mUpstreamIfaceName;
+ // turning on/off RNDIS resets the interface generating and extra discon/conn cycle
+ // count how many to ignore.. Self correcting if you plug/unplug a bunch of times.
+ // TODO - brittle - maybe don't need?
+ private int mUsbResetExpected = 0;
+
HierarchicalStateMachine mTetherMasterSM;
public Tethering(Context context) {
@@ -113,8 +126,8 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
com.android.internal.R.array.config_tether_dhcp_range);
if (mDhcpRange.length == 0) {
mDhcpRange = new String[2];
- mDhcpRange[0] = new String("169.254.2.1");
- mDhcpRange[1] = new String("169.254.2.64");
+ mDhcpRange[0] = DHCP_DEFAULT_RANGE_START;
+ mDhcpRange[1] = DHCP_DEFAULT_RANGE_STOP;
} else if(mDhcpRange.length == 1) {
String[] tmp = new String[2];
tmp[0] = mDhcpRange[0];
@@ -127,26 +140,17 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
mTetherableWifiRegexs = context.getResources().getStringArray(
com.android.internal.R.array.config_tether_wifi_regexs);
- String[] ifaces = new String[0];
- try {
- ifaces = service.listInterfaces();
- } catch (Exception e) {
- Log.e(TAG, "Error listing Interfaces :" + e);
- }
- for (String iface : ifaces) {
- interfaceAdded(iface);
- }
-
// TODO - remove and rely on real notifications of the current iface
mDnsServers = new String[2];
- mDnsServers[0] = "8.8.8.8";
- mDnsServers[1] = "4.2.2.2";
+ mDnsServers[0] = DNS_DEFAULT_SERVER1;
+ mDnsServers[1] = DNS_DEFAULT_SERVER2;
mUpstreamIfaceName = "rmnet0";
}
public void interfaceLinkStatusChanged(String iface, boolean link) {
Log.d(TAG, "interfaceLinkStatusChanged " + iface + ", " + link);
boolean found = false;
+ boolean usb = false;
for (String regex : mTetherableWifiRegexs) {
if (iface.matches(regex)) {
found = true;
@@ -156,6 +160,7 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
for (String regex: mTetherableUsbRegexs) {
if (iface.matches(regex)) {
found = true;
+ usb = true;
break;
}
}
@@ -165,7 +170,7 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
TetherInterfaceSM sm = mIfaces.get(iface);
if (link) {
if (sm == null) {
- sm = new TetherInterfaceSM(iface);
+ sm = new TetherInterfaceSM(iface, usb);
mIfaces.put(iface, sm);
sm.start();
}
@@ -179,7 +184,10 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
}
public void interfaceAdded(String iface) {
+ IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
+ INetworkManagementService service = INetworkManagementService.Stub.asInterface(b);
boolean found = false;
+ boolean usb = false;
for (String regex : mTetherableWifiRegexs) {
if (iface.matches(regex)) {
found = true;
@@ -189,6 +197,7 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
for (String regex : mTetherableUsbRegexs) {
if (iface.matches(regex)) {
found = true;
+ usb = true;
break;
}
}
@@ -196,13 +205,14 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
Log.d(TAG, iface + " is not a tetherable iface, ignoring");
return;
}
+
synchronized (mIfaces) {
TetherInterfaceSM sm = mIfaces.get(iface);
if (sm != null) {
Log.e(TAG, "active iface (" + iface + ") reported as added, ignoring");
return;
}
- sm = new TetherInterfaceSM(iface);
+ sm = new TetherInterfaceSM(iface, usb);
mIfaces.put(iface, sm);
sm.start();
}
@@ -297,7 +307,8 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
broadcast.putStringArrayListExtra(ConnectivityManager.EXTRA_ERRORED_TETHER,
erroredList);
mContext.sendStickyBroadcast(broadcast);
-
+ Log.d(TAG, "sendTetherStateChangedBroadcast " + availableList.size() + ", " +
+ activeList.size() + ", " + erroredList.size());
// check if we need to send a USB notification
// Check if the user wants to be bothered
boolean tellUser = (Settings.Secure.getInt(mContext.getContentResolver(),
@@ -314,8 +325,8 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
if (tellUser) {
for (Object o : availableList) {
String s = (String)o;
- for (Object matchObject : mTetherableUsbRegexs) {
- if (s.matches((String)matchObject)) {
+ for (String match : mTetherableUsbRegexs) {
+ if (s.matches(match)) {
showTetherAvailableNotification();
return;
}
@@ -414,20 +425,32 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
}
}
-
-
-
private class StateReceiver extends BroadcastReceiver {
public void onReceive(Context content, Intent intent) {
String action = intent.getAction();
if (action.equals(Intent.ACTION_UMS_CONNECTED)) {
- Tethering.this.handleTtyConnect();
+ Log.w(TAG, "got UMS connected");
+ synchronized (Tethering.this) {
+ if(mUsbResetExpected != 0) {
+ Log.w(TAG, "mUsbResetExpected == " + mUsbResetExpected + ", ignored");
+ mUsbResetExpected--;
+ return;
+ }
+ }
+ Tethering.this.enableUsbIfaces(true); // add them
} else if (action.equals(Intent.ACTION_UMS_DISCONNECTED)) {
- Tethering.this.handleTtyDisconnect();
+ Log.w(TAG, "got UMS disconneded broadcast");
+ synchronized (Tethering.this) {
+ if(mUsbResetExpected != 0) {
+ Log.w(TAG, "mUsbResetExpected == " + mUsbResetExpected + ", ignored");
+ mUsbResetExpected--;
+ return;
+ }
+ }
+ Tethering.this.enableUsbIfaces(false); // remove them
} else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
IBinder b = ServiceManager.getService(Context.CONNECTIVITY_SERVICE);
- IConnectivityManager service =
- IConnectivityManager.Stub.asInterface(b);
+ IConnectivityManager service = IConnectivityManager.Stub.asInterface(b);
try {
NetworkInfo info = service.getNetworkInfo(ConnectivityManager.TYPE_MOBILE_DUN);
int msg;
@@ -442,6 +465,103 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
}
}
+ // used on cable insert/remove
+ private void enableUsbIfaces(boolean enable) {
+ IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
+ INetworkManagementService service = INetworkManagementService.Stub.asInterface(b);
+ String[] ifaces = new String[0];
+ try {
+ ifaces = service.listInterfaces();
+ } catch (Exception e) {
+ Log.e(TAG, "Error listing Interfaces :" + e);
+ return;
+ }
+ for (String iface : ifaces) {
+ for (String regex : mTetherableUsbRegexs) {
+ if (iface.matches(regex)) {
+ if (enable) {
+ interfaceAdded(iface);
+ } else {
+ interfaceRemoved(iface);
+ }
+ }
+ }
+ }
+ }
+
+ // toggled when we enter/leave the fully teathered state
+ private boolean enableUsbRndis(boolean enabled) {
+ Log.d(TAG, "enableUsbRndis(" + enabled + ")");
+ IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
+ INetworkManagementService service = INetworkManagementService.Stub.asInterface(b);
+
+ try {
+ if (enabled) {
+ // turning this on will reset USB and generate two bogus events - ignore them
+ synchronized (this) {
+ if (!service.isUsbRNDISStarted()) {
+ mUsbResetExpected += 2;
+ service.startUsbRNDIS();
+ }
+ }
+ } else {
+ if (service.isUsbRNDISStarted()) {
+ service.stopUsbRNDIS();
+ }
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "Error toggling usb RNDIS :" + e);
+ return false;
+ }
+ return true;
+ }
+
+ // configured when we start tethering and unconfig'd on error or conclusion
+ private boolean configureUsbIface(boolean enabled) {
+ Log.d(TAG, "configureUsbIface(" + enabled + ")");
+
+ IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
+ INetworkManagementService service = INetworkManagementService.Stub.asInterface(b);
+
+ // bring toggle the interfaces
+ String[] ifaces = new String[0];
+ try {
+ ifaces = service.listInterfaces();
+ } catch (Exception e) {
+ Log.e(TAG, "Error listing Interfaces :" + e);
+ return false;
+ }
+ for (String iface : ifaces) {
+ for (String regex : mTetherableUsbRegexs) {
+ if (iface.matches(regex)) {
+ InterfaceConfiguration ifcg = null;
+ try {
+ ifcg = service.getInterfaceConfig(iface);
+ if (ifcg != null) {
+ ifcg.ipAddr = (169 << 24) + (254 << 16) + (2 << 8) + 1;
+ ifcg.netmask = (255 << 24) + (255 << 16) + (255 << 8) + 0;
+ if (enabled) {
+ ifcg.interfaceFlags = ifcg.interfaceFlags.replace("down", "up");
+ } else {
+ ifcg.interfaceFlags = ifcg.interfaceFlags.replace("up", "down");
+ // TODO - clean this up - maybe a better regex?
+ ifcg.interfaceFlags = ifcg.interfaceFlags.replace(" running", "");
+ ifcg.interfaceFlags = ifcg.interfaceFlags.replace("running ","");
+ ifcg.interfaceFlags = ifcg.interfaceFlags.replace("running","");
+ }
+ service.setInterfaceConfig(iface, ifcg);
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "Error configuring interface " + iface + ", :" + e);
+ return false;
+ }
+ }
+ }
+ }
+
+ return true;
+ }
+
private void handleTtyConnect() {
Log.d(TAG, "handleTtyConnect");
// for each of the available Tty not already supported by a ppp session,
@@ -609,6 +729,7 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
private HierarchicalState mUntetherInterfaceErrorState;
private HierarchicalState mEnableNatErrorState;
private HierarchicalState mDisableNatErrorState;
+ private HierarchicalState mUsbConfigurationErrorState;
private HierarchicalState mUnavailableState;
@@ -617,10 +738,12 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
private boolean mTethered;
String mIfaceName;
+ boolean mUsb;
- TetherInterfaceSM(String name) {
+ TetherInterfaceSM(String name, boolean usb) {
super(name);
mIfaceName = name;
+ mUsb = usb;
mInitialState = new InitialState();
addState(mInitialState);
@@ -638,6 +761,8 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
addState(mEnableNatErrorState);
mDisableNatErrorState = new DisableNatErrorState();
addState(mDisableNatErrorState);
+ mUsbConfigurationErrorState = new UsbConfigurationErrorState();
+ addState(mUsbConfigurationErrorState);
mUnavailableState = new UnavailableState();
addState(mUnavailableState);
@@ -656,6 +781,7 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
if (current == mUntetherInterfaceErrorState) res += "UntetherInterfaceErrorState";
if (current == mEnableNatErrorState) res += "EnableNatErrorState";
if (current == mDisableNatErrorState) res += "DisableNatErrorState";
+ if (current == mUsbConfigurationErrorState) res += "UsbConfigurationErrorState";
if (current == mUnavailableState) res += "UnavailableState";
if (mAvailable) res += " - Available";
if (mTethered) res += " - Tethered";
@@ -686,8 +812,15 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
return mErrored;
}
- private synchronized void setErrored(boolean errored) {
- mErrored = errored;
+ private void setErrored(boolean errored) {
+ synchronized (this) {
+ mErrored = errored;
+ }
+ if (errored && mUsb) {
+ // note everything's been unwound by this point so nothing to do on
+ // further error..
+ Tethering.this.configureUsbIface(false);
+ }
}
class InitialState extends HierarchicalState {
@@ -726,6 +859,19 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
@Override
public void enter() {
setAvailable(false);
+ if (mUsb) {
+ if (!Tethering.this.configureUsbIface(true)) {
+ Message m = mTetherMasterSM.obtainMessage(
+ TetherMasterSM.CMD_TETHER_MODE_UNREQUESTED);
+ m.obj = TetherInterfaceSM.this;
+ mTetherMasterSM.sendMessage(m);
+
+ m = obtainMessage(CMD_TRANSITION_TO_ERROR);
+ m.obj = mUsbConfigurationErrorState;
+ sendMessageAtFrontOfQueue(m);
+ return;
+ }
+ }
sendTetherStateChangedBroadcast();
}
@Override
@@ -739,6 +885,12 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
TetherMasterSM.CMD_TETHER_MODE_UNREQUESTED);
m.obj = TetherInterfaceSM.this;
mTetherMasterSM.sendMessage(m);
+ if (mUsb) {
+ if (!Tethering.this.configureUsbIface(false)) {
+ transitionTo(mUsbConfigurationErrorState);
+ break;
+ }
+ }
transitionTo(mInitialState);
break;
case CMD_TETHER_MODE_ALIVE:
@@ -759,6 +911,10 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
mTetherMasterSM.sendMessage(m);
transitionTo(mUnavailableState);
break;
+ case CMD_TRANSITION_TO_ERROR:
+ HierarchicalState s = (HierarchicalState)(message.obj);
+ transitionTo(s);
+ break;
default:
retValue = false;
}
@@ -788,12 +944,17 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
sendMessageAtFrontOfQueue(m);
return;
}
+ if (mUsb) Tethering.this.enableUsbRndis(true);
Log.d(TAG, "Tethered " + mIfaceName);
setAvailable(false);
setTethered(true);
sendTetherStateChangedBroadcast();
}
@Override
+ public void exit() {
+ if (mUsb) Tethering.this.enableUsbRndis(false);
+ }
+ @Override
public boolean processMessage(Message message) {
Log.d(TAG, "TetheredState.processMessage what=" + message.what);
boolean retValue = true;
@@ -821,12 +982,19 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
m.obj = TetherInterfaceSM.this;
mTetherMasterSM.sendMessage(m);
if (message.what == CMD_TETHER_UNREQUESTED) {
- transitionTo(mInitialState);
+ if (mUsb) {
+ if (!Tethering.this.configureUsbIface(false)) {
+ transitionTo(mUsbConfigurationErrorState);
+ } else {
+ transitionTo(mInitialState);
+ }
+ } else {
+ transitionTo(mInitialState);
+ }
} else if (message.what == CMD_INTERFACE_DOWN) {
transitionTo(mUnavailableState);
}
Log.d(TAG, "Untethered " + mIfaceName);
- sendTetherStateChangedBroadcast();
break;
case CMD_CELL_DUN_ERROR:
case CMD_IP_FORWARDING_ENABLE_ERROR:
@@ -857,6 +1025,12 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
}
Log.d(TAG, "Tether lost upstream connection " + mIfaceName);
sendTetherStateChangedBroadcast();
+ if (mUsb) {
+ if (!Tethering.this.configureUsbIface(false)) {
+ transitionTo(mUsbConfigurationErrorState);
+ break;
+ }
+ }
transitionTo(mInitialState);
break;
case CMD_TRANSITION_TO_ERROR:
@@ -974,6 +1148,15 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
sendTetherStateChangedBroadcast();
}
}
+
+ class UsbConfigurationErrorState extends ErrorState {
+ @Override
+ public void enter() {
+ Log.e(TAG, "Error trying to configure USB " + mIfaceName);
+ setAvailable(false);
+ setErrored(true);
+ }
+ }
}
class TetherMasterSM extends HierarchicalStateMachine {
@@ -1000,7 +1183,6 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
private HierarchicalState mCellDunRequestedState;
private HierarchicalState mCellDunAliveState;
private HierarchicalState mTetherModeAliveState;
- private HierarchicalState mCellDunUnRequestedState;
private HierarchicalState mCellDunErrorState;
private HierarchicalState mSetIpForwardingEnabledErrorState;
@@ -1028,8 +1210,6 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
addState(mCellDunAliveState);
mTetherModeAliveState = new TetherModeAliveState();
addState(mTetherModeAliveState);
- mCellDunUnRequestedState = new CellDunUnRequestedState();
- addState(mCellDunUnRequestedState);
mCellDunErrorState = new CellDunErrorState();
addState(mCellDunErrorState);
@@ -1049,8 +1229,81 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
setInitialState(mInitialState);
}
+ class TetherMasterUtilState extends HierarchicalState {
+ @Override
+ public boolean processMessage(Message m) {
+ return false;
+ }
+ public int turnOnMobileDun() {
+ IBinder b = ServiceManager.getService(Context.CONNECTIVITY_SERVICE);
+ IConnectivityManager service = IConnectivityManager.Stub.asInterface(b);
+ int retValue = Phone.APN_REQUEST_FAILED;
+ try {
+ retValue = service.startUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE,
+ Phone.FEATURE_ENABLE_DUN, new Binder());
+ } catch (Exception e) {
+ }
+ return retValue;
+ }
+ public boolean turnOffMobileDun() {
+ IBinder b = ServiceManager.getService(Context.CONNECTIVITY_SERVICE);
+ IConnectivityManager service =
+ IConnectivityManager.Stub.asInterface(b);
+ try {
+ service.stopUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE,
+ Phone.FEATURE_ENABLE_DUN);
+ } catch (Exception e) {
+ return false;
+ }
+ return true;
+ }
+ public boolean turnOnMasterTetherSettings() {
+ IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
+ INetworkManagementService service =
+ INetworkManagementService.Stub.asInterface(b);
+ try {
+ service.setIpForwardingEnabled(true);
+ } catch (Exception e) {
+ transitionTo(mSetIpForwardingEnabledErrorState);
+ return false;
+ }
+ try {
+ service.startTethering(mDhcpRange[0], mDhcpRange[1]);
+ } catch (Exception e) {
+ transitionTo(mStartTetheringErrorState);
+ return false;
+ }
+ try {
+ service.setDnsForwarders(mDnsServers);
+ } catch (Exception e) {
+ transitionTo(mSetDnsForwardersErrorState);
+ return false;
+ }
+ transitionTo(mTetherModeAliveState);
+ return true;
+ }
+ public boolean turnOffMasterTetherSettings() {
+ IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
+ INetworkManagementService service =
+ INetworkManagementService.Stub.asInterface(b);
+ try {
+ service.stopTethering();
+ } catch (Exception e) {
+ transitionTo(mStopTetheringErrorState);
+ return false;
+ }
+ try {
+ service.setIpForwardingEnabled(false);
+ } catch (Exception e) {
+ transitionTo(mSetIpForwardingDisabledErrorState);
+ return false;
+ }
+ transitionTo(mInitialState);
+ return true;
+ }
+ }
- class InitialState extends HierarchicalState {
+ class InitialState extends TetherMasterUtilState {
@Override
public boolean processMessage(Message message) {
Log.d(TAG, "MasterInitialState.processMessage what=" + message.what);
@@ -1080,20 +1333,11 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
return retValue;
}
}
- class CellDunRequestedState extends HierarchicalState {
+ class CellDunRequestedState extends TetherMasterUtilState {
@Override
public void enter() {
++mSequenceNumber;
- IBinder b = ServiceManager.getService(Context.CONNECTIVITY_SERVICE);
- IConnectivityManager service =
- IConnectivityManager.Stub.asInterface(b);
- int result;
- try {
- result = service.startUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE,
- Phone.FEATURE_ENABLE_DUN, new Binder());
- } catch (Exception e) {
- result = Phone.APN_REQUEST_FAILED;
- }
+ int result = turnOnMobileDun();
switch (result) {
case Phone.APN_ALREADY_ACTIVE:
Log.d(TAG, "Dun already active");
@@ -1132,34 +1376,13 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
if (index != -1) {
mNotifyList.remove(index);
if (mNotifyList.isEmpty()) {
- transitionTo(mCellDunUnRequestedState);
+ turnOffMobileDun();
+ transitionTo(mInitialState);
}
}
break;
case CMD_CELL_DUN_ENABLED:
- IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
- INetworkManagementService service =
- INetworkManagementService.Stub.asInterface(b);
-
- try {
- service.setIpForwardingEnabled(true);
- } catch (Exception e) {
- transitionTo(mSetIpForwardingEnabledErrorState);
- break;
- }
- try {
- service.startTethering(mDhcpRange[0], mDhcpRange[1]);
- } catch (Exception e) {
- transitionTo(mStartTetheringErrorState);
- break;
- }
- try {
- service.setDnsForwarders(mDnsServers);
- } catch (Exception e) {
- transitionTo(mSetDnsForwardersErrorState);
- break;
- }
- transitionTo(mTetherModeAliveState);
+ turnOnMasterTetherSettings();
break;
case CMD_CELL_DUN_DISABLED:
break;
@@ -1176,9 +1399,10 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
}
}
- class CellDunAliveState extends HierarchicalState {
+ class CellDunAliveState extends TetherMasterUtilState {
@Override
public void enter() {
+ Log.d(TAG, "renewing Dun in " + CELL_DUN_RENEW_MS + "ms");
sendMessageDelayed(obtainMessage(CMD_CELL_DUN_RENEW), CELL_DUN_RENEW_MS);
}
@@ -1190,29 +1414,7 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
case CMD_TETHER_MODE_REQUESTED:
TetherInterfaceSM who = (TetherInterfaceSM)message.obj;
mNotifyList.add(who);
- IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
- INetworkManagementService service =
- INetworkManagementService.Stub.asInterface(b);
-
- try {
- service.setIpForwardingEnabled(true);
- } catch (Exception e) {
- transitionTo(mSetIpForwardingEnabledErrorState);
- break;
- }
- try {
- service.startTethering(mDhcpRange[0], mDhcpRange[1]);
- } catch (Exception e) {
- transitionTo(mStartTetheringErrorState);
- break;
- }
- try {
- service.setDnsForwarders(mDnsServers);
- } catch (Exception e) {
- transitionTo(mSetDnsForwardersErrorState);
- break;
- }
- transitionTo(mTetherModeAliveState);
+ turnOnMasterTetherSettings();
break;
case CMD_TETHER_MODE_UNREQUESTED:
who = (TetherInterfaceSM)message.obj;
@@ -1220,7 +1422,8 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
if (index != -1) {
mNotifyList.remove(index);
if (mNotifyList.isEmpty()) {
- transitionTo(mCellDunUnRequestedState);
+ turnOffMobileDun();
+ transitionTo(mInitialState);
}
}
break;
@@ -1228,13 +1431,9 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
transitionTo(mInitialState);
break;
case CMD_CELL_DUN_RENEW:
- b = ServiceManager.getService(Context.CONNECTIVITY_SERVICE);
- IConnectivityManager cservice = IConnectivityManager.Stub.asInterface(b);
- try {
- cservice.startUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE,
- Phone.FEATURE_ENABLE_DUN, new Binder());
- } catch (Exception e) {
- }
+ Log.d(TAG, "renewing dun connection - requeuing for another " +
+ CELL_DUN_RENEW_MS + "ms");
+ turnOnMobileDun();
sendMessageDelayed(obtainMessage(CMD_CELL_DUN_RENEW), CELL_DUN_RENEW_MS);
break;
default:
@@ -1245,9 +1444,11 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
}
}
- class TetherModeAliveState extends HierarchicalState {
+ class TetherModeAliveState extends TetherMasterUtilState {
@Override
public void enter() {
+ Log.d(TAG, "renewing Dun in " + CELL_DUN_RENEW_MS + "ms");
+ sendMessageDelayed(obtainMessage(CMD_CELL_DUN_RENEW), CELL_DUN_RENEW_MS);
for (Object o : mNotifyList) {
TetherInterfaceSM sm = (TetherInterfaceSM)o;
sm.sendMessage(sm.obtainMessage(TetherInterfaceSM.CMD_TETHER_MODE_ALIVE));
@@ -1269,7 +1470,8 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
if (index != -1) {
mNotifyList.remove(index);
if (mNotifyList.isEmpty()) {
- transitionTo(mCellDunUnRequestedState);
+ turnOffMobileDun();
+ turnOffMasterTetherSettings(); // transitions appropriately
}
}
break;
@@ -1281,22 +1483,13 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
sm.sendMessage(sm.obtainMessage(
TetherInterfaceSM.CMD_TETHER_MODE_DEAD));
}
- IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
- INetworkManagementService service =
- INetworkManagementService.Stub.asInterface(b);
- try {
- service.stopTethering();
- } catch (Exception e) {
- transitionTo(mStopTetheringErrorState);
- break;
- }
- try {
- service.setIpForwardingEnabled(false);
- } catch (Exception e) {
- transitionTo(mSetIpForwardingDisabledErrorState);
- break;
- }
- transitionTo(mInitialState);
+ turnOffMasterTetherSettings(); // transitions appropriately
+ break;
+ case CMD_CELL_DUN_RENEW:
+ Log.d(TAG, "renewing dun connection - requeuing for another " +
+ CELL_DUN_RENEW_MS + "ms");
+ turnOnMobileDun();
+ sendMessageDelayed(obtainMessage(CMD_CELL_DUN_RENEW), CELL_DUN_RENEW_MS);
break;
default:
retValue = false;
@@ -1306,58 +1499,6 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
}
}
- class CellDunUnRequestedState extends HierarchicalState {
- @Override
- public void enter() {
- IBinder b = ServiceManager.getService(Context.CONNECTIVITY_SERVICE);
- IConnectivityManager service =
- IConnectivityManager.Stub.asInterface(b);
- NetworkInfo dunInfo = null;
- try {
- dunInfo = service.getNetworkInfo(ConnectivityManager.TYPE_MOBILE_DUN);
- } catch (Exception e) {}
- if (dunInfo != null && !dunInfo.isConnectedOrConnecting()) {
- sendMessage(obtainMessage(CMD_CELL_DUN_DISABLED));
- return;
- }
- try {
- service.stopUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE,
- Phone.FEATURE_ENABLE_DUN);
- } catch (Exception e) {}
- Message m = obtainMessage(CMD_CELL_DUN_TIMEOUT);
- m.arg1 = ++mSequenceNumber;
- // use a short timeout - this will often be a no-op and
- // we just want this request to get into the queue before we
- // try again.
- sendMessageDelayed(m, CELL_DISABLE_DUN_TIMEOUT_MS);
- }
- @Override
- public boolean processMessage(Message message) {
- Log.d(TAG, "CellDunUnRequestedState.processMessage what=" + message.what);
- boolean retValue = true;
- switch (message.what) {
- case CMD_TETHER_MODE_REQUESTED:
- case CMD_TETHER_MODE_UNREQUESTED:
- deferMessage(message);
- break;
- case CMD_CELL_DUN_DISABLED:
- transitionTo(mInitialState);
- break;
- case CMD_CELL_DUN_TIMEOUT:
- // if we aren't using a sep apn, we won't get a disconnect broadcast..
- // just go back to initial after our short pause
- if (message.arg1 == mSequenceNumber) {
- transitionTo(mInitialState);
- }
- break;
- default:
- retValue = false;
- break;
- }
- return retValue;
- }
- }
-
class ErrorState extends HierarchicalState {
int mErrorNotification;
@Override
diff --git a/services/java/com/android/server/status/ExpandedView.java b/services/java/com/android/server/status/ExpandedView.java
index d0f14cb..33ac8c1 100644
--- a/services/java/com/android/server/status/ExpandedView.java
+++ b/services/java/com/android/server/status/ExpandedView.java
@@ -11,17 +11,11 @@ import android.util.Log;
public class ExpandedView extends LinearLayout {
- final Display mDisplay;
StatusBarService mService;
- boolean mTracking;
- int mStartX, mStartY;
- int mMaxHeight = 0;
int mPrevHeight = -1;
public ExpandedView(Context context, AttributeSet attrs) {
super(context, attrs);
- mDisplay = ((WindowManager)context.getSystemService(
- Context.WINDOW_SERVICE)).getDefaultDisplay();
}
@Override
@@ -36,12 +30,6 @@ public class ExpandedView extends LinearLayout {
}
@Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- super.onMeasure(widthMeasureSpec,
- MeasureSpec.makeMeasureSpec(mMaxHeight, MeasureSpec.AT_MOST));
- }
-
- @Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
int height = bottom - top;
@@ -51,11 +39,4 @@ public class ExpandedView extends LinearLayout {
mService.updateExpandedViewPos(StatusBarService.EXPANDED_LEAVE_ALONE);
}
}
-
- void setMaxHeight(int h) {
- if (h != mMaxHeight) {
- mMaxHeight = h;
- requestLayout();
- }
- }
}
diff --git a/services/java/com/android/server/status/StatusBarPolicy.java b/services/java/com/android/server/status/StatusBarPolicy.java
index d13f9d3..f1ccb9b 100644
--- a/services/java/com/android/server/status/StatusBarPolicy.java
+++ b/services/java/com/android/server/status/StatusBarPolicy.java
@@ -826,7 +826,10 @@ public class StatusBarPolicy {
final Uri soundUri = Uri.parse("file://" + soundPath);
if (soundUri != null) {
final Ringtone sfx = RingtoneManager.getRingtone(mContext, soundUri);
- if (sfx != null) sfx.play();
+ if (sfx != null) {
+ sfx.setStreamType(AudioManager.STREAM_SYSTEM);
+ sfx.play();
+ }
}
}
}
diff --git a/services/java/com/android/server/status/StatusBarService.java b/services/java/com/android/server/status/StatusBarService.java
index 493bd93..3f77291 100644
--- a/services/java/com/android/server/status/StatusBarService.java
+++ b/services/java/com/android/server/status/StatusBarService.java
@@ -187,8 +187,9 @@ public class StatusBarService extends IStatusBar.Stub
TextView mSpnLabel;
TextView mPlmnLabel;
TextView mClearButton;
+ View mExpandedContents;
CloseDragHandle mCloseView;
- int[] mCloseLocation = new int[2];
+ int[] mPositionTmp = new int[2];
boolean mExpanded;
boolean mExpandedVisible;
@@ -198,7 +199,7 @@ public class StatusBarService extends IStatusBar.Stub
// the tracker view
TrackingView mTrackingView;
WindowManager.LayoutParams mTrackingParams;
- int mTrackingPosition;
+ int mTrackingPosition; // the position of the top of the tracking view.
// ticker
private Ticker mTicker;
@@ -274,6 +275,7 @@ public class StatusBarService extends IStatusBar.Stub
mExpandedDialog = new ExpandedDialog(context);
mExpandedView = expanded;
+ mExpandedContents = expanded.findViewById(R.id.notificationLinearLayout);
mOngoingTitle = (TextView)expanded.findViewById(R.id.ongoingTitle);
mOngoingItems = (LinearLayout)expanded.findViewById(R.id.ongoingItems);
mLatestTitle = (TextView)expanded.findViewById(R.id.latestTitle);
@@ -1530,20 +1532,11 @@ public class StatusBarService extends IStatusBar.Stub
/// ---------- Expanded View --------------
pixelFormat = PixelFormat.TRANSLUCENT;
- bg = mExpandedView.getBackground();
- if (bg != null) {
- pixelFormat = bg.getOpacity();
- if (pixelFormat != PixelFormat.TRANSLUCENT) {
- // we want good-looking gradients, so we force a 8-bits per
- // pixel format.
- pixelFormat = PixelFormat.RGBX_8888;
- }
- }
final int disph = mDisplay.getHeight();
lp = mExpandedDialog.getWindow().getAttributes();
lp.width = ViewGroup.LayoutParams.MATCH_PARENT;
- lp.height = ViewGroup.LayoutParams.WRAP_CONTENT;
+ lp.height = getExpandedHeight();
lp.x = 0;
mTrackingPosition = lp.y = -disph; // sufficiently large negative
lp.type = WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL;
@@ -1562,10 +1555,10 @@ public class StatusBarService extends IStatusBar.Stub
mExpandedDialog.getWindow().requestFeature(Window.FEATURE_NO_TITLE);
mExpandedDialog.setContentView(mExpandedView,
new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
- ViewGroup.LayoutParams.WRAP_CONTENT));
+ ViewGroup.LayoutParams.MATCH_PARENT));
+ mExpandedDialog.getWindow().setBackgroundDrawable(null);
mExpandedDialog.show();
FrameLayout hack = (FrameLayout)mExpandedView.getParent();
- hack.setForeground(null);
}
void setDateViewVisibility(boolean visible, int anim) {
@@ -1630,11 +1623,15 @@ public class StatusBarService extends IStatusBar.Stub
mTrackingParams.height = disph-h;
WindowManagerImpl.getDefault().updateViewLayout(mTrackingView, mTrackingParams);
- mCloseView.getLocationInWindow(mCloseLocation);
-
if (mExpandedParams != null) {
+ mCloseView.getLocationInWindow(mPositionTmp);
+ final int closePos = mPositionTmp[1];
+
+ mExpandedContents.getLocationInWindow(mPositionTmp);
+ final int contentsBottom = mPositionTmp[1] + mExpandedContents.getHeight();
+
mExpandedParams.y = pos + mTrackingView.getHeight()
- - (mTrackingParams.height-mCloseLocation[1]) - mExpandedView.getHeight();
+ - (mTrackingParams.height-closePos) - contentsBottom;
int max = h;
if (mExpandedParams.y > max) {
mExpandedParams.y = max;
@@ -1644,13 +1641,13 @@ public class StatusBarService extends IStatusBar.Stub
mExpandedParams.y = min;
}
- /*
- Log.d(TAG, "mTrackingPosition=" + mTrackingPosition
- + " mTrackingView.height=" + mTrackingView.getHeight()
- + " diff=" + (mTrackingPosition + mTrackingView.getHeight())
- + " h=" + h);
- */
- panelSlightlyVisible((mTrackingPosition + mTrackingView.getHeight()) > h);
+ boolean visible = (mTrackingPosition + mTrackingView.getHeight()) > h;
+ if (!visible) {
+ // if the contents aren't visible, move the expanded view way off screen
+ // because the window itself extends below the content view.
+ mExpandedParams.y = -disph;
+ }
+ panelSlightlyVisible(visible);
mExpandedDialog.getWindow().setAttributes(mExpandedParams);
}
@@ -1658,16 +1655,19 @@ public class StatusBarService extends IStatusBar.Stub
Log.d(TAG, "updateExpandedViewPos after expandedPosition=" + expandedPosition
+ " mTrackingParams.y=" + mTrackingParams.y
+ " mTrackingPosition=" + mTrackingPosition
- + " mExpandedParams.y=" + mExpandedParams.y);
+ + " mExpandedParams.y=" + mExpandedParams.y
+ + " mExpandedParams.height=" + mExpandedParams.height);
}
}
- void updateAvailableHeight() {
+ int getExpandedHeight() {
+ return mDisplay.getHeight() - mStatusBarView.getHeight() - mCloseView.getHeight();
+ }
+
+ void updateExpandedHeight() {
if (mExpandedView != null) {
- int disph = mDisplay.getHeight();
- int h = mStatusBarView.getHeight();
- int max = disph - (mCloseView.getHeight() + h);
- mExpandedView.setMaxHeight(max);
+ mExpandedParams.height = getExpandedHeight();
+ mExpandedDialog.getWindow().setAttributes(mExpandedParams);
}
}
diff --git a/services/java/com/android/server/status/StorageNotification.java b/services/java/com/android/server/status/StorageNotification.java
index 3b79049..e0b288d 100644
--- a/services/java/com/android/server/status/StorageNotification.java
+++ b/services/java/com/android/server/status/StorageNotification.java
@@ -36,6 +36,7 @@ import android.os.ServiceManager;
import android.os.storage.StorageEventListener;
import android.os.storage.StorageManager;
import android.os.storage.StorageResultCode;
+import android.provider.Settings;
import android.util.Log;
import android.view.View;
import android.widget.Button;
@@ -46,6 +47,8 @@ import android.widget.Toast;
public class StorageNotification extends StorageEventListener {
private static final String TAG = "StorageNotification";
+ private static final boolean POP_UMS_ACTIVITY_ON_CONNECT = true;
+
/**
* Binder context for this service
*/
@@ -239,12 +242,28 @@ public class StorageNotification extends StorageEventListener {
Intent intent = new Intent();
intent.setClass(mContext, com.android.server.status.UsbStorageActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+
+ final boolean adbOn = 1 == Settings.Secure.getInt(
+ mContext.getContentResolver(),
+ Settings.Secure.ADB_ENABLED,
+ 0);
+
PendingIntent pi = PendingIntent.getActivity(mContext, 0, intent, 0);
setUsbStorageNotification(
com.android.internal.R.string.usb_storage_notification_title,
com.android.internal.R.string.usb_storage_notification_message,
com.android.internal.R.drawable.stat_sys_data_usb,
false, true, pi);
+
+ if (POP_UMS_ACTIVITY_ON_CONNECT && !adbOn) {
+ // We assume that developers don't want to enable UMS every
+ // time they attach a device to a USB host. The average user,
+ // however, is looking to charge the phone (in which case this
+ // is harmless) or transfer files (in which case this coaches
+ // the user about how to complete that task and saves several
+ // steps).
+ mContext.startActivity(intent);
+ }
} else {
setUsbStorageNotification(0, 0, 0, false, false, null);
}
diff --git a/services/java/com/android/server/status/TrackingView.java b/services/java/com/android/server/status/TrackingView.java
index 722d10c..886d66d 100644
--- a/services/java/com/android/server/status/TrackingView.java
+++ b/services/java/com/android/server/status/TrackingView.java
@@ -23,7 +23,7 @@ public class TrackingView extends LinearLayout {
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
- mService.updateAvailableHeight();
+ mService.updateExpandedHeight();
}
@Override
diff --git a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
index 52c8b1f..cab7b81 100644
--- a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
@@ -440,10 +440,11 @@ public abstract class DataConnectionTracker extends Handler {
return Phone.APN_REQUEST_FAILED;
}
- if(DBG) Log.d(LOG_TAG, "enableApnType("+type+"), isApnTypeActive = "
+ if (DBG) Log.d(LOG_TAG, "enableApnType("+type+"), isApnTypeActive = "
+ isApnTypeActive(type) + " and state = " + state);
if (!isApnTypeAvailable(type)) {
+ if (DBG) Log.d(LOG_TAG, "type not available");
return Phone.APN_TYPE_NOT_AVAILABLE;
}
diff --git a/telephony/java/com/android/internal/telephony/IccPhoneBookInterfaceManager.java b/telephony/java/com/android/internal/telephony/IccPhoneBookInterfaceManager.java
index 31cf6a7..9f8e57f 100644
--- a/telephony/java/com/android/internal/telephony/IccPhoneBookInterfaceManager.java
+++ b/telephony/java/com/android/internal/telephony/IccPhoneBookInterfaceManager.java
@@ -22,10 +22,7 @@ import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.ServiceManager;
-import android.telephony.PhoneNumberUtils;
-import android.util.Log;
-import java.util.ArrayList;
import java.util.List;
/**
@@ -37,7 +34,7 @@ public abstract class IccPhoneBookInterfaceManager extends IIccPhoneBook.Stub {
protected PhoneBase phone;
protected AdnRecordCache adnCache;
- protected Object mLock = new Object();
+ protected final Object mLock = new Object();
protected int recordSize[];
protected boolean success;
protected List<AdnRecord> records;
@@ -80,8 +77,7 @@ public abstract class IccPhoneBookInterfaceManager extends IIccPhoneBook.Stub {
ar = (AsyncResult)msg.obj;
synchronized (mLock) {
if (ar.exception == null) {
- records = (List<AdnRecord>)
- ((ArrayList<AdnRecord>) ar.result);
+ records = (List<AdnRecord>) ar.result;
} else {
if(DBG) logd("Cannot load ADN records");
if (records != null) {
diff --git a/telephony/java/com/android/internal/telephony/IccProvider.java b/telephony/java/com/android/internal/telephony/IccProvider.java
index 4232887..fa91457 100644
--- a/telephony/java/com/android/internal/telephony/IccProvider.java
+++ b/telephony/java/com/android/internal/telephony/IccProvider.java
@@ -19,8 +19,9 @@ package com.android.internal.telephony;
import android.content.ContentProvider;
import android.content.UriMatcher;
import android.content.ContentValues;
-import com.android.common.ArrayListCursor;
+import android.database.AbstractCursor;
import android.database.Cursor;
+import android.database.CursorWindow;
import android.net.Uri;
import android.os.SystemProperties;
import android.os.RemoteException;
@@ -35,6 +36,149 @@ import com.android.internal.telephony.IccConstants;
import com.android.internal.telephony.AdnRecord;
import com.android.internal.telephony.IIccPhoneBook;
+/**
+ * XXX old code -- should be replaced with MatrixCursor.
+ * @deprecated This is has been replaced by MatrixCursor.
+*/
+class ArrayListCursor extends AbstractCursor {
+ private String[] mColumnNames;
+ private ArrayList<Object>[] mRows;
+
+ @SuppressWarnings({"unchecked"})
+ public ArrayListCursor(String[] columnNames, ArrayList<ArrayList> rows) {
+ int colCount = columnNames.length;
+ boolean foundID = false;
+ // Add an _id column if not in columnNames
+ for (int i = 0; i < colCount; ++i) {
+ if (columnNames[i].compareToIgnoreCase("_id") == 0) {
+ mColumnNames = columnNames;
+ foundID = true;
+ break;
+ }
+ }
+
+ if (!foundID) {
+ mColumnNames = new String[colCount + 1];
+ System.arraycopy(columnNames, 0, mColumnNames, 0, columnNames.length);
+ mColumnNames[colCount] = "_id";
+ }
+
+ int rowCount = rows.size();
+ mRows = new ArrayList[rowCount];
+
+ for (int i = 0; i < rowCount; ++i) {
+ mRows[i] = rows.get(i);
+ if (!foundID) {
+ mRows[i].add(i);
+ }
+ }
+ }
+
+ @Override
+ public void fillWindow(int position, CursorWindow window) {
+ if (position < 0 || position > getCount()) {
+ return;
+ }
+
+ window.acquireReference();
+ try {
+ int oldpos = mPos;
+ mPos = position - 1;
+ window.clear();
+ window.setStartPosition(position);
+ int columnNum = getColumnCount();
+ window.setNumColumns(columnNum);
+ while (moveToNext() && window.allocRow()) {
+ for (int i = 0; i < columnNum; i++) {
+ final Object data = mRows[mPos].get(i);
+ if (data != null) {
+ if (data instanceof byte[]) {
+ byte[] field = (byte[]) data;
+ if (!window.putBlob(field, mPos, i)) {
+ window.freeLastRow();
+ break;
+ }
+ } else {
+ String field = data.toString();
+ if (!window.putString(field, mPos, i)) {
+ window.freeLastRow();
+ break;
+ }
+ }
+ } else {
+ if (!window.putNull(mPos, i)) {
+ window.freeLastRow();
+ break;
+ }
+ }
+ }
+ }
+
+ mPos = oldpos;
+ } catch (IllegalStateException e){
+ // simply ignore it
+ } finally {
+ window.releaseReference();
+ }
+ }
+
+ @Override
+ public int getCount() {
+ return mRows.length;
+ }
+
+ @Override
+ public String[] getColumnNames() {
+ return mColumnNames;
+ }
+
+ @Override
+ public byte[] getBlob(int columnIndex) {
+ return (byte[]) mRows[mPos].get(columnIndex);
+ }
+
+ @Override
+ public String getString(int columnIndex) {
+ Object cell = mRows[mPos].get(columnIndex);
+ return (cell == null) ? null : cell.toString();
+ }
+
+ @Override
+ public short getShort(int columnIndex) {
+ Number num = (Number) mRows[mPos].get(columnIndex);
+ return num.shortValue();
+ }
+
+ @Override
+ public int getInt(int columnIndex) {
+ Number num = (Number) mRows[mPos].get(columnIndex);
+ return num.intValue();
+ }
+
+ @Override
+ public long getLong(int columnIndex) {
+ Number num = (Number) mRows[mPos].get(columnIndex);
+ return num.longValue();
+ }
+
+ @Override
+ public float getFloat(int columnIndex) {
+ Number num = (Number) mRows[mPos].get(columnIndex);
+ return num.floatValue();
+ }
+
+ @Override
+ public double getDouble(int columnIndex) {
+ Number num = (Number) mRows[mPos].get(columnIndex);
+ return num.doubleValue();
+ }
+
+ @Override
+ public boolean isNull(int columnIndex) {
+ return mRows[mPos].get(columnIndex) == null;
+ }
+}
+
/**
* {@hide}
diff --git a/telephony/java/com/android/internal/telephony/PhoneSubInfo.java b/telephony/java/com/android/internal/telephony/PhoneSubInfo.java
index 19900c8..1ac2da3 100644
--- a/telephony/java/com/android/internal/telephony/PhoneSubInfo.java
+++ b/telephony/java/com/android/internal/telephony/PhoneSubInfo.java
@@ -39,6 +39,11 @@ public class PhoneSubInfo extends IPhoneSubInfo.Stub {
}
protected void finalize() {
+ try {
+ super.finalize();
+ } catch (Throwable throwable) {
+ Log.e(LOG_TAG, "Error while finalizing:", throwable);
+ }
Log.d(LOG_TAG, "PhoneSubInfo finalized");
}
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
index fbb3c4c..d5f18e0 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
@@ -23,6 +23,8 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
+import android.net.ConnectivityManager;
+import android.net.IConnectivityManager;
import android.net.NetworkInfo;
import android.net.wifi.WifiManager;
import android.os.AsyncResult;
@@ -188,8 +190,16 @@ 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());
+ boolean dataEnabledSetting = true;
+ try {
+ dataEnabledSetting = IConnectivityManager.Stub.asInterface(ServiceManager.
+ getService(Context.CONNECTIVITY_SERVICE)).getMobileDataEnabled();
+ } catch (Exception e) {
+ // nothing to do - use the old behavior and leave data on
+ }
dataEnabled[APN_DEFAULT_ID] =
- !sp.getBoolean(CDMAPhone.DATA_DISABLED_ON_BOOT_KEY, false);
+ !sp.getBoolean(CDMAPhone.DATA_DISABLED_ON_BOOT_KEY, false) &&
+ dataEnabledSetting;
if (dataEnabled[APN_DEFAULT_ID]) {
enabledCount++;
}
diff --git a/telephony/java/com/android/internal/telephony/cdma/EriManager.java b/telephony/java/com/android/internal/telephony/cdma/EriManager.java
index 0e186d0..37c1d55 100644
--- a/telephony/java/com/android/internal/telephony/cdma/EriManager.java
+++ b/telephony/java/com/android/internal/telephony/cdma/EriManager.java
@@ -23,8 +23,8 @@ import android.util.Xml;
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.PhoneBase;
+import com.android.internal.util.XmlUtils;
-import com.android.common.XmlUtils;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
diff --git a/telephony/java/com/android/internal/telephony/cdma/RuimPhoneBookInterfaceManager.java b/telephony/java/com/android/internal/telephony/cdma/RuimPhoneBookInterfaceManager.java
index 78e89d5..6e12f24 100644
--- a/telephony/java/com/android/internal/telephony/cdma/RuimPhoneBookInterfaceManager.java
+++ b/telephony/java/com/android/internal/telephony/cdma/RuimPhoneBookInterfaceManager.java
@@ -16,22 +16,10 @@
package com.android.internal.telephony.cdma;
-import android.content.pm.PackageManager;
-import android.os.AsyncResult;
-import android.os.Handler;
-import android.os.Looper;
import android.os.Message;
-import android.os.ServiceManager;
-import android.telephony.PhoneNumberUtils;
import android.util.Log;
-import com.android.internal.telephony.AdnRecord;
-import com.android.internal.telephony.AdnRecordCache;
import com.android.internal.telephony.IccPhoneBookInterfaceManager;
-import com.android.internal.telephony.PhoneProxy;
-
-import java.util.ArrayList;
-import java.util.List;
/**
* RuimPhoneBookInterfaceManager to provide an inter-process communication to
@@ -42,20 +30,6 @@ import java.util.List;
public class RuimPhoneBookInterfaceManager extends IccPhoneBookInterfaceManager {
static final String LOG_TAG = "CDMA";
-
- Handler mHandler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- AsyncResult ar;
-
- switch(msg.what) {
- default:
- mBaseHandler.handleMessage(msg);
- break;
- }
- }
- };
-
public RuimPhoneBookInterfaceManager(CDMAPhone phone) {
super(phone);
adnCache = phone.mRuimRecords.getAdnCache();
@@ -67,6 +41,11 @@ public class RuimPhoneBookInterfaceManager extends IccPhoneBookInterfaceManager
}
protected void finalize() {
+ try {
+ super.finalize();
+ } catch (Throwable throwable) {
+ Log.e(LOG_TAG, "Error while finalizing:", throwable);
+ }
if(DBG) Log.d(LOG_TAG, "RuimPhoneBookInterfaceManager finalized");
}
diff --git a/telephony/java/com/android/internal/telephony/cdma/RuimSmsInterfaceManager.java b/telephony/java/com/android/internal/telephony/cdma/RuimSmsInterfaceManager.java
index 9439359..cfcfd98 100644
--- a/telephony/java/com/android/internal/telephony/cdma/RuimSmsInterfaceManager.java
+++ b/telephony/java/com/android/internal/telephony/cdma/RuimSmsInterfaceManager.java
@@ -30,6 +30,7 @@ import com.android.internal.telephony.PhoneProxy;
import com.android.internal.telephony.SmsRawData;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
import static android.telephony.SmsManager.STATUS_ON_ICC_FREE;
@@ -89,6 +90,11 @@ public class RuimSmsInterfaceManager extends IccSmsInterfaceManager {
}
protected void finalize() {
+ try {
+ super.finalize();
+ } catch (Throwable throwable) {
+ Log.e(LOG_TAG, "Error while finalizing:", throwable);
+ }
if(DBG) Log.d(LOG_TAG, "RuimSmsInterfaceManager finalized");
}
@@ -143,7 +149,7 @@ public class RuimSmsInterfaceManager extends IccSmsInterfaceManager {
public boolean copyMessageToIccEf(int status, byte[] pdu, byte[] smsc) {
//NOTE smsc not used in RUIM
if (DBG) log("copyMessageToIccEf: status=" + status + " ==> " +
- "pdu=("+ pdu + ")");
+ "pdu=("+ Arrays.toString(pdu) + ")");
enforceReceiveAndSend("Copying message to RUIM");
synchronized(mLock) {
mSuccess = false;
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnection.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnection.java
index 905d5e3..d893ec4 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnection.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnection.java
@@ -18,8 +18,8 @@ package com.android.internal.telephony.gsm;
import android.os.Message;
import android.util.Log;
+import android.util.Patterns;
-import com.android.common.Patterns;
import com.android.internal.telephony.DataConnection;
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.RILConstants;
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
index 1fd6be8..30beaaa 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
@@ -27,6 +27,8 @@ import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.database.ContentObserver;
import android.database.Cursor;
+import android.net.ConnectivityManager;
+import android.net.IConnectivityManager;
import android.net.NetworkInfo;
import android.net.Uri;
import android.net.wifi.WifiManager;
@@ -243,7 +245,15 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
// This preference tells us 1) initial condition for "dataEnabled",
// 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);
+ boolean dataEnabledSetting = true;
+ try {
+ dataEnabledSetting = IConnectivityManager.Stub.asInterface(ServiceManager.
+ getService(Context.CONNECTIVITY_SERVICE)).getMobileDataEnabled();
+ } catch (Exception e) {
+ // nothing to do - use the old behavior and leave data on
+ }
+ dataEnabled[APN_DEFAULT_ID] = !sp.getBoolean(GSMPhone.DATA_DISABLED_ON_BOOT_KEY, false) &&
+ dataEnabledSetting;
if (dataEnabled[APN_DEFAULT_ID]) {
enabledCount++;
}
diff --git a/telephony/java/com/android/internal/telephony/gsm/SimPhoneBookInterfaceManager.java b/telephony/java/com/android/internal/telephony/gsm/SimPhoneBookInterfaceManager.java
index 076da6b..feb508a 100644
--- a/telephony/java/com/android/internal/telephony/gsm/SimPhoneBookInterfaceManager.java
+++ b/telephony/java/com/android/internal/telephony/gsm/SimPhoneBookInterfaceManager.java
@@ -16,22 +16,10 @@
package com.android.internal.telephony.gsm;
-import android.content.pm.PackageManager;
-import android.os.AsyncResult;
-import android.os.Handler;
-import android.os.Looper;
import android.os.Message;
-import android.os.ServiceManager;
-import android.telephony.PhoneNumberUtils;
import android.util.Log;
-import com.android.internal.telephony.AdnRecord;
-import com.android.internal.telephony.AdnRecordCache;
import com.android.internal.telephony.IccPhoneBookInterfaceManager;
-import com.android.internal.telephony.PhoneProxy;
-
-import java.util.ArrayList;
-import java.util.List;
/**
* SimPhoneBookInterfaceManager to provide an inter-process communication to
@@ -42,20 +30,6 @@ import java.util.List;
public class SimPhoneBookInterfaceManager extends IccPhoneBookInterfaceManager {
static final String LOG_TAG = "GSM";
-
- Handler mHandler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- AsyncResult ar;
-
- switch(msg.what) {
- default:
- mBaseHandler.handleMessage(msg);
- break;
- }
- }
- };
-
public SimPhoneBookInterfaceManager(GSMPhone phone) {
super(phone);
adnCache = phone.mSIMRecords.getAdnCache();
@@ -67,6 +41,11 @@ public class SimPhoneBookInterfaceManager extends IccPhoneBookInterfaceManager {
}
protected void finalize() {
+ try {
+ super.finalize();
+ } catch (Throwable throwable) {
+ Log.e(LOG_TAG, "Error while finalizing:", throwable);
+ }
if(DBG) Log.d(LOG_TAG, "SimPhoneBookInterfaceManager finalized");
}
diff --git a/telephony/java/com/android/internal/telephony/gsm/SimSmsInterfaceManager.java b/telephony/java/com/android/internal/telephony/gsm/SimSmsInterfaceManager.java
index 875d8d0..2028ca4 100644
--- a/telephony/java/com/android/internal/telephony/gsm/SimSmsInterfaceManager.java
+++ b/telephony/java/com/android/internal/telephony/gsm/SimSmsInterfaceManager.java
@@ -25,10 +25,10 @@ import android.util.Log;
import com.android.internal.telephony.IccConstants;
import com.android.internal.telephony.IccSmsInterfaceManager;
import com.android.internal.telephony.IccUtils;
-import com.android.internal.telephony.PhoneProxy;
import com.android.internal.telephony.SmsRawData;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
import static android.telephony.SmsManager.STATUS_ON_ICC_FREE;
@@ -65,8 +65,7 @@ public class SimSmsInterfaceManager extends IccSmsInterfaceManager {
ar = (AsyncResult)msg.obj;
synchronized (mLock) {
if (ar.exception == null) {
- mSms = (List<SmsRawData>)
- buildValidRawData((ArrayList<byte[]>) ar.result);
+ mSms = buildValidRawData((ArrayList<byte[]>) ar.result);
} else {
if(DBG) log("Cannot load Sms records");
if (mSms != null)
@@ -88,6 +87,11 @@ public class SimSmsInterfaceManager extends IccSmsInterfaceManager {
}
protected void finalize() {
+ try {
+ super.finalize();
+ } catch (Throwable throwable) {
+ Log.e(LOG_TAG, "Error while finalizing:", throwable);
+ }
if(DBG) Log.d(LOG_TAG, "SimSmsInterfaceManager finalized");
}
@@ -106,7 +110,7 @@ public class SimSmsInterfaceManager extends IccSmsInterfaceManager {
updateMessageOnIccEf(int index, int status, byte[] pdu) {
if (DBG) log("updateMessageOnIccEf: index=" + index +
" status=" + status + " ==> " +
- "("+ pdu + ")");
+ "("+ Arrays.toString(pdu) + ")");
enforceReceiveAndSend("Updating message on SIM");
synchronized(mLock) {
mSuccess = false;
@@ -118,7 +122,7 @@ public class SimSmsInterfaceManager extends IccSmsInterfaceManager {
mPhone.mCM.deleteSmsOnSim(index, response);
} else {
byte[] record = makeSmsRecordData(status, pdu);
- ((SIMFileHandler)mPhone.getIccFileHandler()).updateEFLinearFixed(
+ mPhone.getIccFileHandler().updateEFLinearFixed(
IccConstants.EF_SMS,
index, record, null, response);
}
@@ -142,7 +146,8 @@ public class SimSmsInterfaceManager extends IccSmsInterfaceManager {
*/
public boolean copyMessageToIccEf(int status, byte[] pdu, byte[] smsc) {
if (DBG) log("copyMessageToIccEf: status=" + status + " ==> " +
- "pdu=("+ pdu + "), smsm=(" + smsc +")");
+ "pdu=("+ Arrays.toString(pdu) +
+ "), smsm=(" + Arrays.toString(smsc) +")");
enforceReceiveAndSend("Copying message to SIM");
synchronized(mLock) {
mSuccess = false;
@@ -175,8 +180,7 @@ public class SimSmsInterfaceManager extends IccSmsInterfaceManager {
"Reading messages from SIM");
synchronized(mLock) {
Message response = mHandler.obtainMessage(EVENT_LOAD_DONE);
- ((SIMFileHandler)mPhone.getIccFileHandler()).loadEFLinearFixedAll(IccConstants.EF_SMS,
- response);
+ mPhone.getIccFileHandler().loadEFLinearFixedAll(IccConstants.EF_SMS, response);
try {
mLock.wait();
diff --git a/telephony/java/com/android/internal/telephony/gsm/SpnOverride.java b/telephony/java/com/android/internal/telephony/gsm/SpnOverride.java
index abb0230..9ea30101 100644
--- a/telephony/java/com/android/internal/telephony/gsm/SpnOverride.java
+++ b/telephony/java/com/android/internal/telephony/gsm/SpnOverride.java
@@ -13,7 +13,7 @@ import android.os.Environment;
import android.util.Log;
import android.util.Xml;
-import com.android.common.XmlUtils;
+import com.android.internal.util.XmlUtils;
public class SpnOverride {
private HashMap<String, String> CarrierSpnMap;
diff --git a/telephony/java/com/android/internal/telephony/gsm/VoiceMailConstants.java b/telephony/java/com/android/internal/telephony/gsm/VoiceMailConstants.java
index 0bedd53..0e49e35 100644
--- a/telephony/java/com/android/internal/telephony/gsm/VoiceMailConstants.java
+++ b/telephony/java/com/android/internal/telephony/gsm/VoiceMailConstants.java
@@ -28,7 +28,8 @@ import java.io.IOException;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
-import com.android.common.XmlUtils;
+
+import com.android.internal.util.XmlUtils;
/**
* {@hide}
diff --git a/test-runner/src/android/test/InstrumentationTestRunner.java b/test-runner/src/android/test/InstrumentationTestRunner.java
index 4ae98e6..ee6b89c 100644
--- a/test-runner/src/android/test/InstrumentationTestRunner.java
+++ b/test-runner/src/android/test/InstrumentationTestRunner.java
@@ -19,6 +19,7 @@ package android.test;
import static android.test.suitebuilder.TestPredicates.REJECT_PERFORMANCE;
import com.android.internal.util.Predicate;
+import com.android.internal.util.Predicates;
import android.app.Activity;
import android.app.Instrumentation;
@@ -31,11 +32,14 @@ import android.os.PerformanceCollector.PerformanceResultsWriter;
import android.test.suitebuilder.TestMethod;
import android.test.suitebuilder.TestPredicates;
import android.test.suitebuilder.TestSuiteBuilder;
+import android.test.suitebuilder.annotation.HasAnnotation;
+import android.test.suitebuilder.annotation.LargeTest;
import android.util.Log;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.PrintStream;
+import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
@@ -93,6 +97,18 @@ import junit.textui.ResultPrinter;
* -e size large
* com.android.foo/android.test.InstrumentationTestRunner
* <p/>
+ * <b>Filter test run to tests with given annotation:</b> adb shell am instrument -w
+ * -e annotation com.android.foo.MyAnnotation
+ * com.android.foo/android.test.InstrumentationTestRunner
+ * <p/>
+ * If used with other options, the resulting test run will contain the union of the two options.
+ * e.g. "-e size large -e annotation com.android.foo.MyAnnotation" will run only tests with both
+ * the {@link LargeTest} and "com.android.foo.MyAnnotation" annotations.
+ * <p/>
+ * <b>Filter test run to tests <i>without</i> given annotation:</b> adb shell am instrument -w
+ * -e notAnnotation com.android.foo.MyAnnotation
+ * com.android.foo/android.test.InstrumentationTestRunner
+ * <p/>
* <b>Running a single testcase:</b> adb shell am instrument -w
* -e class com.android.foo.FooTest
* com.android.foo/android.test.InstrumentationTestRunner
@@ -161,6 +177,10 @@ public class InstrumentationTestRunner extends Instrumentation implements TestSu
private static final String LARGE_SUITE = "large";
private static final String ARGUMENT_LOG_ONLY = "log";
+ /** @hide */
+ static final String ARGUMENT_ANNOTATION = "annotation";
+ /** @hide */
+ static final String ARGUMENT_NOT_ANNOTATION = "notAnnotation";
/**
* This constant defines the maximum allowed runtime (in ms) for a test included in the "small"
@@ -274,6 +294,8 @@ public class InstrumentationTestRunner extends Instrumentation implements TestSu
ClassPathPackageInfoSource.setApkPaths(apkPaths);
Predicate<TestMethod> testSizePredicate = null;
+ Predicate<TestMethod> testAnnotationPredicate = null;
+ Predicate<TestMethod> testNotAnnotationPredicate = null;
boolean includePerformance = false;
String testClassesArg = null;
boolean logOnly = false;
@@ -287,6 +309,11 @@ public class InstrumentationTestRunner extends Instrumentation implements TestSu
mPackageOfTests = arguments.getString(ARGUMENT_TEST_PACKAGE);
testSizePredicate = getSizePredicateFromArg(
arguments.getString(ARGUMENT_TEST_SIZE_PREDICATE));
+ testAnnotationPredicate = getAnnotationPredicate(
+ arguments.getString(ARGUMENT_ANNOTATION));
+ testNotAnnotationPredicate = getNotAnnotationPredicate(
+ arguments.getString(ARGUMENT_NOT_ANNOTATION));
+
includePerformance = getBooleanArgument(arguments, ARGUMENT_INCLUDE_PERF);
logOnly = getBooleanArgument(arguments, ARGUMENT_LOG_ONLY);
mCoverage = getBooleanArgument(arguments, "coverage");
@@ -306,6 +333,12 @@ public class InstrumentationTestRunner extends Instrumentation implements TestSu
if (testSizePredicate != null) {
testSuiteBuilder.addRequirements(testSizePredicate);
}
+ if (testAnnotationPredicate != null) {
+ testSuiteBuilder.addRequirements(testAnnotationPredicate);
+ }
+ if (testNotAnnotationPredicate != null) {
+ testSuiteBuilder.addRequirements(testNotAnnotationPredicate);
+ }
if (!includePerformance) {
testSuiteBuilder.addRequirements(REJECT_PERFORMANCE);
}
@@ -406,6 +439,59 @@ public class InstrumentationTestRunner extends Instrumentation implements TestSu
}
}
+ /**
+ * Returns the test predicate object, corresponding to the annotation class value provided via
+ * the {@link ARGUMENT_ANNOTATION} argument.
+ *
+ * @return the predicate or <code>null</code>
+ */
+ private Predicate<TestMethod> getAnnotationPredicate(String annotationClassName) {
+ Class<? extends Annotation> annotationClass = getAnnotationClass(annotationClassName);
+ if (annotationClass != null) {
+ return new HasAnnotation(annotationClass);
+ }
+ return null;
+ }
+
+ /**
+ * Returns the negative test predicate object, corresponding to the annotation class value
+ * provided via the {@link ARGUMENT_NOT_ANNOTATION} argument.
+ *
+ * @return the predicate or <code>null</code>
+ */
+ private Predicate<TestMethod> getNotAnnotationPredicate(String annotationClassName) {
+ Class<? extends Annotation> annotationClass = getAnnotationClass(annotationClassName);
+ if (annotationClass != null) {
+ return Predicates.not(new HasAnnotation(annotationClass));
+ }
+ return null;
+ }
+
+ /**
+ * Helper method to return the annotation class with specified name
+ *
+ * @param annotationClassName the fully qualified name of the class
+ * @return the annotation class or <code>null</code>
+ */
+ private Class<? extends Annotation> getAnnotationClass(String annotationClassName) {
+ if (annotationClassName == null) {
+ return null;
+ }
+ try {
+ Class<?> annotationClass = Class.forName(annotationClassName);
+ if (annotationClass.isAnnotation()) {
+ return (Class<? extends Annotation>)annotationClass;
+ } else {
+ Log.e(LOG_TAG, String.format("Provided annotation value %s is not an Annotation",
+ annotationClassName));
+ }
+ } catch (ClassNotFoundException e) {
+ Log.e(LOG_TAG, String.format("Could not find class for specified annotation %s",
+ annotationClassName));
+ }
+ return null;
+ }
+
@Override
public void onStart() {
Looper.prepare();
@@ -471,7 +557,7 @@ public class InstrumentationTestRunner extends Instrumentation implements TestSu
String coverageFilePath = getCoverageFilePath();
java.io.File coverageFile = new java.io.File(coverageFilePath);
try {
- Class emmaRTClass = Class.forName("com.vladium.emma.rt.RT");
+ Class<?> emmaRTClass = Class.forName("com.vladium.emma.rt.RT");
Method dumpCoverageMethod = emmaRTClass.getMethod("dumpCoverageData",
coverageFile.getClass(), boolean.class, boolean.class);
diff --git a/test-runner/tests/src/android/test/InstrumentationTestRunnerTest.java b/test-runner/tests/src/android/test/InstrumentationTestRunnerTest.java
index d9afd54..6db72ad 100644
--- a/test-runner/tests/src/android/test/InstrumentationTestRunnerTest.java
+++ b/test-runner/tests/src/android/test/InstrumentationTestRunnerTest.java
@@ -109,6 +109,33 @@ public class InstrumentationTestRunnerTest extends TestCase {
assertTrue(mStubAndroidTestRunner.isRun());
}
+ /**
+ * Test that the -e {@link InstrumentationTestRunner.ARGUMENT_ANNOTATION} parameter properly
+ * selects tests.
+ */
+ public void testAnnotationParameter() throws Exception {
+ String expectedTestClassName = AnnotationTest.class.getName();
+ Bundle args = new Bundle();
+ args.putString(InstrumentationTestRunner.ARGUMENT_TEST_CLASS, expectedTestClassName);
+ args.putString(InstrumentationTestRunner.ARGUMENT_ANNOTATION, FlakyTest.class.getName());
+ mInstrumentationTestRunner.onCreate(args);
+ assertTestRunnerCalledWithExpectedParameters(expectedTestClassName, "testAnnotated");
+ }
+
+ /**
+ * Test that the -e {@link InstrumentationTestRunner.ARGUMENT_NOT_ANNOTATION} parameter
+ * properly excludes tests.
+ */
+ public void testNotAnnotationParameter() throws Exception {
+ String expectedTestClassName = AnnotationTest.class.getName();
+ Bundle args = new Bundle();
+ args.putString(InstrumentationTestRunner.ARGUMENT_TEST_CLASS, expectedTestClassName);
+ args.putString(InstrumentationTestRunner.ARGUMENT_NOT_ANNOTATION,
+ FlakyTest.class.getName());
+ mInstrumentationTestRunner.onCreate(args);
+ assertTestRunnerCalledWithExpectedParameters(expectedTestClassName, "testNotAnnotated");
+ }
+
private void assertContentsInOrder(List<TestDescriptor> actual, TestDescriptor... source) {
TestDescriptor[] clonedSource = source.clone();
assertEquals("Unexpected number of items.", clonedSource.length, actual.size());
@@ -269,4 +296,17 @@ public class InstrumentationTestRunnerTest extends TestCase {
}
}
+
+ /**
+ * Annotated test used for validation.
+ */
+ public static class AnnotationTest extends TestCase {
+
+ public void testNotAnnotated() throws Exception {
+ }
+
+ @FlakyTest
+ public void testAnnotated() throws Exception {
+ }
+ }
}
diff --git a/common/tests/res/raw/alt_ip_only.crt b/tests/AndroidTests/res/raw/alt_ip_only.crt
index 3ac9f5a..3ac9f5a 100644
--- a/common/tests/res/raw/alt_ip_only.crt
+++ b/tests/AndroidTests/res/raw/alt_ip_only.crt
diff --git a/common/tests/res/raw/subject_alt_only.crt b/tests/AndroidTests/res/raw/subject_alt_only.crt
index d5808fb..d5808fb 100644
--- a/common/tests/res/raw/subject_alt_only.crt
+++ b/tests/AndroidTests/res/raw/subject_alt_only.crt
diff --git a/common/tests/res/raw/subject_only.crt b/tests/AndroidTests/res/raw/subject_only.crt
index 11b34e7..11b34e7 100644
--- a/common/tests/res/raw/subject_only.crt
+++ b/tests/AndroidTests/res/raw/subject_only.crt
diff --git a/common/tests/res/raw/subject_with_alt_names.crt b/tests/AndroidTests/res/raw/subject_with_alt_names.crt
index 6963c7e..6963c7e 100644
--- a/common/tests/res/raw/subject_with_alt_names.crt
+++ b/tests/AndroidTests/res/raw/subject_with_alt_names.crt
diff --git a/common/tests/res/raw/subject_with_wild_alt_name.crt b/tests/AndroidTests/res/raw/subject_with_wild_alt_name.crt
index 19b1174..19b1174 100644
--- a/common/tests/res/raw/subject_with_wild_alt_name.crt
+++ b/tests/AndroidTests/res/raw/subject_with_wild_alt_name.crt
diff --git a/common/tests/res/raw/wild_alt_name_only.crt b/tests/AndroidTests/res/raw/wild_alt_name_only.crt
index fafdebf..fafdebf 100644
--- a/common/tests/res/raw/wild_alt_name_only.crt
+++ b/tests/AndroidTests/res/raw/wild_alt_name_only.crt
diff --git a/tests/AndroidTests/src/com/android/unit_tests/AsecTests.java b/tests/AndroidTests/src/com/android/unit_tests/AsecTests.java
index 3bbb447..5aaf13b 100755
--- a/tests/AndroidTests/src/com/android/unit_tests/AsecTests.java
+++ b/tests/AndroidTests/src/com/android/unit_tests/AsecTests.java
@@ -55,6 +55,7 @@ public class AsecTests extends AndroidTestCase {
void failStr(String errMsg) {
Log.w(TAG, "errMsg="+errMsg);
}
+
void failStr(Exception e) {
Log.w(TAG, "e.getMessage="+e.getMessage());
Log.w(TAG, "e="+e);
@@ -67,6 +68,13 @@ public class AsecTests extends AndroidTestCase {
cleanupContainers();
}
+ @Override
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ if (localLOGV) Log.i(TAG, "Cleaning out old test containers");
+ cleanupContainers();
+ }
+
private void cleanupContainers() throws RemoteException {
IMountService ms = getMs();
String[] containers = ms.getSecureContainerList();
@@ -132,6 +140,14 @@ public class AsecTests extends AndroidTestCase {
return ms.destroySecureContainer(fullId, force);
}
+ private boolean isContainerMounted(String localId) throws RemoteException {
+ Assert.assertTrue(isMediaMounted());
+ String fullId = "com.android.unittests.AsecTests." + localId;
+
+ IMountService ms = getMs();
+ return ms.isSecureContainerMounted(fullId);
+ }
+
private IMountService getMs() {
IBinder service = ServiceManager.getService("mount");
if (service != null) {
@@ -300,7 +316,7 @@ public class AsecTests extends AndroidTestCase {
}
}
- public void testRenameMountedContainer() {
+ public void testRenameSrcMountedContainer() {
try {
Assert.assertEquals(StorageResultCode.OperationSucceeded,
createContainer("testRenameContainer.1", 4, "none"));
@@ -312,12 +328,15 @@ public class AsecTests extends AndroidTestCase {
}
}
- public void testRenameToExistingContainer() {
+ public void testRenameDstMountedContainer() {
try {
Assert.assertEquals(StorageResultCode.OperationSucceeded,
createContainer("testRenameContainer.1", 4, "none"));
Assert.assertEquals(StorageResultCode.OperationSucceeded,
+ unmountContainer("testRenameContainer.1", false));
+
+ Assert.assertEquals(StorageResultCode.OperationSucceeded,
createContainer("testRenameContainer.2", 4, "none"));
Assert.assertEquals(StorageResultCode.OperationFailedStorageMounted,
@@ -326,4 +345,25 @@ public class AsecTests extends AndroidTestCase {
failStr(e);
}
}
+
+ public void testIsContainerMountedAfterRename() {
+ try {
+ Assert.assertEquals(StorageResultCode.OperationSucceeded,
+ createContainer("testRenameContainer.1", 4, "none"));
+
+ Assert.assertEquals(StorageResultCode.OperationSucceeded,
+ unmountContainer("testRenameContainer.1", false));
+
+ Assert.assertEquals(StorageResultCode.OperationSucceeded,
+ renameContainer("testRenameContainer.1", "testRenameContainer.2"));
+
+ Assert.assertEquals(false, containerExists("testRenameContainer.1"));
+ Assert.assertEquals(true, containerExists("testRenameContainer.2"));
+ // Check if isContainerMounted returns valid value
+ Assert.assertEquals(true, isContainerMounted("testRenameContainer.2"));
+ } catch (Exception e) {
+ failStr(e);
+ }
+ }
+
}
diff --git a/common/tests/src/com/android/common/DNParserTest.java b/tests/AndroidTests/src/com/android/unit_tests/DNParserTest.java
index 34b140a..61d0b42 100644
--- a/common/tests/src/com/android/common/DNParserTest.java
+++ b/tests/AndroidTests/src/com/android/unit_tests/DNParserTest.java
@@ -13,7 +13,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.common;
+package com.android.unit_tests;
+
+import com.android.internal.net.DNParser;
import javax.security.auth.x500.X500Principal;
diff --git a/common/tests/src/com/android/common/DomainNameValidatorTest.java b/tests/AndroidTests/src/com/android/unit_tests/DomainNameValidatorTest.java
index b825be4..1754dbe 100644
--- a/common/tests/src/com/android/common/DomainNameValidatorTest.java
+++ b/tests/AndroidTests/src/com/android/unit_tests/DomainNameValidatorTest.java
@@ -13,9 +13,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.common;
+package com.android.unit_tests;
-import com.android.common.tests.R;
+import com.android.internal.net.DomainNameValidator;
import android.test.AndroidTestCase;
diff --git a/tests/AndroidTests/src/com/android/unit_tests/PackageManagerTests.java b/tests/AndroidTests/src/com/android/unit_tests/PackageManagerTests.java
index 9c5c44d..5e3895a 100755
--- a/tests/AndroidTests/src/com/android/unit_tests/PackageManagerTests.java
+++ b/tests/AndroidTests/src/com/android/unit_tests/PackageManagerTests.java
@@ -57,17 +57,25 @@ import android.os.Environment;
import android.os.Handler;
import android.os.IBinder;
import android.os.storage.IMountService;
+import android.os.storage.IMountServiceListener;
+import android.os.storage.StorageEventListener;
+import android.os.storage.StorageManager;
import android.os.storage.StorageResultCode;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.StatFs;
import android.provider.Settings;
+import android.provider.Settings.SettingNotFoundException;
public class PackageManagerTests extends AndroidTestCase {
private static final boolean localLOGV = true;
public static final String TAG="PackageManagerTests";
public final long MAX_WAIT_TIME=120*1000;
public final long WAIT_TIME_INCR=20*1000;
+ private static final String SECURE_CONTAINERS_PREFIX = "/mnt/asec";
+ private static final int APP_INSTALL_AUTO = 0;
+ private static final int APP_INSTALL_DEVICE = 1;
+ private static final int APP_INSTALL_SDCARD = 2;
void failStr(String errMsg) {
Log.w(TAG, "errMsg="+errMsg);
@@ -244,9 +252,46 @@ public class PackageManagerTests extends AndroidTestCase {
packageParser = null;
return pkg;
}
-
- private void assertInstall(String pkgName, int flags) {
+ private boolean getInstallLoc(int flags, int expInstallLocation) {
+ // Flags explicitly over ride everything else.
+ if ((flags & PackageManager.INSTALL_FORWARD_LOCK) != 0 ) {
+ return false;
+ } else if ((flags & PackageManager.INSTALL_EXTERNAL) != 0 ) {
+ return true;
+ }
+ // Manifest option takes precedence next
+ if (expInstallLocation == PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL) {
+ return true;
+ }
+ // TODO Out of memory checks here.
+ boolean checkSd = false;
+ int setLoc = 0;
+ try {
+ setLoc = Settings.System.getInt(mContext.getContentResolver(), Settings.System.SET_INSTALL_LOCATION);
+ } catch (SettingNotFoundException e) {
+ failStr(e);
+ }
+ if (setLoc == 1) {
+ int userPref = APP_INSTALL_AUTO;
+ try {
+ userPref = Settings.System.getInt(mContext.getContentResolver(), Settings.System.DEFAULT_INSTALL_LOCATION);
+ } catch (SettingNotFoundException e) {
+ failStr(e);
+ }
+ if (userPref == APP_INSTALL_DEVICE) {
+ checkSd = false;
+ } else if (userPref == APP_INSTALL_SDCARD) {
+ checkSd = true;
+ } else if (userPref == APP_INSTALL_AUTO) {
+ // Might be determined dynamically. TODO fix this
+ checkSd = false;
+ }
+ }
+ return checkSd;
+ }
+ private void assertInstall(PackageParser.Package pkg, int flags, int expInstallLocation) {
try {
+ String pkgName = pkg.packageName;
ApplicationInfo info = getPm().getApplicationInfo(pkgName, 0);
assertNotNull(info);
assertEquals(pkgName, info.packageName);
@@ -264,15 +309,14 @@ public class PackageManagerTests extends AndroidTestCase {
assertEquals(publicSrcPath, appInstallPath);
} else {
assertFalse((info.flags & ApplicationInfo.FLAG_FORWARD_LOCK) != 0);
- if ((flags & PackageManager.INSTALL_EXTERNAL) != 0) {
- assertTrue((info.flags & ApplicationInfo.FLAG_ON_SDCARD) != 0);
- // Hardcoded for now
- assertTrue(srcPath.startsWith("/asec"));
- assertTrue(publicSrcPath.startsWith("/asec"));
- } else {
+ if (!getInstallLoc(flags, expInstallLocation)) {
assertEquals(srcPath, appInstallPath);
assertEquals(publicSrcPath, appInstallPath);
assertFalse((info.flags & ApplicationInfo.FLAG_ON_SDCARD) != 0);
+ } else {
+ assertTrue((info.flags & ApplicationInfo.FLAG_ON_SDCARD) != 0);
+ assertTrue(srcPath.startsWith(SECURE_CONTAINERS_PREFIX));
+ assertTrue(publicSrcPath.startsWith(SECURE_CONTAINERS_PREFIX));
}
}
} catch (NameNotFoundException e) {
@@ -300,7 +344,7 @@ public class PackageManagerTests extends AndroidTestCase {
private InstallParams sampleInstallFromRawResource(int flags, boolean cleanUp) {
return installFromRawResource("install.apk", R.raw.install, flags, cleanUp,
- false, -1);
+ false, -1, PackageInfo.INSTALL_LOCATION_AUTO);
}
public void clearSecureContainersForPkg(String pkgName) {
@@ -327,7 +371,8 @@ public class PackageManagerTests extends AndroidTestCase {
* PackageManager api to install it.
*/
private InstallParams installFromRawResource(String outFileName,
- int rawResId, int flags, boolean cleanUp, boolean fail, int result) {
+ int rawResId, int flags, boolean cleanUp, boolean fail, int result,
+ int expInstallLocation) {
File filesDir = mContext.getFilesDir();
File outFile = new File(filesDir, outFileName);
Uri packageURI = getInstallablePackage(rawResId, outFile);
@@ -337,9 +382,7 @@ public class PackageManagerTests extends AndroidTestCase {
// Make sure the package doesn't exist
getPm().deletePackage(pkg.packageName, null, 0);
// Clean up the containers as well
- if ((flags & PackageManager.INSTALL_EXTERNAL) != 0) {
- clearSecureContainersForPkg(pkg.packageName);
- }
+ clearSecureContainersForPkg(pkg.packageName);
try {
try {
if (fail) {
@@ -351,7 +394,7 @@ public class PackageManagerTests extends AndroidTestCase {
assertTrue(invokeInstallPackage(packageURI, flags,
pkg.packageName, receiver));
// Verify installed information
- assertInstall(pkg.packageName, flags);
+ assertInstall(pkg, flags, expInstallLocation);
ip = new InstallParams(pkg, outFileName, packageURI);
}
} catch (Exception e) {
@@ -360,7 +403,7 @@ public class PackageManagerTests extends AndroidTestCase {
return ip;
} finally {
if (cleanUp) {
- cleanUpInstall(ip);
+ //cleanUpInstall(ip);
}
}
}
@@ -443,6 +486,7 @@ public class PackageManagerTests extends AndroidTestCase {
public void replaceFromRawResource(int flags) {
InstallParams ip = sampleInstallFromRawResource(flags, false);
boolean replace = ((flags & PackageManager.INSTALL_REPLACE_EXISTING) != 0);
+ Log.i(TAG, "replace=" + replace);
GenericReceiver receiver;
if (replace) {
receiver = new ReplaceReceiver(ip.pkg.packageName);
@@ -455,7 +499,7 @@ public class PackageManagerTests extends AndroidTestCase {
assertEquals(invokeInstallPackage(ip.packageURI, flags,
ip.pkg.packageName, receiver), replace);
if (replace) {
- assertInstall(ip.pkg.packageName, flags);
+ assertInstall(ip.pkg, flags, ip.pkg.installLocation);
}
} catch (Exception e) {
failStr("Failed with exception : " + e);
@@ -738,51 +782,73 @@ public class PackageManagerTests extends AndroidTestCase {
}
}
+ class StorageListener extends StorageEventListener {
+ String oldState;
+ String newState;
+ String path;
+ private boolean doneFlag = false;
+ @Override
+ public void onStorageStateChanged(String path, String oldState, String newState) {
+ if (localLOGV) Log.i(TAG, "Storage state changed from " + oldState + " to " + newState);
+ synchronized (this) {
+ this.oldState = oldState;
+ this.newState = newState;
+ this.path = path;
+ doneFlag = true;
+ notifyAll();
+ }
+ }
+
+ public boolean isDone() {
+ return doneFlag;
+ }
+ }
+
private boolean unmountMedia() {
if (!getMediaState()) {
return true;
}
+ String path = Environment.getExternalStorageDirectory().toString();
+ StorageListener observer = new StorageListener();
+ StorageManager sm = (StorageManager) mContext.getSystemService(Context.STORAGE_SERVICE);
+ sm.registerListener(observer);
try {
- String mPath = Environment.getExternalStorageDirectory().toString();
- int ret = getMs().unmountVolume(mPath, false);
- return ret == StorageResultCode.OperationSucceeded;
- } catch (RemoteException e) {
- return true;
+ // Wait on observer
+ synchronized(observer) {
+ getMs().unmountVolume(path, false);
+ long waitTime = 0;
+ while((!observer.isDone()) && (waitTime < MAX_WAIT_TIME) ) {
+ observer.wait(WAIT_TIME_INCR);
+ waitTime += WAIT_TIME_INCR;
+ }
+ if(!observer.isDone()) {
+ throw new Exception("Timed out waiting for packageInstalled callback");
+ }
+ return true;
+ }
+ } catch (Exception e) {
+ return false;
+ } finally {
+ sm.unregisterListener(observer);
}
}
- /*
- * Install package on sdcard. Unmount and then mount the media.
- * (Use PackageManagerService private api for now)
- * Make sure the installed package is available.
- * STOPSHIP will uncomment when MountService api's to mount/unmount
- * are made asynchronous.
- */
- public void xxxtestMountSdNormalInternal() {
- assertTrue(mountFromRawResource());
- }
-
private boolean mountFromRawResource() {
// Install pkg on sdcard
- InstallParams ip = sampleInstallFromRawResource(PackageManager.INSTALL_EXTERNAL |
- PackageManager.INSTALL_REPLACE_EXISTING, false);
+ InstallParams ip = sampleInstallFromRawResource(PackageManager.INSTALL_EXTERNAL, false);
if (localLOGV) Log.i(TAG, "Installed pkg on sdcard");
boolean origState = getMediaState();
+ boolean registeredReceiver = false;
SdMountReceiver receiver = new SdMountReceiver(new String[]{ip.pkg.packageName});
try {
if (localLOGV) Log.i(TAG, "Unmounting media");
// Unmount media
assertTrue(unmountMedia());
if (localLOGV) Log.i(TAG, "Unmounted media");
- try {
- if (localLOGV) Log.i(TAG, "Sleeping for 10 second");
- Thread.sleep(10*1000);
- } catch (InterruptedException e) {
- failStr(e);
- }
// Register receiver here
PackageManager pm = getPm();
mContext.registerReceiver(receiver, receiver.filter);
+ registeredReceiver = true;
// Wait on receiver
synchronized (receiver) {
@@ -807,7 +873,7 @@ public class PackageManagerTests extends AndroidTestCase {
failStr(e);
return false;
} finally {
- mContext.unregisterReceiver(receiver);
+ if (registeredReceiver) mContext.unregisterReceiver(receiver);
// Restore original media state
if (origState) {
mountMedia();
@@ -819,6 +885,17 @@ public class PackageManagerTests extends AndroidTestCase {
}
}
+ /*
+ * Install package on sdcard. Unmount and then mount the media.
+ * (Use PackageManagerService private api for now)
+ * Make sure the installed package is available.
+ * STOPSHIP will uncomment when MountService api's to mount/unmount
+ * are made asynchronous.
+ */
+ public void xxxtestMountSdNormalInternal() {
+ assertTrue(mountFromRawResource());
+ }
+
void cleanUpInstall(InstallParams ip) {
if (ip == null) {
return;
@@ -834,28 +911,29 @@ public class PackageManagerTests extends AndroidTestCase {
public void testManifestInstallLocationInternal() {
installFromRawResource("install.apk", R.raw.install_loc_internal,
- 0, true, false, -1);
+ 0, true, false, -1, PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY);
}
public void testManifestInstallLocationSdcard() {
installFromRawResource("install.apk", R.raw.install_loc_sdcard,
- 0, true, false, -1);
+ 0, true, false, -1, PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL);
}
public void testManifestInstallLocationAuto() {
installFromRawResource("install.apk", R.raw.install_loc_auto,
- 0, true, false, -1);
+ 0, true, false, -1, PackageInfo.INSTALL_LOCATION_AUTO);
}
public void testManifestInstallLocationUnspecified() {
installFromRawResource("install.apk", R.raw.install_loc_unspecified,
- 0, true, false, -1);
+ 0, true, false, -1, PackageInfo.INSTALL_LOCATION_AUTO);
}
public void testManifestInstallLocationFwdLockedSdcard() {
installFromRawResource("install.apk", R.raw.install_loc_sdcard,
PackageManager.INSTALL_FORWARD_LOCK, true, true,
- PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION);
+ PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION,
+ PackageInfo.INSTALL_LOCATION_AUTO);
}
public void xxxtestClearAllSecureContainers() {
diff --git a/common/tests/src/com/android/common/PatternsTest.java b/tests/AndroidTests/src/com/android/unit_tests/PatternsTest.java
index 9e2ad58..0edcd6d 100644
--- a/common/tests/src/com/android/common/PatternsTest.java
+++ b/tests/AndroidTests/src/com/android/unit_tests/PatternsTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007 The Android Open Source Project
+ * Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,14 +13,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
-package com.android.common;
+package com.android.unit_tests;
import android.test.suitebuilder.annotation.SmallTest;
-import junit.framework.TestCase;
+import android.util.Patterns;
import java.util.regex.Matcher;
-import java.util.regex.Pattern;
+
+import junit.framework.TestCase;
public class PatternsTest extends TestCase {
diff --git a/tests/CoreTests/android/core/MiscRegressionTest.java b/tests/CoreTests/android/core/MiscRegressionTest.java
index 8fe064c..8281db0 100644
--- a/tests/CoreTests/android/core/MiscRegressionTest.java
+++ b/tests/CoreTests/android/core/MiscRegressionTest.java
@@ -110,6 +110,16 @@ public class MiscRegressionTest extends TestCase {
Logger.global.finest("This has logging Level.FINEST, should become VERBOSE");
}
+ // Regression test for Issue 5697:
+ // getContextClassLoader returns a non-application classloader
+ // http://code.google.com/p/android/issues/detail?id=5697
+ //
+ @MediumTest
+ public void testJavaContextClassLoader() throws Exception {
+ Assert.assertNotNull("Must hava a Java context ClassLoader",
+ Thread.currentThread().getContextClassLoader());
+ }
+
// Regression test for #1045939: Different output for Method.toString()
@SmallTest
public void testMethodToString() {
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java b/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java
index ac98054..6ceb0f9 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java
@@ -81,6 +81,30 @@ public class FileFilter {
};
static void fillIgnoreResultList() {
+ // This first block of tests are for HTML5 features, for which Android
+ // should pass all tests. They are skipped only temporarily.
+ // TODO: Fix these failing tests and remove them from this list.
+ ignoreResultList.add("fast/dom/Geolocation/callback-exception.html"); // exception output incorrect with V8
+ ignoreResultList.add("http/tests/appcache/auth.html"); // file not found
+ ignoreResultList.add("http/tests/appcache/deferred-events.html"); // file not found
+ ignoreResultList.add("http/tests/appcache/deferred-events-delete-while-raising.html"); // file not found
+ ignoreResultList.add("http/tests/appcache/destroyed-frame.html"); // file not found
+ ignoreResultList.add("http/tests/appcache/detached-iframe.html"); // file not found
+ ignoreResultList.add("http/tests/appcache/different-scheme.html"); // file not found
+ ignoreResultList.add("http/tests/appcache/disabled.html"); // not found
+ ignoreResultList.add("http/tests/appcache/empty-manifest.html"); // flaky
+ ignoreResultList.add("http/tests/appcache/foreign-iframe-main.html"); // flaky - skips states
+ ignoreResultList.add("http/tests/appcache/local-content.html"); // text diff
+ ignoreResultList.add("http/tests/appcache/max-size.html"); // no layoutTestController.setAppCacheMaximumSize
+ ignoreResultList.add("http/tests/appcache/manifest-with-empty-file.html"); // flaky
+ ignoreResultList.add("http/tests/appcache/whitelist-wildcard.html"); // file not found
+ ignoreResultList.add("storage/database-lock-after-reload.html"); // failure
+ ignoreResultList.add("storage/domstorage/localstorage/string-conversion.html"); // false failure due to whitespace diff in output with V8
+ ignoreResultList.add("storage/domstorage/sessionstorage/string-conversion.html"); // false failure due to whitespace diff in output with V8
+ ignoreResultList.add("storage/statement-error-callback.html"); // expected line number diff in V8 only
+ ignoreResultList.add("storage/transaction-error-callback.html"); // expected line number diff in V8 only
+ ignoreResultList.add("storage/transaction-callback-exception-crash.html"); // expected line number diff in V8 only
+
ignoreResultList.add("fast/css/case-transform.html"); // will not fix #619707
ignoreResultList.add("fast/dom/Element/offsetLeft-offsetTop-body-quirk.html"); // different screen size result in extra spaces in Apple compared to us
ignoreResultList.add("fast/dom/Window/Plug-ins.html"); // need test plugin
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java b/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java
index 8983612..634d683 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java
@@ -339,14 +339,7 @@ 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) {
- Log.e(LOGTAG, "Cannot find test path prefix: " + e.getMessage());
- return;
- }
-
+ this.mTestPathPrefix = (new File(LAYOUT_TESTS_ROOT + runner.mTestPath)).getAbsolutePath();
this.mRebaselineResults = runner.mRebaseline;
int timeout = runner.mTimeoutInMillis;
@@ -395,11 +388,7 @@ public class LayoutTestsAutoTest extends ActivityInstrumentationTestCase2<TestSh
if (runner.mTestPath != null) {
test_path += runner.mTestPath;
}
- try {
- test_path = new File(test_path).getCanonicalPath();
- } catch (IOException e) {
- Log.e("LayoutTestsAutoTest", "Cannot get cannonical path " + e.getMessage());
- }
+ test_path = new File(test_path).getAbsolutePath();
Log.v("LayoutTestsAutoTest", " Test path : " + test_path);
return test_path;
diff --git a/tests/LocationTracker/Android.mk b/tests/LocationTracker/Android.mk
new file mode 100644
index 0000000..b142d22
--- /dev/null
+++ b/tests/LocationTracker/Android.mk
@@ -0,0 +1,10 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_PACKAGE_NAME := LocationTracker
+
+LOCAL_MODULE_TAGS := tests
+
+include $(BUILD_PACKAGE)
diff --git a/tests/LocationTracker/AndroidManifest.xml b/tests/LocationTracker/AndroidManifest.xml
new file mode 100644
index 0000000..dc7ea99
--- /dev/null
+++ b/tests/LocationTracker/AndroidManifest.xml
@@ -0,0 +1,30 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.locationtracker">
+
+ <!-- Permissions for the Location Service -->
+ <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
+ <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
+
+ <!-- Permission for wifi -->
+ <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
+
+ <!-- give the location tracker ability to induce device insomnia -->
+ <uses-permission android:name="android.permission.WAKE_LOCK" />
+
+ <!-- Permission for SD card -->
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+
+ <application android:label="@string/app_label">
+ <activity android:name="TrackerActivity" android:label="Location Tracker">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ <service android:name=".TrackerService" />
+ <activity android:label="@string/settings_menu" android:name="SettingsActivity" />
+ <provider android:name=".data.TrackerProvider"
+ android:authorities="com.android.locationtracker" />
+ </application>
+
+</manifest>
diff --git a/tests/LocationTracker/res/layout/entrylist_item.xml b/tests/LocationTracker/res/layout/entrylist_item.xml
new file mode 100644
index 0000000..d2a8033
--- /dev/null
+++ b/tests/LocationTracker/res/layout/entrylist_item.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (C) 2006-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.
+ */
+-->
+
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/entrylist_item"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+/>
diff --git a/tests/LocationTracker/res/menu/menu.xml b/tests/LocationTracker/res/menu/menu.xml
new file mode 100644
index 0000000..05d13fd
--- /dev/null
+++ b/tests/LocationTracker/res/menu/menu.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+* 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.
+*/
+-->
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:id="@+id/start_service_menu"
+ android:title="@string/start_service_menu" />
+ <item android:id="@+id/stop_service_menu"
+ android:title="@string/stop_service_menu" />
+ <item android:id="@+id/settings_menu"
+ android:title="@string/settings_menu" />
+ <item android:id="@+id/export_sub_menu"
+ android:title="@string/export_sub_menu">
+ <menu>
+ <item android:id="@+id/export_kml"
+ android:title="@string/export_kml" />
+ <item android:id="@+id/export_csv"
+ android:title="@string/export_csv" />
+ </menu>
+ </item>
+ <item android:title="@string/clear_data"
+ android:id="@+id/clear_data_menu"/>
+</menu>
diff --git a/tests/LocationTracker/res/values/strings.xml b/tests/LocationTracker/res/values/strings.xml
new file mode 100644
index 0000000..ea6bf2d
--- /dev/null
+++ b/tests/LocationTracker/res/values/strings.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+* 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.
+*/
+-->
+
+<resources>
+ <string name="start_service_menu">Start Service</string>
+ <string name="stop_service_menu">Stop Service</string>
+ <string name="settings_menu">Settings</string>
+ <string name="update_preference">Update frequency</string>
+ <string name="title_mintime_preference">Minimum update time</string>
+ <string name="summary_mintime_preference">The suggested minimum time interval for location updates, in seconds</string>
+ <string name="dialog_title_mintime_preference">Minimum update time</string>
+ <string name="title_mindistance_preference">Minimum distance</string>
+ <string name="summary_mindistance_preference">Minimum distance interval for location updates, in meters</string>
+ <string name="dialog_title_mindistance_preference">Minimum distance</string>
+ <string name="provider_preferences">Location providers</string>
+ <string name="title_network_preference">Network location</string>
+ <string name="summary_network_preference">Listen for updates to network location (Wi-Fi/cellid)</string>
+ <string name="title_gps_preference">GPS location</string>
+ <string name="summary_gps_preference">Listen for updates to GPS location</string>
+ <string name="title_signal_preference">Signal strength</string>
+ <string name="summary_signal_preference">Listen for updates to signal strength</string>
+ <string name="advanced_preferences">Advanced</string>
+ <string name="title_advanced_log_preference">Location debug logging</string>
+ <string name="summary_advanced_preference">Logs detailed location data, only relevant for location/test engineers</string>
+ <string name="app_label">Location Tracker</string>
+ <string name="export_sub_menu">Export\u2026</string>
+ <string name="export_kml">Export As KML</string>
+ <string name="export_csv">Export As CSV</string>
+ <string name="clear_data">Clear data</string>
+ <string name="delete_confirm">All current tracking data will be deleted.</string>
+ <string name="confirm_title">Clear data</string>
+</resources>
diff --git a/tests/LocationTracker/res/xml/preferences.xml b/tests/LocationTracker/res/xml/preferences.xml
new file mode 100755
index 0000000..61d4817
--- /dev/null
+++ b/tests/LocationTracker/res/xml/preferences.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<!-- The Location preferences UI -->
+<PreferenceScreen
+ xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <PreferenceCategory android:title="@string/update_preference">
+ <EditTextPreference android:key="mintime_preference"
+ android:defaultValue="0"
+ android:title="@string/title_mintime_preference"
+ android:summary="@string/summary_mintime_preference"
+ android:dialogTitle="@string/dialog_title_mintime_preference" />
+
+ <EditTextPreference android:key="mindistance_preference"
+ android:defaultValue="0"
+ android:title="@string/title_mindistance_preference"
+ android:summary="@string/summary_mindistance_preference"
+ android:dialogTitle="@string/dialog_title_mindistance_preference" />
+
+ </PreferenceCategory>
+
+ <PreferenceCategory android:title="@string/provider_preferences">
+
+ <CheckBoxPreference android:key="network_preference"
+ android:defaultValue="true"
+ android:title="@string/title_network_preference"
+ android:summary="@string/summary_network_preference" />
+
+ <CheckBoxPreference android:key="gps_preference"
+ android:defaultValue="true"
+ android:title="@string/title_gps_preference"
+ android:summary="@string/summary_gps_preference" />
+
+ <CheckBoxPreference android:key="signal_preference"
+ android:defaultValue="false"
+ android:title="@string/title_signal_preference"
+ android:summary="@string/summary_signal_preference" />
+
+ </PreferenceCategory>
+
+ <PreferenceCategory android:title="@string/advanced_preferences">
+
+ <CheckBoxPreference android:key="advanced_log_preference"
+ android:defaultValue="false"
+ android:title="@string/title_advanced_log_preference"
+ android:summary="@string/summary_advanced_preference" />
+ </PreferenceCategory>
+
+</PreferenceScreen>
diff --git a/tests/LocationTracker/src/com/android/locationtracker/SettingsActivity.java b/tests/LocationTracker/src/com/android/locationtracker/SettingsActivity.java
new file mode 100755
index 0000000..cb77118
--- /dev/null
+++ b/tests/LocationTracker/src/com/android/locationtracker/SettingsActivity.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 com.android.locationtracker;
+
+import android.os.Bundle;
+import android.preference.PreferenceActivity;
+
+/**
+ * Settings preference screen for location tracker
+ */
+public class SettingsActivity extends PreferenceActivity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // Load the preferences from an XML resource
+ addPreferencesFromResource(R.xml.preferences);
+ }
+
+}
diff --git a/tests/LocationTracker/src/com/android/locationtracker/TrackerActivity.java b/tests/LocationTracker/src/com/android/locationtracker/TrackerActivity.java
new file mode 100644
index 0000000..98d0a50
--- /dev/null
+++ b/tests/LocationTracker/src/com/android/locationtracker/TrackerActivity.java
@@ -0,0 +1,226 @@
+/*
+ * 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.locationtracker;
+
+import com.android.locationtracker.data.DateUtils;
+import com.android.locationtracker.data.TrackerDataHelper;
+import com.android.locationtracker.data.TrackerListHelper;
+
+import android.app.AlertDialog;
+import android.app.ListActivity;
+import android.content.DialogInterface;
+import android.content.DialogInterface.OnClickListener;
+import android.content.Intent;
+import android.database.Cursor;
+import android.location.LocationManager;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.widget.Toast;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.Writer;
+
+/**
+ * Activity for location tracker service
+ *
+ * Contains facilities for starting and
+ * stopping location tracker service, as well as displaying the current location
+ * data
+ *
+ * Future enhancements:
+ * - export data as dB
+ * - enable/disable "start service" and "stop service" menu items as
+ * appropriate
+ */
+public class TrackerActivity extends ListActivity {
+
+ static final String LOG_TAG = "LocationTracker";
+
+ private TrackerListHelper mDataHelper;
+
+ /**
+ * Retrieves and displays the currently logged location data from file
+ *
+ * @param icicle
+ */
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ mDataHelper = new TrackerListHelper(this);
+ mDataHelper.bindListUI(R.layout.entrylist_item);
+ }
+
+ /**
+ * Builds the menu
+ *
+ * @param menu - menu to add items to
+ */
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ MenuInflater menuInflater = getMenuInflater();
+ menuInflater.inflate(R.menu.menu, menu);
+ return true;
+ }
+
+ /**
+ * Handles menu item selection
+ *
+ * @param item - the selected menu item
+ */
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ switch (item.getItemId()) {
+ case R.id.start_service_menu: {
+ startService(new Intent(TrackerActivity.this,
+ TrackerService.class));
+ break;
+ }
+ case R.id.stop_service_menu: {
+ stopService(new Intent(TrackerActivity.this,
+ TrackerService.class));
+ break;
+ }
+ case R.id.settings_menu: {
+ launchSettings();
+ break;
+ }
+ case R.id.export_kml: {
+ exportKML();
+ break;
+ }
+ case R.id.export_csv: {
+ exportCSV();
+ break;
+ }
+ case R.id.clear_data_menu: {
+ clearData();
+ break;
+ }
+ }
+ return super.onOptionsItemSelected(item);
+ }
+
+ private void clearData() {
+ Runnable clearAction = new Runnable() {
+ public void run() {
+ TrackerDataHelper helper =
+ new TrackerDataHelper(TrackerActivity.this);
+ helper.deleteAll();
+ }
+ };
+ showConfirm(R.string.delete_confirm, clearAction);
+ }
+
+ private void showConfirm(int textId, final Runnable onConfirmAction) {
+ AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(this);
+ dialogBuilder.setTitle(R.string.confirm_title);
+ dialogBuilder.setMessage(textId);
+ dialogBuilder.setPositiveButton(android.R.string.ok,
+ new OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ onConfirmAction.run();
+ }
+ });
+ dialogBuilder.setNegativeButton(android.R.string.cancel,
+ new OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ // do nothing
+ }
+ });
+ dialogBuilder.show();
+ }
+
+ private void exportCSV() {
+ String exportFileName = getUniqueFileName("csv");
+ exportFile(null, exportFileName, new TrackerDataHelper(this,
+ TrackerDataHelper.CSV_FORMATTER));
+ }
+
+ private void exportKML() {
+ String exportFileName = getUniqueFileName(
+ LocationManager.NETWORK_PROVIDER + ".kml");
+ exportFile(LocationManager.NETWORK_PROVIDER, exportFileName,
+ new TrackerDataHelper(this, TrackerDataHelper.KML_FORMATTER));
+ exportFileName = getUniqueFileName(
+ LocationManager.GPS_PROVIDER + ".kml");
+ exportFile(LocationManager.GPS_PROVIDER, exportFileName,
+ new TrackerDataHelper(this, TrackerDataHelper.KML_FORMATTER));
+ }
+
+ private void exportFile(String tagFilter,
+ String exportFileName,
+ TrackerDataHelper trackerData) {
+ BufferedWriter exportWriter = null;
+ Cursor cursor = trackerData.query(tagFilter);
+ try {
+ exportWriter = new BufferedWriter(new FileWriter(exportFileName));
+ exportWriter.write(trackerData.getOutputHeader());
+
+ String line = null;
+
+ while ((line = trackerData.getNextOutput(cursor)) != null) {
+ exportWriter.write(line);
+ }
+ exportWriter.write(trackerData.getOutputFooter());
+ Toast.makeText(this, "Successfully exported data to " +
+ exportFileName, Toast.LENGTH_SHORT).show();
+
+ } catch (IOException e) {
+ Toast.makeText(this, "Error exporting file: " +
+ e.getLocalizedMessage(), Toast.LENGTH_SHORT).show();
+
+ Log.e(LOG_TAG, "Error exporting file", e);
+ } finally {
+ closeWriter(exportWriter);
+ if (cursor != null) {
+ cursor.close();
+ }
+ }
+ }
+
+ private void closeWriter(Writer exportWriter) {
+ if (exportWriter != null) {
+ try {
+ exportWriter.close();
+ } catch (IOException e) {
+ Log.e(LOG_TAG, "error closing file", e);
+ }
+ }
+ }
+
+ private String getUniqueFileName(String ext) {
+ File dir = new File("/sdcard/locationtracker");
+ if (!dir.exists()) {
+ dir.mkdir();
+ }
+ return "/sdcard/locationtracker/tracking-" +
+ DateUtils.getCurrentTimestamp() + "." + ext;
+ }
+
+ private void launchSettings() {
+ Intent settingsIntent = new Intent();
+ settingsIntent.setClass(this, SettingsActivity.class);
+ startActivity(settingsIntent);
+ }
+}
diff --git a/tests/LocationTracker/src/com/android/locationtracker/TrackerService.java b/tests/LocationTracker/src/com/android/locationtracker/TrackerService.java
new file mode 100644
index 0000000..5b75653
--- /dev/null
+++ b/tests/LocationTracker/src/com/android/locationtracker/TrackerService.java
@@ -0,0 +1,445 @@
+/*
+ * 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.locationtracker;
+
+import com.android.locationtracker.data.TrackerDataHelper;
+
+import android.app.Service;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.SharedPreferences;
+import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
+import android.location.Location;
+import android.location.LocationListener;
+import android.location.LocationManager;
+import android.net.ConnectivityManager;
+import android.net.wifi.ScanResult;
+import android.net.wifi.WifiManager;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.preference.PreferenceManager;
+import android.telephony.CellLocation;
+import android.telephony.PhoneStateListener;
+import android.telephony.SignalStrength;
+import android.telephony.TelephonyManager;
+import android.telephony.cdma.CdmaCellLocation;
+import android.telephony.gsm.GsmCellLocation;
+import android.util.Log;
+import android.widget.Toast;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Location Tracking service
+ *
+ * Records location updates for all registered location providers, and cell
+ * location updates
+ */
+public class TrackerService extends Service {
+
+ private List<LocationTrackingListener> mListeners;
+
+ private static final String LOG_TAG = TrackerActivity.LOG_TAG;
+
+ // controls which location providers to track
+ private Set<String> mTrackedProviders;
+
+ private TrackerDataHelper mTrackerData;
+
+ private TelephonyManager mTelephonyManager;
+ private Location mNetworkLocation;
+
+ // Handlers and Receivers for phone and network state
+ private NetworkStateBroadcastReceiver mNetwork;
+ private static final String CELL_PROVIDER_TAG = "cell";
+ // signal strength updates
+ private static final String SIGNAL_PROVIDER_TAG = "signal";
+ private static final String WIFI_PROVIDER_TAG = "wifi";
+ // tracking tag for data connectivity issues
+ private static final String DATA_CONN_PROVIDER_TAG = "data";
+
+ // preference constants
+ private static final String MIN_TIME_PREF = "mintime_preference";
+ private static final String MIN_DIS_PREF = "mindistance_preference";
+ private static final String GPS_PREF = "gps_preference";
+ private static final String NETWORK_PREF = "network_preference";
+ private static final String SIGNAL_PREF = "signal_preference";
+ private static final String DEBUG_PREF = "advanced_log_preference";
+
+ private PreferenceListener mPrefListener;
+
+ public TrackerService() {
+ }
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ // ignore - nothing to do
+ return null;
+ }
+
+ /**
+ * registers location listeners
+ *
+ * @param intent
+ * @param startId
+ */
+ @Override
+ public void onStart(Intent intent, int startId) {
+ super.onStart(intent, startId);
+ mNetworkLocation = null;
+
+ initLocationListeners();
+ Toast.makeText(this, "Tracking service started", Toast.LENGTH_SHORT);
+ }
+
+ private synchronized void initLocationListeners() {
+ mTrackerData = new TrackerDataHelper(this);
+ LocationManager lm = getLocationManager();
+
+ mTrackedProviders = getTrackedProviders();
+
+ List<String> locationProviders = lm.getAllProviders();
+ mListeners = new ArrayList<LocationTrackingListener>(
+ locationProviders.size());
+
+ long minUpdateTime = getLocationUpdateTime();
+ float minDistance = getLocationMinDistance();
+
+ for (String providerName : locationProviders) {
+ if (mTrackedProviders.contains(providerName)) {
+ Log.d(LOG_TAG, "Adding location listener for provider " +
+ providerName);
+ if (doDebugLogging()) {
+ mTrackerData.writeEntry("init", String.format(
+ "start listening to %s : %d ms; %f meters",
+ providerName, minUpdateTime, minDistance));
+ }
+ LocationTrackingListener listener =
+ new LocationTrackingListener();
+ lm.requestLocationUpdates(providerName, minUpdateTime,
+ minDistance, listener);
+ mListeners.add(listener);
+ }
+ }
+ mTelephonyManager = (TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE);
+
+ if (doDebugLogging()) {
+ // register for cell location updates
+ mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_CELL_LOCATION);
+
+ // Register for Network (Wifi or Mobile) updates
+ mNetwork = new NetworkStateBroadcastReceiver();
+ IntentFilter mIntentFilter;
+ mIntentFilter = new IntentFilter();
+ mIntentFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
+ mIntentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
+ mIntentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
+ Log.d(LOG_TAG, "registering receiver");
+ registerReceiver(mNetwork, mIntentFilter);
+ }
+
+ if (trackSignalStrength()) {
+ mTelephonyManager.listen(mPhoneStateListener,
+ PhoneStateListener.LISTEN_SIGNAL_STRENGTHS);
+ }
+
+ // register for preference changes, so we can restart listeners on
+ // pref changes
+ mPrefListener = new PreferenceListener();
+ getPreferences().registerOnSharedPreferenceChangeListener(mPrefListener);
+ }
+
+ private Set<String> getTrackedProviders() {
+ Set<String> providerSet = new HashSet<String>();
+
+ if (trackGPS()) {
+ providerSet.add(LocationManager.GPS_PROVIDER);
+ }
+ if (trackNetwork()) {
+ providerSet.add(LocationManager.NETWORK_PROVIDER);
+ }
+ return providerSet;
+ }
+
+ private SharedPreferences getPreferences() {
+ return PreferenceManager.getDefaultSharedPreferences(this);
+ }
+
+ private boolean trackNetwork() {
+ return getPreferences().getBoolean(NETWORK_PREF, true);
+ }
+
+ private boolean trackGPS() {
+ return getPreferences().getBoolean(GPS_PREF, true);
+ }
+
+ private boolean doDebugLogging() {
+ return getPreferences().getBoolean(DEBUG_PREF, true);
+ }
+
+ private boolean trackSignalStrength() {
+ return getPreferences().getBoolean(SIGNAL_PREF, true);
+ }
+
+ private float getLocationMinDistance() {
+ try {
+ String disString = getPreferences().getString(MIN_DIS_PREF, "0");
+ return Float.parseFloat(disString);
+ }
+ catch (NumberFormatException e) {
+ Log.e(LOG_TAG, "Invalid preference for location min distance", e);
+ }
+ return 0;
+ }
+
+ private long getLocationUpdateTime() {
+ try {
+ String timeString = getPreferences().getString(MIN_TIME_PREF, "0");
+ long secondsTime = Long.valueOf(timeString);
+ return secondsTime * 1000;
+ }
+ catch (NumberFormatException e) {
+ Log.e(LOG_TAG, "Invalid preference for location min time", e);
+ }
+ return 0;
+ }
+
+ /**
+ * Shuts down this service
+ */
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ Log.d(LOG_TAG, "Removing location listeners");
+ stopListeners();
+ Toast.makeText(this, "Tracking service stopped", Toast.LENGTH_SHORT);
+ }
+
+ /**
+ * De-registers all location listeners, closes persistent storage
+ */
+ protected synchronized void stopListeners() {
+ LocationManager lm = getLocationManager();
+ if (mListeners != null) {
+ for (LocationTrackingListener listener : mListeners) {
+ lm.removeUpdates(listener);
+ }
+ mListeners.clear();
+ }
+ mListeners = null;
+
+ // stop cell state listener
+ if (mTelephonyManager != null) {
+ mTelephonyManager.listen(mPhoneStateListener, 0);
+ }
+
+ // stop network/wifi listener
+ if (mNetwork != null) {
+ unregisterReceiver(mNetwork);
+ }
+ mNetwork = null;
+
+ mTrackerData = null;
+ if (mPrefListener != null) {
+ getPreferences().unregisterOnSharedPreferenceChangeListener(mPrefListener);
+ mPrefListener = null;
+ }
+ }
+
+ private LocationManager getLocationManager() {
+ return (LocationManager) getSystemService(Context.LOCATION_SERVICE);
+ }
+
+ /**
+ * Determine the current distance from given location to the last
+ * approximated network location
+ *
+ * @param location - new location
+ *
+ * @return float distance in meters
+ */
+ private synchronized float getDistanceFromNetwork(Location location) {
+ float value = 0;
+ if (mNetworkLocation != null) {
+ value = location.distanceTo(mNetworkLocation);
+ }
+ if (LocationManager.NETWORK_PROVIDER.equals(location.getProvider())) {
+ mNetworkLocation = location;
+ }
+ return value;
+ }
+
+ private class LocationTrackingListener implements LocationListener {
+
+ /**
+ * Writes details of location update to tracking file, including
+ * recording the distance between this location update and the last
+ * network location update
+ *
+ * @param location - new location
+ */
+ public void onLocationChanged(Location location) {
+ if (location == null) {
+ return;
+ }
+ float distance = getDistanceFromNetwork(location);
+ mTrackerData.writeEntry(location, distance);
+ }
+
+ /**
+ * Writes update to tracking file
+ *
+ * @param provider - name of disabled provider
+ */
+ public void onProviderDisabled(String provider) {
+ if (doDebugLogging()) {
+ mTrackerData.writeEntry(provider, "provider disabled");
+ }
+ }
+
+ /**
+ * Writes update to tracking file
+ *
+ * @param provider - name of enabled provider
+ */
+ public void onProviderEnabled(String provider) {
+ if (doDebugLogging()) {
+ mTrackerData.writeEntry(provider, "provider enabled");
+ }
+ }
+
+ /**
+ * Writes update to tracking file
+ *
+ * @param provider - name of provider whose status changed
+ * @param status - new status
+ * @param extras - optional set of extra status messages
+ */
+ public void onStatusChanged(String provider, int status, Bundle extras) {
+ if (doDebugLogging()) {
+ mTrackerData.writeEntry(provider, "status change: " + status);
+ }
+ }
+ }
+
+ PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
+ @Override
+ public void onCellLocationChanged(CellLocation location) {
+ try {
+ if (location instanceof GsmCellLocation) {
+ GsmCellLocation cellLocation = (GsmCellLocation)location;
+ String updateMsg = "cid=" + cellLocation.getCid() +
+ ", lac=" + cellLocation.getLac();
+ mTrackerData.writeEntry(CELL_PROVIDER_TAG, updateMsg);
+ } else if (location instanceof CdmaCellLocation) {
+ CdmaCellLocation cellLocation = (CdmaCellLocation)location;
+ String updateMsg = "BID=" + cellLocation.getBaseStationId() +
+ ", SID=" + cellLocation.getSystemId() +
+ ", NID=" + cellLocation.getNetworkId() +
+ ", lat=" + cellLocation.getBaseStationLatitude() +
+ ", long=" + cellLocation.getBaseStationLongitude() +
+ ", SID=" + cellLocation.getSystemId() +
+ ", NID=" + cellLocation.getNetworkId();
+ mTrackerData.writeEntry(CELL_PROVIDER_TAG, updateMsg);
+ }
+ } catch (Exception e) {
+ Log.e(LOG_TAG, "Exception in CellStateHandler.handleMessage:", e);
+ }
+ }
+
+ public void onSignalStrengthsChanged(SignalStrength signalStrength) {
+ if (mTelephonyManager.getPhoneType() == TelephonyManager.PHONE_TYPE_CDMA) {
+ String updateMsg = "cdma dBM=" + signalStrength.getCdmaDbm();
+ mTrackerData.writeEntry(SIGNAL_PROVIDER_TAG, updateMsg);
+ } else if (mTelephonyManager.getPhoneType() == TelephonyManager.PHONE_TYPE_GSM) {
+ String updateMsg = "gsm signal=" + signalStrength.getGsmSignalStrength();
+ mTrackerData.writeEntry(SIGNAL_PROVIDER_TAG, updateMsg);
+ }
+ }
+ };
+
+ /**
+ * Listener + recorder for mobile or wifi updates
+ */
+ private class NetworkStateBroadcastReceiver extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+
+ if (action.equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) {
+ WifiManager wifiManager =
+ (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
+ List<ScanResult> wifiScanResults = wifiManager.getScanResults();
+ String updateMsg = "num scan results=" +
+ (wifiScanResults == null ? "0" : wifiScanResults.size());
+ mTrackerData.writeEntry(WIFI_PROVIDER_TAG, updateMsg);
+
+ } else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
+ String updateMsg;
+ boolean noConnectivity =
+ intent.getBooleanExtra(
+ ConnectivityManager.EXTRA_NO_CONNECTIVITY, false);
+ if (noConnectivity) {
+ updateMsg = "no connectivity";
+ }
+ else {
+ updateMsg = "connection available";
+ }
+ mTrackerData.writeEntry(DATA_CONN_PROVIDER_TAG, updateMsg);
+
+ } else if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
+ int state = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
+ WifiManager.WIFI_STATE_UNKNOWN);
+
+ String stateString = "unknown";
+ switch (state) {
+ case WifiManager.WIFI_STATE_DISABLED:
+ stateString = "disabled";
+ break;
+ case WifiManager.WIFI_STATE_DISABLING:
+ stateString = "disabling";
+ break;
+ case WifiManager.WIFI_STATE_ENABLED:
+ stateString = "enabled";
+ break;
+ case WifiManager.WIFI_STATE_ENABLING:
+ stateString = "enabling";
+ break;
+ }
+ mTrackerData.writeEntry(WIFI_PROVIDER_TAG,
+ "state = " + stateString);
+ }
+ }
+ }
+
+ private class PreferenceListener implements OnSharedPreferenceChangeListener {
+
+ public void onSharedPreferenceChanged(
+ SharedPreferences sharedPreferences, String key) {
+ Log.d(LOG_TAG, "restarting listeners due to preference change");
+ synchronized (TrackerService.this) {
+ stopListeners();
+ initLocationListeners();
+ }
+ }
+ }
+}
diff --git a/tests/LocationTracker/src/com/android/locationtracker/data/CSVFormatter.java b/tests/LocationTracker/src/com/android/locationtracker/data/CSVFormatter.java
new file mode 100644
index 0000000..672ce28
--- /dev/null
+++ b/tests/LocationTracker/src/com/android/locationtracker/data/CSVFormatter.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.locationtracker.data;
+
+import com.android.locationtracker.data.TrackerEntry.EntryType;
+
+/**
+ * Formats tracker data as CSV output
+ */
+class CSVFormatter implements IFormatter {
+
+ private static final String DELIMITER = ", ";
+
+ public String getHeader() {
+ StringBuilder csvBuilder = new StringBuilder();
+ for (String col : TrackerEntry.ATTRIBUTES) {
+ // skip type and id column
+ if (!TrackerEntry.ENTRY_TYPE.equals(col) &&
+ !TrackerEntry.ID_COL.equals(col)) {
+ csvBuilder.append(col);
+ csvBuilder.append(DELIMITER);
+ }
+ }
+ csvBuilder.append("\n");
+ return csvBuilder.toString();
+ }
+
+ public String getOutput(TrackerEntry entry) {
+ StringBuilder rowOutput = new StringBuilder();
+ // these must match order of columns added in getHeader
+ rowOutput.append(entry.getTimestamp());
+ rowOutput.append(DELIMITER);
+ rowOutput.append(entry.getTag());
+ rowOutput.append(DELIMITER);
+ //rowOutput.append(entry.getType());
+ //rowOutput.append(DELIMITER);
+ if (entry.getType() == EntryType.LOCATION_TYPE) {
+ if (entry.getLocation().hasAccuracy()) {
+ rowOutput.append(entry.getLocation().getAccuracy());
+ }
+ rowOutput.append(DELIMITER);
+ rowOutput.append(entry.getLocation().getLatitude());
+ rowOutput.append(DELIMITER);
+ rowOutput.append(entry.getLocation().getLongitude());
+ rowOutput.append(DELIMITER);
+ if (entry.getLocation().hasAltitude()) {
+ rowOutput.append(entry.getLocation().getAltitude());
+ }
+ rowOutput.append(DELIMITER);
+ if (entry.getLocation().hasSpeed()) {
+ rowOutput.append(entry.getLocation().getSpeed());
+ }
+ rowOutput.append(DELIMITER);
+ if (entry.getLocation().hasBearing()) {
+ rowOutput.append(entry.getLocation().getBearing());
+ }
+ rowOutput.append(DELIMITER);
+ rowOutput.append(entry.getDistFromNetLocation());
+ rowOutput.append(DELIMITER);
+ rowOutput.append(DateUtils.getKMLTimestamp(entry.getLocation()
+ .getTime()));
+ rowOutput.append(DELIMITER);
+ }
+ rowOutput.append(entry.getLogMsg());
+ rowOutput.append("\n");
+ return rowOutput.toString();
+ }
+
+ public String getFooter() {
+ // not needed, return empty string
+ return "";
+ }
+}
diff --git a/tests/LocationTracker/src/com/android/locationtracker/data/DateUtils.java b/tests/LocationTracker/src/com/android/locationtracker/data/DateUtils.java
new file mode 100644
index 0000000..13226bd
--- /dev/null
+++ b/tests/LocationTracker/src/com/android/locationtracker/data/DateUtils.java
@@ -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 com.android.locationtracker.data;
+
+import java.util.Calendar;
+import java.util.TimeZone;
+
+/**
+ * Provides formatting date as string utilities
+ */
+public class DateUtils {
+
+ private DateUtils() {
+
+ }
+
+ /**
+ * Returns timestamp given by param in KML format ie yyyy-mm-ddThh:mm:ssZ,
+ * where T is the separator between the date and the time and the time zone
+ * is Z (for UTC)
+ *
+ * @return KML timestamp as String
+ */
+ public static String getKMLTimestamp(long when) {
+ TimeZone tz = TimeZone.getTimeZone("GMT");
+ Calendar c = Calendar.getInstance(tz);
+ c.setTimeInMillis(when);
+ return String.format("%tY-%tm-%tdT%tH:%tM:%tSZ", c, c, c, c, c, c);
+ }
+
+ /**
+ * Helper version of getKMLTimestamp, that returns timestamp for current
+ * time
+ */
+ public static String getCurrentKMLTimestamp() {
+ return getKMLTimestamp(System.currentTimeMillis());
+ }
+
+ /**
+ * Returns timestamp in following format: yyyy-mm-dd-hh-mm-ss
+ */
+ public static String getCurrentTimestamp() {
+ Calendar c = Calendar.getInstance();
+ c.setTimeInMillis(System.currentTimeMillis());
+ return String.format("%tY-%tm-%td-%tH-%tM-%tS", c, c, c, c, c, c);
+ }
+}
diff --git a/tests/LocationTracker/src/com/android/locationtracker/data/IFormatter.java b/tests/LocationTracker/src/com/android/locationtracker/data/IFormatter.java
new file mode 100644
index 0000000..af0b5ed
--- /dev/null
+++ b/tests/LocationTracker/src/com/android/locationtracker/data/IFormatter.java
@@ -0,0 +1,27 @@
+/*
+ * 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.locationtracker.data;
+
+/**
+ * interface for formatting tracker data output
+ */
+interface IFormatter {
+
+ String getHeader();
+ String getOutput(TrackerEntry entry);
+ String getFooter();
+}
diff --git a/tests/LocationTracker/src/com/android/locationtracker/data/KMLFormatter.java b/tests/LocationTracker/src/com/android/locationtracker/data/KMLFormatter.java
new file mode 100644
index 0000000..a5e1816
--- /dev/null
+++ b/tests/LocationTracker/src/com/android/locationtracker/data/KMLFormatter.java
@@ -0,0 +1,88 @@
+/*
+ * 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.locationtracker.data;
+
+import com.android.locationtracker.data.TrackerEntry.EntryType;
+
+import android.location.Location;
+
+/**
+ * Formats tracker data as KML output
+ */
+class KMLFormatter implements IFormatter {
+
+ public String getHeader() {
+ LineBuilder builder = new LineBuilder();
+ builder.addLine("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
+ builder.addLine("<kml xmlns=\"http://earth.google.com/kml/2.2\">");
+ builder.addLine("<Document>");
+ return builder.toString();
+ }
+
+ public String getFooter() {
+ LineBuilder builder = new LineBuilder();
+ builder.addLine("</Document>");
+ builder.addLine("</kml>");
+ return builder.toString();
+ }
+
+ public String getOutput(TrackerEntry entry) {
+ LineBuilder builder = new LineBuilder();
+
+ if (entry.getType() == EntryType.LOCATION_TYPE) {
+
+ Location loc = entry.getLocation();
+ builder.addLine("<Placemark>");
+ builder.addLine("<description>");
+ builder.addLine("accuracy = " + loc.getAccuracy());
+ builder.addLine("distance from last network location = "
+ + entry.getDistFromNetLocation());
+ builder.addLine("</description>");
+ builder.addLine("<TimeStamp>");
+ builder.addLine("<when>" + entry.getTimestamp() + "</when>");
+ builder.addLine("</TimeStamp>");
+ builder.addLine("<Point>");
+ builder.addLine("<coordinates>");
+ builder.addLine(loc.getLongitude() + "," + loc.getLatitude() + ","
+ + loc.getAltitude());
+ builder.addLine("</coordinates>");
+ builder.addLine("</Point>");
+ builder.addLine("</Placemark>");
+ }
+ return builder.toString();
+ }
+
+ private static class LineBuilder {
+ private StringBuilder mBuilder;
+
+ public LineBuilder() {
+ mBuilder = new StringBuilder();
+ }
+
+ public void addLine(String line) {
+ mBuilder.append(line);
+ mBuilder.append("\n");
+ }
+
+ @Override
+ public String toString() {
+ return mBuilder.toString();
+ }
+
+ }
+
+}
diff --git a/tests/LocationTracker/src/com/android/locationtracker/data/TrackerDataHelper.java b/tests/LocationTracker/src/com/android/locationtracker/data/TrackerDataHelper.java
new file mode 100644
index 0000000..a3838df
--- /dev/null
+++ b/tests/LocationTracker/src/com/android/locationtracker/data/TrackerDataHelper.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 com.android.locationtracker.data;
+
+import android.content.Context;
+import android.database.Cursor;
+import android.location.Location;
+
+/**
+ * Helper class for writing and retrieving data using the TrackerProvider
+ * content provider
+ *
+ */
+public class TrackerDataHelper {
+
+ private Context mContext;
+ /** formats data output */
+ protected IFormatter mFormatter;
+
+ /** formats output as Comma separated value CSV file */
+ public static final IFormatter CSV_FORMATTER = new CSVFormatter();
+ /** formats output as KML file */
+ public static final IFormatter KML_FORMATTER = new KMLFormatter();
+ /** provides no formatting */
+ public static final IFormatter NO_FORMATTER = new IFormatter() {
+ public String getFooter() {
+ return "";
+ }
+
+ public String getHeader() {
+ return "";
+ }
+
+ public String getOutput(TrackerEntry entry) {
+ return "";
+ }
+ };
+
+ /**
+ * Creates instance
+ *
+ * @param context - content context
+ * @param formatter - formats the output from the get*Output* methods
+ */
+ public TrackerDataHelper(Context context, IFormatter formatter) {
+ mContext = context;
+ mFormatter = formatter;
+ }
+
+ /**
+ * Creates a instance with no output formatting capabilities. Useful for
+ * clients that require write-only access
+ */
+ public TrackerDataHelper(Context context) {
+ this(context, NO_FORMATTER);
+ }
+
+ /**
+ * insert given TrackerEntry into content provider
+ */
+ void writeEntry(TrackerEntry entry) {
+ mContext.getContentResolver().insert(TrackerProvider.CONTENT_URI,
+ entry.getAsContentValues());
+ }
+
+ /**
+ * insert given location into tracker data
+ */
+ public void writeEntry(Location loc, float distFromNetLoc) {
+ writeEntry(TrackerEntry.createEntry(loc, distFromNetLoc));
+ }
+
+ /**
+ * insert given log message into tracker data
+ */
+ public void writeEntry(String tag, String logMsg) {
+ writeEntry(TrackerEntry.createEntry(tag, logMsg));
+ }
+
+ /**
+ * Deletes all tracker entries
+ */
+ public void deleteAll() {
+ mContext.getContentResolver().delete(TrackerProvider.CONTENT_URI, null,
+ null);
+ }
+
+ /**
+ * Query tracker data, filtering by given tag
+ *
+ * @param tag
+ * @return Cursor to data
+ */
+ public Cursor query(String tag, int limit) {
+ String selection = (tag == null ? null : TrackerEntry.TAG + "=?");
+ String[] selectionArgs = (tag == null ? null : new String[] {tag});
+ Cursor cursor = mContext.getContentResolver().query(
+ TrackerProvider.CONTENT_URI, TrackerEntry.ATTRIBUTES,
+ selection, selectionArgs, null);
+ if (cursor == null) {
+ return cursor;
+ }
+ int pos = (cursor.getCount() < limit ? 0 : cursor.getCount() - limit);
+ cursor.moveToPosition(pos);
+ return cursor;
+ }
+
+ /**
+ * Retrieves a cursor that starts at the last limit rows
+ *
+ * @param limit
+ * @return a cursor, null if bad things happened
+ */
+ public Cursor query(int limit) {
+ return query(null, limit);
+ }
+
+ /**
+ * Query tracker data, filtering by given tag. mo limit to number of rows
+ * returned
+ *
+ * @param tag
+ * @return Cursor to data
+ */
+ public Cursor query(String tag) {
+ return query(tag, Integer.MAX_VALUE);
+ }
+
+ /**
+ * Returns the output header particular to the associated formatter
+ */
+ public String getOutputHeader() {
+ return mFormatter.getHeader();
+ }
+
+ /**
+ * Returns the output footer particular to the associated formatter
+ */
+ public String getOutputFooter() {
+ return mFormatter.getFooter();
+ }
+
+ /**
+ * Helper method which converts row referenced by given cursor to a string
+ * output
+ *
+ * @param cursor
+ * @return CharSequence output, null if given cursor is invalid or no more
+ * data
+ */
+ public String getNextOutput(Cursor cursor) {
+ if (cursor == null || cursor.isAfterLast()) {
+ return null;
+ }
+ String output = mFormatter.getOutput(TrackerEntry.createEntry(cursor));
+ cursor.moveToNext();
+ return output;
+ }
+}
diff --git a/tests/LocationTracker/src/com/android/locationtracker/data/TrackerEntry.java b/tests/LocationTracker/src/com/android/locationtracker/data/TrackerEntry.java
new file mode 100644
index 0000000..b2741f6
--- /dev/null
+++ b/tests/LocationTracker/src/com/android/locationtracker/data/TrackerEntry.java
@@ -0,0 +1,253 @@
+/*
+ * 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.locationtracker.data;
+
+import android.content.ContentValues;
+import android.database.Cursor;
+import android.location.Location;
+
+
+/**
+ * Class that holds a tracker entry. An entry can be either a valid location, or
+ * a simple log msg
+ *
+ * It provides a concrete data structure to represent data stored in the
+ * TrackerProvider
+ */
+class TrackerEntry {
+
+ static final String TIMESTAMP = "Timestamp";
+ static final String TAG = "Tag";
+ static final String ENTRY_TYPE = "Type";
+
+ private Location mLocation;
+ private float mDistFromNetLocation;
+ private String mLogMsg;
+
+ static final String ID_COL = "_id";
+ static final String ACCURACY = "Accuracy";
+ static final String LATITUDE = "Latitude";
+ static final String LONGITUDE = "Longitude";
+ static final String ALTITUDE = "Altitude";
+ static final String SPEED = "Speed";
+ static final String BEARING = "Bearing";
+ static final String DIST_NET_LOCATION = "DistFromNetLocation";
+ static final String LOC_TIME = "LocationTime";
+ static final String DEBUG_INFO = "DebugInfo";
+
+ static final String STRING_DATA = "STRING";
+ static final String INT_DATA = "INTEGER";
+ static final String REAL_DATA = "REAL";
+ static final String BLOB_DATA = "BLOB";
+
+ static final String[] ATTRIBUTES = {
+ ID_COL, TIMESTAMP, TAG, ENTRY_TYPE, ACCURACY, LATITUDE, LONGITUDE,
+ ALTITUDE, SPEED, BEARING, DIST_NET_LOCATION, LOC_TIME, DEBUG_INFO};
+ static final String[] ATTRIBUTES_DATA_TYPE = {
+ INT_DATA + " PRIMARY KEY", STRING_DATA, STRING_DATA, STRING_DATA,
+ REAL_DATA, REAL_DATA, REAL_DATA, REAL_DATA, REAL_DATA, REAL_DATA,
+ REAL_DATA, INT_DATA, STRING_DATA};
+
+ // location extra keys used to retrieve debug info
+ private static final String NETWORK_LOCATION_SOURCE_KEY =
+ "networkLocationSource";
+ private static final String NETWORK_LOCATION_TYPE_KEY =
+ "networkLocationType";
+ private static final String[] LOCATION_DEBUG_KEYS = {
+ NETWORK_LOCATION_SOURCE_KEY, NETWORK_LOCATION_TYPE_KEY};
+
+ enum EntryType {
+ LOCATION_TYPE, LOG_TYPE
+ }
+
+ private String mTimestamp;
+ private String mTag;
+ private EntryType mType;
+
+ private TrackerEntry(String tag, EntryType type) {
+ mType = type;
+ mTag = tag;
+ mLocation = null;
+ }
+
+ private TrackerEntry(Location loc) {
+ this(loc.getProvider(), EntryType.LOCATION_TYPE);
+ mLocation = new Location(loc);
+ }
+
+ /**
+ * Creates a TrackerEntry from a Location
+ */
+ static TrackerEntry createEntry(Location loc, float distFromNetLocation) {
+ TrackerEntry entry = new TrackerEntry(loc);
+
+ String timestampVal = DateUtils.getCurrentKMLTimestamp();
+ entry.setTimestamp(timestampVal);
+ entry.setDistFromNetLocation(distFromNetLocation);
+ return entry;
+ }
+
+ /**
+ * Creates a TrackerEntry from a log msg
+ */
+ static TrackerEntry createEntry(String tag, String msg) {
+ TrackerEntry entry = new TrackerEntry(tag, EntryType.LOG_TYPE);
+ String timestampVal = DateUtils.getCurrentKMLTimestamp();
+ entry.setTimestamp(timestampVal);
+ entry.setLogMsg(msg);
+ return entry;
+ }
+
+ private void setTimestamp(String timestamp) {
+ mTimestamp = timestamp;
+ }
+
+ EntryType getType() {
+ return mType;
+ }
+
+ private void setDistFromNetLocation(float distFromNetLocation) {
+ mDistFromNetLocation = distFromNetLocation;
+ }
+
+ private void setLogMsg(String msg) {
+ mLogMsg = msg;
+ }
+
+ private void setLocation(Location location) {
+ mLocation = location;
+ }
+
+ String getTimestamp() {
+ return mTimestamp;
+ }
+
+ String getTag() {
+ return mTag;
+ }
+
+ Location getLocation() {
+ return mLocation;
+ }
+
+ String getLogMsg() {
+ return mLogMsg;
+ }
+
+ float getDistFromNetLocation() {
+ return mDistFromNetLocation;
+ }
+
+ static void buildCreationString(StringBuilder builder) {
+ if (ATTRIBUTES.length != ATTRIBUTES_DATA_TYPE.length) {
+ throw new IllegalArgumentException(
+ "Attribute length does not match data type length");
+ }
+ for (int i = 0; i < ATTRIBUTES_DATA_TYPE.length; i++) {
+ if (i != 0) {
+ builder.append(", ");
+ }
+ builder.append(String.format("%s %s", ATTRIBUTES[i],
+ ATTRIBUTES_DATA_TYPE[i]));
+ }
+ }
+
+ ContentValues getAsContentValues() {
+ ContentValues cValues = new ContentValues(ATTRIBUTES.length);
+ cValues.put(TIMESTAMP, mTimestamp);
+ cValues.put(TAG, mTag);
+ cValues.put(ENTRY_TYPE, mType.toString());
+ if (mType == EntryType.LOCATION_TYPE) {
+ cValues.put(LATITUDE, mLocation.getLatitude());
+ cValues.put(LONGITUDE, mLocation.getLongitude());
+ if (mLocation.hasAccuracy()) {
+ cValues.put(ACCURACY, mLocation.getAccuracy());
+ }
+ if (mLocation.hasAltitude()) {
+ cValues.put(ALTITUDE, mLocation.getAltitude());
+ }
+ if (mLocation.hasSpeed()) {
+ cValues.put(SPEED, mLocation.getSpeed());
+ }
+ if (mLocation.hasBearing()) {
+ cValues.put(BEARING, mLocation.getBearing());
+ }
+ cValues.put(DIST_NET_LOCATION, mDistFromNetLocation);
+ cValues.put(LOC_TIME, mLocation.getTime());
+ StringBuilder debugBuilder = new StringBuilder("");
+ if (mLocation.getExtras() != null) {
+ for (String key : LOCATION_DEBUG_KEYS) {
+ Object val = mLocation.getExtras().get(key);
+ if (val != null) {
+ debugBuilder.append(String.format("%s=%s; ", key, val
+ .toString()));
+ }
+ }
+ }
+ cValues.put(DEBUG_INFO, debugBuilder.toString());
+ } else {
+ cValues.put(DEBUG_INFO, mLogMsg);
+ }
+ return cValues;
+ }
+
+ static TrackerEntry createEntry(Cursor cursor) {
+ String timestamp = cursor.getString(cursor.getColumnIndex(TIMESTAMP));
+ String tag = cursor.getString(cursor.getColumnIndex(TAG));
+ String sType = cursor.getString(cursor.getColumnIndex(ENTRY_TYPE));
+ TrackerEntry entry = new TrackerEntry(tag, EntryType.valueOf(sType));
+ entry.setTimestamp(timestamp);
+ if (entry.getType() == EntryType.LOCATION_TYPE) {
+ Location location = new Location(tag);
+ location.setLatitude(cursor.getFloat(cursor
+ .getColumnIndexOrThrow(LATITUDE)));
+ location.setLongitude(cursor.getFloat(cursor
+ .getColumnIndexOrThrow(LONGITUDE)));
+
+ Float accuracy = getNullableFloat(cursor, ACCURACY);
+ if (accuracy != null) {
+ location.setAccuracy(accuracy);
+ }
+ Float altitude = getNullableFloat(cursor, ALTITUDE);
+ if (altitude != null) {
+ location.setAltitude(altitude);
+ }
+ Float bearing = getNullableFloat(cursor, BEARING);
+ if (bearing != null) {
+ location.setBearing(bearing);
+ }
+ Float speed = getNullableFloat(cursor, SPEED);
+ if (speed != null) {
+ location.setSpeed(speed);
+ }
+ location.setTime(cursor.getLong(cursor.getColumnIndex(LOC_TIME)));
+ entry.setLocation(location);
+ }
+ entry.setLogMsg(cursor.getString(cursor.getColumnIndex(DEBUG_INFO)));
+
+ return entry;
+ }
+
+ private static Float getNullableFloat(Cursor cursor, String colName) {
+ Float retValue = null;
+ int colIndex = cursor.getColumnIndexOrThrow(colName);
+ if (!cursor.isNull(colIndex)) {
+ retValue = cursor.getFloat(colIndex);
+ }
+ return retValue;
+ }
+}
diff --git a/tests/LocationTracker/src/com/android/locationtracker/data/TrackerListHelper.java b/tests/LocationTracker/src/com/android/locationtracker/data/TrackerListHelper.java
new file mode 100644
index 0000000..55d4d1e
--- /dev/null
+++ b/tests/LocationTracker/src/com/android/locationtracker/data/TrackerListHelper.java
@@ -0,0 +1,75 @@
+/*
+ * 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.locationtracker.data;
+
+import android.app.ListActivity;
+import android.content.Context;
+import android.database.Cursor;
+import android.view.View;
+import android.widget.ResourceCursorAdapter;
+import android.widget.TextView;
+
+import com.android.locationtracker.R;
+
+/**
+ * Used to bind Tracker data to a list view UI
+ */
+public class TrackerListHelper extends TrackerDataHelper {
+
+ private ListActivity mActivity;
+
+ // sort entries by most recent first
+ private static final String SORT_ORDER = TrackerEntry.ID_COL + " DESC";
+
+ public TrackerListHelper(ListActivity activity) {
+ super(activity, TrackerDataHelper.CSV_FORMATTER);
+ mActivity = activity;
+ }
+
+ /**
+ * Helper method for binding the list activities UI to the tracker data
+ * Tracker data will be sorted in most-recent first order
+ * Will enable automatic UI changes as tracker data changes
+ *
+ * @param layout - layout to populate data
+ */
+ public void bindListUI(int layout) {
+ Cursor cursor = mActivity.managedQuery(TrackerProvider.CONTENT_URI,
+ TrackerEntry.ATTRIBUTES, null, null, SORT_ORDER);
+ // Used to map tracker entries from the database to views
+ TrackerAdapter adapter = new TrackerAdapter(mActivity, layout, cursor);
+ mActivity.setListAdapter(adapter);
+ cursor.setNotificationUri(mActivity.getContentResolver(),
+ TrackerProvider.CONTENT_URI);
+
+ }
+
+ private class TrackerAdapter extends ResourceCursorAdapter {
+
+ public TrackerAdapter(Context context, int layout, Cursor c) {
+ super(context, layout, c);
+ }
+
+ @Override
+ public void bindView(View view, Context context, Cursor cursor) {
+ final TextView v = (TextView) view
+ .findViewById(R.id.entrylist_item);
+ String rowText = mFormatter.getOutput(TrackerEntry
+ .createEntry(cursor));
+ v.setText(rowText);
+ }
+ }
+}
diff --git a/tests/LocationTracker/src/com/android/locationtracker/data/TrackerProvider.java b/tests/LocationTracker/src/com/android/locationtracker/data/TrackerProvider.java
new file mode 100644
index 0000000..88f24c3
--- /dev/null
+++ b/tests/LocationTracker/src/com/android/locationtracker/data/TrackerProvider.java
@@ -0,0 +1,126 @@
+/*
+ * 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.locationtracker.data;
+
+import android.content.ContentProvider;
+import android.content.ContentUris;
+import android.content.ContentValues;
+import android.content.Context;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteOpenHelper;
+import android.net.Uri;
+import android.util.Log;
+
+/**
+ * Content provider for location tracking.
+ *
+ * It is recommended to use the TrackerDataHelper class to access this data
+ * rather than this class directly
+ */
+public class TrackerProvider extends ContentProvider {
+
+ public static final Uri CONTENT_URI = Uri
+ .parse("content://com.android.locationtracker");
+
+ private static final String DB_NAME = "tracking.db";
+ private static final String TABLE_NAME = "tracking";
+ private static final int DB_VERSION = 1;
+
+ private static final String LOG_TAG = "TrackerProvider";
+
+ /**
+ * This class helps open, create, and upgrade the database file.
+ */
+ private static class DatabaseHelper extends SQLiteOpenHelper {
+
+ DatabaseHelper(Context context) {
+ super(context, DB_NAME, null, DB_VERSION);
+ }
+
+ @Override
+ public void onCreate(SQLiteDatabase db) {
+ StringBuilder queryBuilder = new StringBuilder();
+ queryBuilder.append(String.format("CREATE TABLE %s (", TABLE_NAME));
+ TrackerEntry.buildCreationString(queryBuilder);
+
+ queryBuilder.append(");");
+ db.execSQL(queryBuilder.toString());
+ db.setVersion(DB_VERSION);
+ }
+
+ @Override
+ public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+ // TODO: reimplement this when dB version changes
+ Log.w(LOG_TAG, "Upgrading database from version " + oldVersion
+ + " to " + newVersion
+ + ", which will destroy all old data");
+ db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME);
+ onCreate(db);
+ }
+ }
+
+ private DatabaseHelper mOpenHelper;
+
+ @Override
+ public boolean onCreate() {
+ mOpenHelper = new DatabaseHelper(getContext());
+ return true;
+ }
+
+ @Override
+ public int delete(Uri uri, String selection, String[] selectionArgs) {
+ SQLiteDatabase db = mOpenHelper.getWritableDatabase();
+ int result = db.delete(TABLE_NAME, selection, selectionArgs);
+ getContext().getContentResolver().notifyChange(uri, null);
+ return result;
+ }
+
+ @Override
+ public String getType(Uri uri) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Uri insert(Uri uri, ContentValues values) {
+ SQLiteDatabase db = mOpenHelper.getWritableDatabase();
+ long rowId = db.insert(TABLE_NAME, null, values);
+ if (rowId > 0) {
+ Uri addedUri = ContentUris.withAppendedId(CONTENT_URI, rowId);
+ getContext().getContentResolver().notifyChange(addedUri, null);
+ return addedUri;
+ }
+ return null;
+ }
+
+ @Override
+ public Cursor query(Uri uri, String[] projection, String selection,
+ String[] selectionArgs, String sortOrder) {
+ SQLiteDatabase db = mOpenHelper.getReadableDatabase();
+ // TODO: extract limit from URI ?
+ Cursor cursor = db.query(TABLE_NAME, projection, selection,
+ selectionArgs, null, null, sortOrder);
+ getContext().getContentResolver().notifyChange(uri, null);
+ return cursor;
+ }
+
+ @Override
+ public int update(Uri uri, ContentValues values, String selection,
+ String[] selectionArgs) {
+ throw new UnsupportedOperationException();
+ }
+}
diff --git a/tests/SslLoad/src/com/android/sslload/SslLoad.java b/tests/SslLoad/src/com/android/sslload/SslLoad.java
index 1470d48..62aa524 100644
--- a/tests/SslLoad/src/com/android/sslload/SslLoad.java
+++ b/tests/SslLoad/src/com/android/sslload/SslLoad.java
@@ -35,7 +35,7 @@ import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
import android.util.Log;
-import com.android.common.AndroidHttpClient;
+import android.net.http.AndroidHttpClient;
import org.apache.http.client.HttpClient;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.methods.HttpGet;
diff --git a/tools/aapt/Resource.cpp b/tools/aapt/Resource.cpp
index 88c5441..ae4bd14 100644
--- a/tools/aapt/Resource.cpp
+++ b/tools/aapt/Resource.cpp
@@ -221,12 +221,12 @@ static status_t parsePackage(Bundle* bundle, const sp<AaptAssets>& assets,
&& code != ResXMLTree::BAD_DOCUMENT) {
if (code == ResXMLTree::START_TAG) {
if (strcmp16(block.getElementName(&len), uses_sdk16.string()) == 0) {
- ssize_t minSdkIndex = block.indexOfAttribute("android",
+ ssize_t minSdkIndex = block.indexOfAttribute(RESOURCES_ANDROID_NAMESPACE,
"minSdkVersion");
if (minSdkIndex >= 0) {
- String8 minSdkString = String8(
- block.getAttributeStringValue(minSdkIndex, &len));
- bundle->setMinSdkVersion(minSdkString.string());
+ const uint16_t* minSdk16 = block.getAttributeStringValue(minSdkIndex, &len);
+ const char* minSdk8 = strdup(String8(minSdk16).string());
+ bundle->setMinSdkVersion(minSdk8);
}
}
}
diff --git a/tools/aapt/StringPool.cpp b/tools/aapt/StringPool.cpp
index 51afc0a..a09cec0 100644
--- a/tools/aapt/StringPool.cpp
+++ b/tools/aapt/StringPool.cpp
@@ -25,8 +25,12 @@ void printStringPool(const ResStringPool* pool)
const size_t NS = pool->size();
for (size_t s=0; s<NS; s++) {
size_t len;
- printf("String #%ld: %s\n", s,
- String8(pool->stringAt(s, &len)).string());
+ const char *str = (const char*)pool->string8At(s, &len);
+ if (str == NULL) {
+ str = String8(pool->stringAt(s, &len)).string();
+ }
+
+ printf("String #%ld: %s\n", s, str);
}
}
diff --git a/tools/layoutlib/bridge/src/android/graphics/Canvas.java b/tools/layoutlib/bridge/src/android/graphics/Canvas.java
index 8bf5e85..d5d315e 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Canvas.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Canvas.java
@@ -236,11 +236,6 @@ public class Canvas extends _Original_Canvas {
// OVERRIDEN METHODS
// --------------------
- @Override
- public void finalize() throws Throwable {
- // pass
- }
-
/* (non-Javadoc)
* @see android.graphics.Canvas#setBitmap(android.graphics.Bitmap)
*/
diff --git a/tools/layoutlib/bridge/src/android/graphics/Matrix.java b/tools/layoutlib/bridge/src/android/graphics/Matrix.java
index 522415c..9e30671 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Matrix.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Matrix.java
@@ -52,11 +52,6 @@ public class Matrix extends _Original_Matrix {
mValues = data;
}
- @Override
- public void finalize() throws Throwable {
- // pass
- }
-
//---------- Custom Methods
/**
diff --git a/tools/layoutlib/bridge/src/android/graphics/Paint.java b/tools/layoutlib/bridge/src/android/graphics/Paint.java
index 2d03618..e4f9794 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Paint.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Paint.java
@@ -219,11 +219,6 @@ public class Paint extends _Original_Paint {
}
@Override
- public void finalize() throws Throwable {
- // pass
- }
-
- @Override
public void reset() {
super.reset();
}
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 41d9f9d..8e9e75f 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
@@ -16,7 +16,7 @@
package com.android.layoutlib.bridge;
-import com.android.common.XmlUtils;
+import com.android.internal.util.XmlUtils;
import com.android.layoutlib.api.ILayoutBridge;
import com.android.layoutlib.api.ILayoutLog;
import com.android.layoutlib.api.ILayoutResult;
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeContext.java
index 73a3986..744bfbe 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeContext.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeContext.java
@@ -927,6 +927,7 @@ public final class BridgeContext extends Context {
return null;
}
+ @Override
public File getExternalCacheDir() {
// TODO Auto-generated method stub
return null;
@@ -964,6 +965,7 @@ public final class BridgeContext extends Context {
return null;
}
+ @Override
public File getExternalFilesDir(String type) {
// TODO Auto-generated method stub
return null;
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeTypedArray.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeTypedArray.java
index efd222e..70c5bd7 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeTypedArray.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeTypedArray.java
@@ -16,7 +16,7 @@
package com.android.layoutlib.bridge;
-import com.android.common.XmlUtils;
+import com.android.internal.util.XmlUtils;
import com.android.layoutlib.api.IResourceValue;
import com.android.layoutlib.api.IStyleResourceValue;
@@ -392,7 +392,8 @@ public final class BridgeTypedArray extends TypedArray {
if (s == null) {
return defValue;
- } else if (s.equals(BridgeConstants.MATCH_PARENT)) {
+ } else if (s.equals(BridgeConstants.MATCH_PARENT) ||
+ s.equals(BridgeConstants.FILL_PARENT)) {
return LayoutParams.MATCH_PARENT;
} else if (s.equals(BridgeConstants.WRAP_CONTENT)) {
return LayoutParams.WRAP_CONTENT;
@@ -460,7 +461,8 @@ public final class BridgeTypedArray extends TypedArray {
if (s == null) {
return defValue;
- } else if (s.equals(BridgeConstants.MATCH_PARENT)) {
+ } else if (s.equals(BridgeConstants.MATCH_PARENT) ||
+ s.equals(BridgeConstants.FILL_PARENT)) {
return LayoutParams.MATCH_PARENT;
} else if (s.equals(BridgeConstants.WRAP_CONTENT)) {
return LayoutParams.WRAP_CONTENT;
diff --git a/tools/preload/20100223.compiled b/tools/preload/20100223.compiled
new file mode 100644
index 0000000..3056388
--- /dev/null
+++ b/tools/preload/20100223.compiled
Binary files differ
diff --git a/tools/preload/MemoryUsage.java b/tools/preload/MemoryUsage.java
index bc21b6f..d8f95f4 100644
--- a/tools/preload/MemoryUsage.java
+++ b/tools/preload/MemoryUsage.java
@@ -166,7 +166,7 @@ class MemoryUsage implements Serializable {
+ ":/system/framework/loadclass.jar";
private static final String[] GET_DIRTY_PAGES = {
- "adb", "-e", "shell", "dalvikvm", CLASS_PATH, "LoadClass" };
+ "adb", "shell", "dalvikvm", CLASS_PATH, "LoadClass" };
/**
* Measures memory usage for the given class.
@@ -248,7 +248,7 @@ class MemoryUsage implements Serializable {
String line = in.readLine();
if (line == null || !line.startsWith("DECAFBAD,")) {
System.err.println("Got bad response for " + className
- + ": " + line);
+ + ": " + line + "; command was " + Arrays.toString(commands));
errorCount += 1;
return NOT_AVAILABLE;
}
diff --git a/tools/preload/Policy.java b/tools/preload/Policy.java
index a8d761d..f557365 100644
--- a/tools/preload/Policy.java
+++ b/tools/preload/Policy.java
@@ -43,9 +43,14 @@ public class Policy {
"system_server",
"com.google.process.content",
"android.process.media",
+ "com.android.bluetooth",
+ "com.android.calendar",
+ "com.android.inputmethod.latin",
"com.android.phone",
- "com.google.android.apps.maps.FriendService",
+ "com.google.android.apps.maps.FriendService", // pre froyo
+ "com.google.android.apps.maps:FriendService", // froyo
"com.google.android.apps.maps.LocationFriendService",
+ "com.google.android.deskclock",
"com.google.process.gapps",
"android.tts"
));
diff --git a/tools/preload/Record.java b/tools/preload/Record.java
index b2be4d4..9d45a26 100644
--- a/tools/preload/Record.java
+++ b/tools/preload/Record.java
@@ -19,6 +19,19 @@
*/
class Record {
+ /**
+ * The delimiter character we use, {@code :}, conflicts with some other
+ * names. In that case, manually replace the delimiter with something else.
+ */
+ private static final String[] REPLACE_CLASSES = {
+ "com.google.android.apps.maps:FriendService",
+ "com.google.android.apps.maps\\u003AFriendService",
+ "com.google.android.apps.maps:driveabout",
+ "com.google.android.apps.maps\\u003Adriveabout",
+ "com.google.android.apps.maps:LocationFriendService",
+ "com.google.android.apps.maps\\u003ALocationFriendService",
+ };
+
enum Type {
/** Start of initialization. */
START_LOAD,
@@ -74,6 +87,10 @@ class Record {
}
sourceLineNumber = lineNum;
+
+ for (int i = 0; i < REPLACE_CLASSES.length; i+= 2) {
+ line = line.replace(REPLACE_CLASSES[i], REPLACE_CLASSES[i+1]);
+ }
line = line.substring(1);
String[] parts = line.split(":");
diff --git a/wifi/java/android/net/wifi/WifiStateTracker.java b/wifi/java/android/net/wifi/WifiStateTracker.java
index afaed24..810e4d2 100644
--- a/wifi/java/android/net/wifi/WifiStateTracker.java
+++ b/wifi/java/android/net/wifi/WifiStateTracker.java
@@ -943,7 +943,7 @@ public class WifiStateTracker extends NetworkStateTracker {
} else {
newDetailedState = DetailedState.FAILED;
}
- handleDisconnectedState(newDetailedState);
+ handleDisconnectedState(newDetailedState, true);
/**
* If we were associated with a network (networkId != -1),
* assume we reached this state because of a failed attempt
@@ -965,7 +965,7 @@ public class WifiStateTracker extends NetworkStateTracker {
} else if (newState == SupplicantState.DISCONNECTED) {
mHaveIpAddress = false;
if (isDriverStopped() || mDisconnectExpected) {
- handleDisconnectedState(DetailedState.DISCONNECTED);
+ handleDisconnectedState(DetailedState.DISCONNECTED, true);
} else {
scheduleDisconnect();
}
@@ -1072,16 +1072,10 @@ public class WifiStateTracker extends NetworkStateTracker {
*/
if (wasDisconnectPending) {
DetailedState saveState = getNetworkInfo().getDetailedState();
- handleDisconnectedState(DetailedState.DISCONNECTED);
+ handleDisconnectedState(DetailedState.DISCONNECTED, false);
setDetailedStateInternal(saveState);
- } else {
- /**
- * stop DHCP to ensure there is a new IP address
- * even if the supplicant transitions without disconnect
- * COMPLETED -> ASSOCIATED -> COMPLETED
- */
- resetConnections(false);
}
+
configureInterface();
mLastBssid = result.BSSID;
mLastSsid = mWifiInfo.getSSID();
@@ -1116,7 +1110,7 @@ public class WifiStateTracker extends NetworkStateTracker {
case EVENT_DEFERRED_DISCONNECT:
if (mWifiInfo.getSupplicantState() != SupplicantState.UNINITIALIZED) {
- handleDisconnectedState(DetailedState.DISCONNECTED);
+ handleDisconnectedState(DetailedState.DISCONNECTED, true);
}
break;
@@ -1284,13 +1278,15 @@ public class WifiStateTracker extends NetworkStateTracker {
* Reset our IP state and send out broadcasts following a disconnect.
* @param newState the {@code DetailedState} to set. Should be either
* {@code DISCONNECTED} or {@code FAILED}.
+ * @param disableInterface indicates whether the interface should
+ * be disabled
*/
- private void handleDisconnectedState(DetailedState newState) {
+ private void handleDisconnectedState(DetailedState newState, boolean disableInterface) {
if (mDisconnectPending) {
cancelDisconnect();
}
mDisconnectExpected = false;
- resetConnections(true);
+ resetConnections(disableInterface);
setDetailedState(newState);
sendNetworkStateChangeBroadcast(mLastBssid);
mWifiInfo.setBSSID(null);