summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.bp45
-rw-r--r--apex/appsearch/Android.bp35
-rw-r--r--apex/appsearch/apex_manifest.json4
-rw-r--r--apex/appsearch/com.android.appsearch.avbpubkeybin0 -> 1032 bytes
-rw-r--r--apex/appsearch/com.android.appsearch.pem51
-rw-r--r--apex/appsearch/com.android.appsearch.pk8bin0 -> 2373 bytes
-rw-r--r--apex/appsearch/com.android.appsearch.x509.pem35
-rw-r--r--apex/appsearch/service/Android.bp3
-rw-r--r--apex/appsearch/service/java/com/android/server/appsearch/impl/FakeIcing.java168
-rw-r--r--apex/jobscheduler/framework/java/android/app/job/JobSchedulerFrameworkInitializer.java4
-rw-r--r--apex/jobscheduler/framework/java/android/os/DeviceIdleManager.java4
-rw-r--r--apex/jobscheduler/framework/java/android/os/IDeviceIdleController.aidl1
-rw-r--r--apex/jobscheduler/framework/java/android/os/PowerWhitelistManager.java85
-rw-r--r--apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java12
-rw-r--r--apex/sdkext/Android.bp32
-rw-r--r--apex/sdkext/OWNERS1
-rw-r--r--apex/sdkext/com.android.sdkext.avbpubkeybin0 -> 1032 bytes
-rw-r--r--apex/sdkext/com.android.sdkext.pem51
-rw-r--r--apex/sdkext/com.android.sdkext.pk8bin0 -> 2375 bytes
-rw-r--r--apex/sdkext/com.android.sdkext.x509.pem35
-rw-r--r--apex/sdkext/framework/Android.bp30
-rw-r--r--apex/sdkext/framework/java/android/os/ext/SdkExtensions.java53
-rw-r--r--apex/sdkext/framework/java/android/os/ext/package.html5
-rw-r--r--apex/sdkext/framework/tests/Android.bp10
-rw-r--r--apex/sdkext/framework/tests/AndroidManifest.xml27
-rw-r--r--apex/sdkext/framework/tests/src/android/os/ext/SdkExtensionsTest.java45
-rw-r--r--apex/sdkext/manifest.json4
-rw-r--r--apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java26
-rw-r--r--api/current.txt27
-rw-r--r--api/system-current.txt221
-rw-r--r--api/system-lint-baseline.txt4
-rw-r--r--api/test-current.txt27
-rw-r--r--cmds/dpm/src/com/android/commands/dpm/Dpm.java14
-rw-r--r--cmds/statsd/Android.bp14
-rw-r--r--cmds/statsd/benchmark/log_event_benchmark.cpp55
-rw-r--r--cmds/statsd/src/atoms.proto3
-rw-r--r--cmds/statsd/src/logd/LogEvent.cpp203
-rw-r--r--cmds/statsd/src/logd/LogEvent.h72
-rwxr-xr-xcmds/statsd/src/socket/StatsSocketListener.cpp19
-rw-r--r--cmds/statsd/tests/LogEvent_test.cpp271
-rw-r--r--core/TEST_MAPPING24
-rw-r--r--core/java/android/app/Activity.java46
-rw-r--r--core/java/android/app/ContextImpl.java12
-rw-r--r--core/java/android/app/EventLogTags.logtags36
-rw-r--r--core/java/android/app/INotificationManager.aidl3
-rw-r--r--core/java/android/app/SystemServiceRegistry.java59
-rw-r--r--core/java/android/app/admin/DevicePolicyManager.java35
-rw-r--r--core/java/android/app/admin/IDevicePolicyManager.aidl2
-rw-r--r--core/java/android/app/backup/BackupManager.java25
-rw-r--r--core/java/android/app/backup/IBackupManager.aidl6
-rw-r--r--core/java/android/app/timedetector/ITimeDetectorService.aidl2
-rw-r--r--core/java/android/app/timedetector/ManualTimeSuggestion.aidl (renamed from services/wifi/java/android/net/wifi/IWifiStackConnector.aidl)16
-rw-r--r--core/java/android/app/timedetector/ManualTimeSuggestion.java127
-rw-r--r--core/java/android/app/timedetector/PhoneTimeSuggestion.java23
-rw-r--r--core/java/android/app/timedetector/TimeDetector.java37
-rw-r--r--core/java/android/app/timezonedetector/ITimeZoneDetectorService.aidl36
-rw-r--r--core/java/android/app/timezonedetector/PhoneTimeZoneSuggestion.aidl19
-rw-r--r--core/java/android/app/timezonedetector/PhoneTimeZoneSuggestion.java341
-rw-r--r--core/java/android/app/timezonedetector/TimeZoneDetector.java59
-rw-r--r--core/java/android/app/usage/IUsageStatsManager.aidl1
-rw-r--r--core/java/android/app/usage/UsageStatsManager.java12
-rw-r--r--core/java/android/content/Context.java78
-rw-r--r--core/java/android/content/ContextWrapper.java10
-rw-r--r--core/java/android/content/Intent.java16
-rw-r--r--core/java/android/content/integrity/AppInstallMetadata.java (renamed from services/core/java/com/android/server/integrity/model/AppInstallMetadata.java)2
-rw-r--r--core/java/android/content/integrity/AppIntegrityManager.java103
-rw-r--r--core/java/android/content/integrity/AtomicFormula.java (renamed from services/core/java/com/android/server/integrity/model/AtomicFormula.java)2
-rw-r--r--core/java/android/content/integrity/CompoundFormula.java (renamed from services/core/java/com/android/server/integrity/model/OpenFormula.java)37
-rw-r--r--core/java/android/content/integrity/Formula.java (renamed from services/core/java/com/android/server/integrity/model/Formula.java)16
-rw-r--r--core/java/android/content/integrity/IAppIntegrityManager.aidl28
-rw-r--r--core/java/android/content/integrity/Rule.aidl19
-rw-r--r--core/java/android/content/integrity/Rule.java (renamed from services/core/java/com/android/server/integrity/model/Rule.java)2
-rw-r--r--core/java/android/content/integrity/RuleSet.java92
-rw-r--r--core/java/android/content/pm/PermissionInfo.java15
-rw-r--r--core/java/android/content/pm/UserInfo.java9
-rw-r--r--core/java/android/net/IpConfiguration.java10
-rw-r--r--core/java/android/net/LinkProperties.java6
-rw-r--r--core/java/android/os/Binder.java13
-rwxr-xr-xcore/java/android/os/Build.java4
-rw-r--r--core/java/android/os/FileObserver.java2
-rw-r--r--core/java/android/os/ResultReceiver.aidl18
-rw-r--r--core/java/android/os/UserHandle.java21
-rw-r--r--core/java/android/os/UserManager.java5
-rw-r--r--core/java/android/os/connectivity/WifiBatteryStats.java4
-rw-r--r--core/java/android/os/incremental/IIncrementalManager.aidl (renamed from core/java/android/os/incremental/IIncrementalService.aidl)24
-rw-r--r--core/java/android/os/incremental/IncrementalDataLoaderParams.java84
-rw-r--r--core/java/android/os/incremental/IncrementalDataLoaderParamsParcel.aidl2
-rw-r--r--core/java/android/os/incremental/IncrementalManager.java327
-rw-r--r--core/java/android/os/incremental/IncrementalStorage.java346
-rw-r--r--core/java/android/provider/Settings.java122
-rw-r--r--core/java/android/provider/Telephony.java (renamed from telephony/java/android/provider/Telephony.java)0
-rw-r--r--core/java/android/service/autofill/SaveInfo.java20
-rw-r--r--core/java/android/util/FeatureFlagUtils.java2
-rw-r--r--core/java/android/view/MotionEvent.java2
-rw-r--r--core/java/android/view/SurfaceControl.java15
-rw-r--r--core/java/android/view/WindowlessViewRoot.java16
-rw-r--r--core/java/android/view/WindowlessWindowManager.java33
-rw-r--r--core/java/android/view/accessibility/AccessibilityEvent.java60
-rw-r--r--core/java/android/view/accessibility/AccessibilityNodeInfo.java161
-rw-r--r--core/java/android/view/accessibility/AccessibilityRecord.java25
-rw-r--r--core/java/android/view/accessibility/AccessibilityWindowInfo.java23
-rw-r--r--core/java/com/android/internal/app/SuspendedAppActivity.java5
-rw-r--r--core/java/com/android/internal/content/NativeLibraryHelper.java19
-rw-r--r--core/java/com/android/internal/os/BatteryStatsImpl.java1
-rw-r--r--core/java/com/android/internal/os/ZygoteInit.java28
-rw-r--r--core/java/com/android/internal/util/BitUtils.java6
-rw-r--r--core/jni/Android.bp3
-rwxr-xr-xcore/jni/android/graphics/Bitmap.cpp1
-rw-r--r--core/jni/android/graphics/BitmapRegionDecoder.cpp5
-rw-r--r--core/jni/android/graphics/CreateJavaOutputStreamAdaptor.cpp1
-rw-r--r--core/jni/android/graphics/Path.cpp16
-rw-r--r--core/jni/android/graphics/Typeface.cpp2
-rw-r--r--core/jni/android/graphics/Utils.cpp2
-rw-r--r--core/jni/android/graphics/Utils.h2
-rw-r--r--core/jni/android/graphics/apex/include/android/graphics/renderthread.h33
-rw-r--r--core/jni/android/graphics/apex/renderthread.cpp25
-rw-r--r--core/jni/android_app_ActivityThread.cpp6
-rw-r--r--core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp3
-rw-r--r--core/jni/android_util_Binder.cpp24
-rw-r--r--core/jni/android_view_SurfaceControl.cpp12
-rw-r--r--core/jni/android_view_TextureLayer.cpp5
-rw-r--r--core/proto/android/app/settings_enums.proto16
-rw-r--r--core/res/AndroidManifest.xml29
-rw-r--r--core/res/res/layout/shutdown_dialog.xml13
-rw-r--r--core/res/res/values-af/strings.xml8
-rw-r--r--core/res/res/values-am/strings.xml11
-rw-r--r--core/res/res/values-ar/strings.xml11
-rw-r--r--core/res/res/values-as/strings.xml11
-rw-r--r--core/res/res/values-az/strings.xml11
-rw-r--r--core/res/res/values-b+sr+Latn/strings.xml8
-rw-r--r--core/res/res/values-be/strings.xml11
-rw-r--r--core/res/res/values-bg/strings.xml11
-rw-r--r--core/res/res/values-bn/strings.xml11
-rw-r--r--core/res/res/values-bs/strings.xml8
-rw-r--r--core/res/res/values-ca/strings.xml11
-rw-r--r--core/res/res/values-cs/strings.xml8
-rw-r--r--core/res/res/values-da/strings.xml8
-rw-r--r--core/res/res/values-de/strings.xml10
-rw-r--r--core/res/res/values-el/strings.xml8
-rw-r--r--core/res/res/values-en-rAU/strings.xml8
-rw-r--r--core/res/res/values-en-rCA/strings.xml8
-rw-r--r--core/res/res/values-en-rGB/strings.xml8
-rw-r--r--core/res/res/values-en-rIN/strings.xml8
-rw-r--r--core/res/res/values-en-rXC/strings.xml8
-rw-r--r--core/res/res/values-es-rUS/strings.xml8
-rw-r--r--core/res/res/values-es/strings.xml8
-rw-r--r--core/res/res/values-et/strings.xml11
-rw-r--r--core/res/res/values-eu/strings.xml8
-rw-r--r--core/res/res/values-fa/strings.xml11
-rw-r--r--core/res/res/values-fi/strings.xml8
-rw-r--r--core/res/res/values-fr-rCA/strings.xml11
-rw-r--r--core/res/res/values-fr/strings.xml10
-rw-r--r--core/res/res/values-gl/strings.xml11
-rw-r--r--core/res/res/values-gu/strings.xml11
-rw-r--r--core/res/res/values-hi/strings.xml11
-rw-r--r--core/res/res/values-hr/strings.xml8
-rw-r--r--core/res/res/values-hu/strings.xml8
-rw-r--r--core/res/res/values-hy/strings.xml11
-rw-r--r--core/res/res/values-in/strings.xml8
-rw-r--r--core/res/res/values-is/strings.xml11
-rw-r--r--core/res/res/values-it/strings.xml8
-rw-r--r--core/res/res/values-iw/strings.xml11
-rw-r--r--core/res/res/values-ja/strings.xml11
-rw-r--r--core/res/res/values-ka/strings.xml11
-rw-r--r--core/res/res/values-kk/strings.xml11
-rw-r--r--core/res/res/values-km/strings.xml11
-rw-r--r--core/res/res/values-kn/strings.xml11
-rw-r--r--core/res/res/values-ko/strings.xml11
-rw-r--r--core/res/res/values-ky/strings.xml14
-rw-r--r--core/res/res/values-lo/strings.xml11
-rw-r--r--core/res/res/values-lt/strings.xml8
-rw-r--r--core/res/res/values-lv/strings.xml11
-rw-r--r--core/res/res/values-mk/strings.xml8
-rw-r--r--core/res/res/values-ml/strings.xml11
-rw-r--r--core/res/res/values-mn/strings.xml11
-rw-r--r--core/res/res/values-mr/strings.xml11
-rw-r--r--core/res/res/values-ms/strings.xml11
-rw-r--r--core/res/res/values-my/strings.xml11
-rw-r--r--core/res/res/values-nb/strings.xml13
-rw-r--r--core/res/res/values-ne/strings.xml11
-rw-r--r--core/res/res/values-nl/strings.xml8
-rw-r--r--core/res/res/values-or/strings.xml11
-rw-r--r--core/res/res/values-pa/strings.xml11
-rw-r--r--core/res/res/values-pl/strings.xml11
-rw-r--r--core/res/res/values-pt-rBR/strings.xml8
-rw-r--r--core/res/res/values-pt-rPT/strings.xml8
-rw-r--r--core/res/res/values-pt/strings.xml8
-rw-r--r--core/res/res/values-ro/strings.xml11
-rw-r--r--core/res/res/values-ru/strings.xml11
-rw-r--r--core/res/res/values-si/strings.xml11
-rw-r--r--core/res/res/values-sk/strings.xml11
-rw-r--r--core/res/res/values-sl/strings.xml11
-rw-r--r--core/res/res/values-sq/strings.xml11
-rw-r--r--core/res/res/values-sr/strings.xml8
-rw-r--r--core/res/res/values-sv/strings.xml8
-rw-r--r--core/res/res/values-sw/strings.xml11
-rw-r--r--core/res/res/values-ta/strings.xml11
-rw-r--r--core/res/res/values-te/strings.xml11
-rw-r--r--core/res/res/values-th/strings.xml11
-rw-r--r--core/res/res/values-tl/strings.xml11
-rw-r--r--core/res/res/values-tr/strings.xml11
-rw-r--r--core/res/res/values-uk/strings.xml11
-rw-r--r--core/res/res/values-ur/strings.xml11
-rw-r--r--core/res/res/values-uz/strings.xml8
-rw-r--r--core/res/res/values-vi/strings.xml11
-rw-r--r--core/res/res/values-zh-rCN/strings.xml11
-rw-r--r--core/res/res/values-zh-rHK/strings.xml11
-rw-r--r--core/res/res/values-zh-rTW/strings.xml11
-rw-r--r--core/res/res/values-zu/strings.xml8
-rw-r--r--core/res/res/values/attrs_manifest.xml3
-rw-r--r--core/res/res/values/config.xml18
-rw-r--r--core/res/res/values/strings.xml7
-rw-r--r--core/res/res/values/symbols.xml4
-rw-r--r--core/tests/coretests/src/android/app/timedetector/PhoneTimeSuggestionTest.java23
-rw-r--r--core/tests/coretests/src/android/app/timezonedetector/PhoneTimeZoneSuggestionTest.java170
-rw-r--r--core/tests/coretests/src/android/content/integrity/AtomicFormulaTest.java (renamed from services/tests/servicestests/src/com/android/server/integrity/model/AtomicFormulaTest.java)44
-rw-r--r--core/tests/coretests/src/android/content/integrity/CompoundFormulaTest.java (renamed from services/tests/servicestests/src/com/android/server/integrity/model/OpenFormulaTest.java)113
-rw-r--r--core/tests/coretests/src/android/content/integrity/RuleTest.java (renamed from services/tests/servicestests/src/com/android/server/integrity/model/RuleTest.java)20
-rw-r--r--core/tests/coretests/src/android/content/integrity/TEST_MAPPING12
-rw-r--r--core/tests/coretests/src/android/content/integrity/TestUtils.java51
-rw-r--r--core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java9
-rw-r--r--data/etc/preinstalled-packages-platform.xml45
-rw-r--r--data/etc/privapp-permissions-platform.xml18
-rw-r--r--libs/hwui/tests/unit/VectorDrawableTests.cpp6
-rw-r--r--libs/hwui/utils/VectorDrawableUtils.cpp4
-rw-r--r--location/TEST_MAPPING5
-rw-r--r--location/java/android/location/GnssStatus.java59
-rw-r--r--location/java/android/location/IGnssStatusListener.aidl2
-rw-r--r--location/java/android/location/LocationManager.java5
-rw-r--r--location/tests/locationtests/src/android/location/GnssStatusTest.java130
-rw-r--r--location/tests/locationtests/src/android/location/SatelliteInfo.java155
-rw-r--r--media/java/android/media/IMediaRoute2ProviderClient.aidl3
-rw-r--r--media/java/android/media/MediaRoute2ProviderService.java69
-rw-r--r--media/java/android/media/MediaRouter.java1
-rw-r--r--media/java/android/media/MediaRouter2.java13
-rw-r--r--media/jni/Android.bp1
-rw-r--r--media/jni/android_media_MediaDataSource.h2
-rw-r--r--media/jni/android_media_MediaDrm.cpp5
-rw-r--r--media/jni/android_media_Streams.cpp61
-rw-r--r--media/jni/android_media_Streams.h44
-rw-r--r--media/tests/MediaRouteProvider/src/com/android/mediarouteprovider/example/SampleMediaRoute2ProviderService.java4
-rw-r--r--media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java186
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/TEST_MAPPING2
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/statusbar/car/UserGridRecyclerView.java32
-rw-r--r--packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java51
-rw-r--r--packages/ExternalStorageProvider/tests/src/com/android/externalstorage/ExternalStorageProviderTest.java17
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/core/instrumentation/VisibilityLoggerMixin.java13
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java11
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java4
-rw-r--r--packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java1
-rw-r--r--packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java1
-rw-r--r--packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java1
-rw-r--r--packages/SystemUI/TEST_MAPPING23
-rw-r--r--packages/SystemUI/res/drawable/action_chip_background.xml27
-rw-r--r--packages/SystemUI/res/drawable/action_chip_container_background.xml21
-rw-r--r--packages/SystemUI/res/layout/global_screenshot.xml9
-rw-r--r--packages/SystemUI/res/layout/global_screenshot_action_chip.xml25
-rw-r--r--packages/SystemUI/res/values-night/colors.xml5
-rw-r--r--packages/SystemUI/res/values/colors.xml5
-rw-r--r--packages/SystemUI/res/values/config.xml1
-rw-r--r--packages/SystemUI/res/values/dimens.xml10
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/dock/DockManager.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java46
-rw-r--r--packages/SystemUI/src/com/android/systemui/power/InattentiveSleepWarningController.java62
-rw-r--r--packages/SystemUI/src/com/android/systemui/power/PowerUI.java25
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java113
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotController.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java35
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/usb/UsbConfirmActivity.java36
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotNotificationSmartActionsTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HotspotControllerImplTest.java1
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeHotspotController.java4
-rw-r--r--packages/Tethering/Android.bp70
-rw-r--r--packages/Tethering/AndroidManifest.xml6
-rw-r--r--packages/Tethering/AndroidManifest_InProcess.xml35
-rw-r--r--packages/Tethering/CleanSpec.mk52
-rw-r--r--packages/Tethering/apex/Android.bp35
-rw-r--r--packages/Tethering/apex/AndroidManifest.xml27
-rw-r--r--packages/Tethering/apex/com.android.tethering.apex.avbpubkeybin0 -> 1032 bytes
-rw-r--r--packages/Tethering/apex/com.android.tethering.apex.pem51
-rw-r--r--packages/Tethering/apex/com.android.tethering.apex.pk8bin0 -> 2375 bytes
-rw-r--r--packages/Tethering/apex/com.android.tethering.apex.x509.pem36
-rw-r--r--packages/Tethering/apex/manifest.json4
-rw-r--r--packages/Tethering/common/TetheringLib/Android.bp13
-rw-r--r--packages/Tethering/common/TetheringLib/src/android/net/ITetherInternalCallback.aidl34
-rw-r--r--packages/Tethering/common/TetheringLib/src/android/net/ITetheringConnector.aidl17
-rw-r--r--packages/Tethering/common/TetheringLib/src/android/net/TetherStatesParcel.aidl31
-rw-r--r--packages/Tethering/common/TetheringLib/src/android/net/TetheringConfigurationParcel.aidl37
-rw-r--r--packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java513
-rw-r--r--packages/Tethering/jni/com_android_server_connectivity_tethering_OffloadHardwareInterface.cpp14
-rw-r--r--packages/Tethering/src/android/net/util/BaseNetdUnsolicitedEventListener.java70
-rw-r--r--packages/Tethering/src/android/net/util/VersionedBroadcastListener.java (renamed from services/net/java/android/net/util/VersionedBroadcastListener.java)13
-rw-r--r--packages/Tethering/src/com/android/server/connectivity/tethering/EntitlementManager.java19
-rw-r--r--packages/Tethering/src/com/android/server/connectivity/tethering/IPv6TetheringCoordinator.java (renamed from services/core/java/com/android/server/connectivity/tethering/IPv6TetheringCoordinator.java)27
-rw-r--r--packages/Tethering/src/com/android/server/connectivity/tethering/OffloadHardwareInterface.java2
-rw-r--r--packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java (renamed from services/core/java/com/android/server/connectivity/Tethering.java)330
-rw-r--r--packages/Tethering/src/com/android/server/connectivity/tethering/TetheringConfiguration.java29
-rw-r--r--packages/Tethering/src/com/android/server/connectivity/tethering/TetheringDependencies.java (renamed from services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java)61
-rw-r--r--packages/Tethering/src/com/android/server/connectivity/tethering/TetheringInterfaceUtils.java (renamed from services/core/java/com/android/server/connectivity/tethering/TetheringInterfaceUtils.java)0
-rw-r--r--packages/Tethering/src/com/android/server/connectivity/tethering/TetheringService.java178
-rw-r--r--packages/Tethering/tests/unit/Android.bp15
-rw-r--r--packages/Tethering/tests/unit/src/android/net/util/VersionedBroadcastListenerTest.java (renamed from tests/net/java/android/net/util/VersionedBroadcastListenerTest.java)6
-rw-r--r--packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/EntitlementManagerTest.java45
-rw-r--r--packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java (renamed from tests/net/java/com/android/server/connectivity/TetheringTest.java)293
-rw-r--r--packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java12
-rw-r--r--packages/WallpaperBackup/test/src/com/android/wallpaperbackup/tests/WallpaperBackupAgentTest.java112
-rw-r--r--services/Android.bp2
-rw-r--r--services/autofill/java/com/android/server/autofill/ui/FillUi.java2
-rw-r--r--services/autofill/java/com/android/server/autofill/ui/SaveUi.java15
-rw-r--r--services/backup/java/com/android/server/backup/BackupManagerService.java21
-rw-r--r--services/backup/java/com/android/server/backup/DataChangedJournal.java9
-rw-r--r--services/backup/java/com/android/server/backup/UserBackupManagerService.java24
-rw-r--r--services/backup/java/com/android/server/backup/UserBackupPreferences.java63
-rw-r--r--services/backup/java/com/android/server/backup/internal/BackupHandler.java3
-rw-r--r--services/backup/java/com/android/server/backup/params/RestoreParams.java32
-rw-r--r--services/backup/java/com/android/server/backup/restore/ActiveRestoreSession.java9
-rw-r--r--services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java76
-rw-r--r--services/core/Android.bp11
-rw-r--r--services/core/java/android/content/pm/PackageManagerInternal.java5
-rw-r--r--services/core/java/android/os/UserManagerInternal.java34
-rw-r--r--services/core/java/com/android/server/ConnectivityService.java277
-rw-r--r--services/core/java/com/android/server/EventLogTags.logtags21
-rw-r--r--services/core/java/com/android/server/LocationManagerService.java278
-rw-r--r--services/core/java/com/android/server/PackageWatchdog.java71
-rw-r--r--services/core/java/com/android/server/StorageManagerService.java36
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java32
-rw-r--r--services/core/java/com/android/server/am/AppCompactor.java4
-rw-r--r--services/core/java/com/android/server/am/EventLogTags.logtags68
-rw-r--r--services/core/java/com/android/server/am/ProcessList.java9
-rw-r--r--services/core/java/com/android/server/compat/CompatChange.java34
-rw-r--r--services/core/java/com/android/server/compat/CompatConfig.java23
-rw-r--r--services/core/java/com/android/server/compat/PlatformCompat.java17
-rw-r--r--services/core/java/com/android/server/connectivity/NetworkAgentInfo.java2
-rw-r--r--services/core/java/com/android/server/display/DisplayDevice.java10
-rw-r--r--services/core/java/com/android/server/display/DisplayModeDirector.java323
-rw-r--r--services/core/java/com/android/server/display/LocalDisplayAdapter.java41
-rw-r--r--services/core/java/com/android/server/display/LogicalDisplay.java5
-rw-r--r--services/core/java/com/android/server/display/OverlayDisplayAdapter.java13
-rw-r--r--services/core/java/com/android/server/display/WifiDisplayController.java3
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java12
-rw-r--r--services/core/java/com/android/server/input/InputManagerService.java21
-rw-r--r--services/core/java/com/android/server/integrity/engine/RuleEvaluationEngine.java15
-rw-r--r--services/core/java/com/android/server/integrity/engine/RuleEvaluator.java26
-rw-r--r--services/core/java/com/android/server/integrity/engine/RuleLoader.java2
-rw-r--r--services/core/java/com/android/server/integrity/model/IntegrityCheckResult.java1
-rw-r--r--services/core/java/com/android/server/integrity/parser/RuleBinaryParser.java2
-rw-r--r--services/core/java/com/android/server/integrity/parser/RuleParser.java2
-rw-r--r--services/core/java/com/android/server/integrity/parser/RuleXmlParser.java41
-rw-r--r--services/core/java/com/android/server/integrity/serializer/RuleBinarySerializer.java8
-rw-r--r--services/core/java/com/android/server/integrity/serializer/RuleSerializer.java9
-rw-r--r--services/core/java/com/android/server/integrity/serializer/RuleXmlSerializer.java61
-rw-r--r--services/core/java/com/android/server/location/GnssLocationProvider.java15
-rw-r--r--services/core/java/com/android/server/location/GnssStatusListenerHelper.java5
-rw-r--r--services/core/java/com/android/server/locksettings/LockSettingsService.java47
-rw-r--r--services/core/java/com/android/server/media/MediaRoute2Provider.java8
-rw-r--r--services/core/java/com/android/server/media/MediaRoute2ProviderProxy.java30
-rw-r--r--services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java24
-rw-r--r--services/core/java/com/android/server/net/NetworkStatsService.java1
-rw-r--r--services/core/java/com/android/server/notification/NotificationHistoryDatabase.java9
-rw-r--r--services/core/java/com/android/server/notification/NotificationHistoryManager.java115
-rwxr-xr-xservices/core/java/com/android/server/notification/NotificationManagerService.java146
-rw-r--r--services/core/java/com/android/server/notification/SnoozeHelper.java3
-rw-r--r--services/core/java/com/android/server/pm/PackageAbiHelperImpl.java46
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerSession.java8
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java38
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerShellCommand.java227
-rw-r--r--services/core/java/com/android/server/pm/StagingManager.java26
-rw-r--r--services/core/java/com/android/server/pm/UserManagerService.java39
-rw-r--r--services/core/java/com/android/server/pm/UserRestrictionsUtils.java37
-rw-r--r--services/core/java/com/android/server/pm/UserSystemPackageInstaller.java301
-rw-r--r--services/core/java/com/android/server/pm/UserTypeDetails.java8
-rw-r--r--services/core/java/com/android/server/pm/permission/BasePermission.java3
-rw-r--r--services/core/java/com/android/server/pm/permission/PermissionManagerService.java7
-rw-r--r--services/core/java/com/android/server/power/ShutdownThread.java6
-rw-r--r--services/core/java/com/android/server/timedetector/SimpleTimeDetectorStrategy.java136
-rw-r--r--services/core/java/com/android/server/timedetector/TimeDetectorService.java28
-rw-r--r--services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java8
-rw-r--r--services/core/java/com/android/server/timedetector/TimeDetectorStrategyCallbackImpl.java2
-rw-r--r--services/core/java/com/android/server/timezonedetector/TimeZoneDetectorCallbackImpl.java79
-rw-r--r--services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java115
-rw-r--r--services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java507
-rw-r--r--services/core/java/com/android/server/wm/ActivityDisplay.java3
-rw-r--r--services/core/java/com/android/server/wm/ActivityMetricsLogger.java4
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java36
-rw-r--r--services/core/java/com/android/server/wm/ActivityStack.java37
-rw-r--r--services/core/java/com/android/server/wm/ActivityStackSupervisor.java6
-rw-r--r--services/core/java/com/android/server/wm/ActivityStarter.java27
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskManagerService.java15
-rw-r--r--services/core/java/com/android/server/wm/EventLogTags.logtags77
-rw-r--r--services/core/java/com/android/server/wm/KeyguardController.java6
-rw-r--r--services/core/java/com/android/server/wm/RootWindowContainer.java6
-rw-r--r--services/core/java/com/android/server/wm/Task.java12
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java10
-rw-r--r--services/core/jni/Android.bp2
-rw-r--r--services/core/jni/com_android_server_input_InputManagerService.cpp9
-rw-r--r--services/core/jni/com_android_server_location_GnssLocationProvider.cpp13
-rw-r--r--services/core/jni/onload.cpp2
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java160
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/Owners.java68
-rw-r--r--services/java/com/android/server/SystemServer.java58
-rw-r--r--services/net/Android.bp2
-rw-r--r--services/robotests/src/com/android/server/testing/shadows/ShadowPerformUnifiedRestoreTask.java6
-rw-r--r--services/tests/servicestests/Android.bp1
-rw-r--r--services/tests/servicestests/src/com/android/server/appsearch/impl/FakeIcingTest.java123
-rw-r--r--services/tests/servicestests/src/com/android/server/backup/DataChangedJournalTest.java10
-rw-r--r--services/tests/servicestests/src/com/android/server/backup/UserBackupPreferencesTest.java86
-rw-r--r--services/tests/servicestests/src/com/android/server/backup/restore/PerformUnifiedRestoreTaskTest.java126
-rw-r--r--services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java272
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java6
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java126
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java3
-rw-r--r--services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java137
-rw-r--r--services/tests/servicestests/src/com/android/server/integrity/engine/RuleEvaluatorTest.java123
-rw-r--r--services/tests/servicestests/src/com/android/server/integrity/parser/RuleXmlParserTest.java612
-rw-r--r--services/tests/servicestests/src/com/android/server/integrity/serializer/RuleXmlSerializerTest.java356
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/UserRestrictionsUtilsTest.java61
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/UserSystemPackageInstallerTest.java193
-rw-r--r--services/tests/servicestests/src/com/android/server/timedetector/SimpleTimeZoneDetectorStrategyTest.java190
-rw-r--r--services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java43
-rw-r--r--services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyTest.java592
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryDatabaseTest.java11
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryManagerTest.java172
-rwxr-xr-xservices/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java68
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java5
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java20
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java15
-rw-r--r--services/usage/java/com/android/server/usage/UsageStatsService.java16
-rw-r--r--services/wifi/Android.bp16
-rw-r--r--services/wifi/java/android/net/wifi/WifiStackClient.java100
-rw-r--r--telecomm/java/android/telecom/ConnectionRequest.java32
-rw-r--r--telecomm/java/android/telecom/TelecomManager.java10
-rw-r--r--telephony/common/com/android/internal/telephony/EncodeException.java (renamed from telephony/java/com/android/internal/telephony/EncodeException.java)0
-rw-r--r--telephony/java/android/service/carrier/CarrierIdentifier.aidl (renamed from core/java/android/service/carrier/CarrierIdentifier.aidl)0
-rw-r--r--telephony/java/android/service/carrier/CarrierIdentifier.java (renamed from core/java/android/service/carrier/CarrierIdentifier.java)0
-rw-r--r--telephony/java/android/service/carrier/CarrierService.java (renamed from core/java/android/service/carrier/CarrierService.java)0
-rw-r--r--telephony/java/android/service/carrier/ICarrierService.aidl (renamed from core/java/android/service/carrier/ICarrierService.aidl)0
-rw-r--r--telephony/java/android/service/euicc/DownloadSubscriptionResult.aidl (renamed from core/java/android/service/euicc/DownloadSubscriptionResult.aidl)0
-rw-r--r--telephony/java/android/service/euicc/DownloadSubscriptionResult.java (renamed from core/java/android/service/euicc/DownloadSubscriptionResult.java)0
-rw-r--r--telephony/java/android/service/euicc/EuiccProfileInfo.aidl (renamed from core/java/android/service/euicc/EuiccProfileInfo.aidl)0
-rw-r--r--telephony/java/android/service/euicc/EuiccProfileInfo.java (renamed from core/java/android/service/euicc/EuiccProfileInfo.java)0
-rw-r--r--telephony/java/android/service/euicc/EuiccService.java (renamed from core/java/android/service/euicc/EuiccService.java)0
-rw-r--r--telephony/java/android/service/euicc/GetDefaultDownloadableSubscriptionListResult.aidl (renamed from core/java/android/service/euicc/GetDefaultDownloadableSubscriptionListResult.aidl)0
-rw-r--r--telephony/java/android/service/euicc/GetDefaultDownloadableSubscriptionListResult.java (renamed from core/java/android/service/euicc/GetDefaultDownloadableSubscriptionListResult.java)0
-rw-r--r--telephony/java/android/service/euicc/GetDownloadableSubscriptionMetadataResult.aidl (renamed from core/java/android/service/euicc/GetDownloadableSubscriptionMetadataResult.aidl)0
-rw-r--r--telephony/java/android/service/euicc/GetDownloadableSubscriptionMetadataResult.java (renamed from core/java/android/service/euicc/GetDownloadableSubscriptionMetadataResult.java)0
-rw-r--r--telephony/java/android/service/euicc/GetEuiccProfileInfoListResult.aidl (renamed from core/java/android/service/euicc/GetEuiccProfileInfoListResult.aidl)0
-rw-r--r--telephony/java/android/service/euicc/GetEuiccProfileInfoListResult.java (renamed from core/java/android/service/euicc/GetEuiccProfileInfoListResult.java)0
-rw-r--r--telephony/java/android/service/euicc/IDeleteSubscriptionCallback.aidl (renamed from core/java/android/service/euicc/IDeleteSubscriptionCallback.aidl)0
-rw-r--r--telephony/java/android/service/euicc/IDownloadSubscriptionCallback.aidl (renamed from core/java/android/service/euicc/IDownloadSubscriptionCallback.aidl)0
-rw-r--r--telephony/java/android/service/euicc/IEraseSubscriptionsCallback.aidl (renamed from core/java/android/service/euicc/IEraseSubscriptionsCallback.aidl)0
-rw-r--r--telephony/java/android/service/euicc/IEuiccService.aidl (renamed from core/java/android/service/euicc/IEuiccService.aidl)0
-rw-r--r--telephony/java/android/service/euicc/IGetDefaultDownloadableSubscriptionListCallback.aidl (renamed from core/java/android/service/euicc/IGetDefaultDownloadableSubscriptionListCallback.aidl)0
-rw-r--r--telephony/java/android/service/euicc/IGetDownloadableSubscriptionMetadataCallback.aidl (renamed from core/java/android/service/euicc/IGetDownloadableSubscriptionMetadataCallback.aidl)0
-rw-r--r--telephony/java/android/service/euicc/IGetEidCallback.aidl (renamed from core/java/android/service/euicc/IGetEidCallback.aidl)0
-rw-r--r--telephony/java/android/service/euicc/IGetEuiccInfoCallback.aidl (renamed from core/java/android/service/euicc/IGetEuiccInfoCallback.aidl)0
-rw-r--r--telephony/java/android/service/euicc/IGetEuiccProfileInfoListCallback.aidl (renamed from core/java/android/service/euicc/IGetEuiccProfileInfoListCallback.aidl)0
-rw-r--r--telephony/java/android/service/euicc/IGetOtaStatusCallback.aidl (renamed from core/java/android/service/euicc/IGetOtaStatusCallback.aidl)0
-rw-r--r--telephony/java/android/service/euicc/IOtaStatusChangedCallback.aidl (renamed from core/java/android/service/euicc/IOtaStatusChangedCallback.aidl)0
-rw-r--r--telephony/java/android/service/euicc/IRetainSubscriptionsForFactoryResetCallback.aidl (renamed from core/java/android/service/euicc/IRetainSubscriptionsForFactoryResetCallback.aidl)0
-rw-r--r--telephony/java/android/service/euicc/ISwitchToSubscriptionCallback.aidl (renamed from core/java/android/service/euicc/ISwitchToSubscriptionCallback.aidl)0
-rw-r--r--telephony/java/android/service/euicc/IUpdateSubscriptionNicknameCallback.aidl (renamed from core/java/android/service/euicc/IUpdateSubscriptionNicknameCallback.aidl)0
-rw-r--r--telephony/java/android/telephony/DataFailCause.java7
-rw-r--r--telephony/java/android/telephony/LocationAccessPolicy.java15
-rw-r--r--telephony/java/android/telephony/SmsCbMessage.java15
-rw-r--r--telephony/java/android/telephony/SubscriptionManager.java49
-rw-r--r--telephony/java/android/telephony/TelephonyManager.java134
-rw-r--r--telephony/java/com/android/internal/telephony/CarrierAppUtils.java2
-rwxr-xr-xtelephony/java/com/android/internal/telephony/ISub.aidl2
-rw-r--r--telephony/java/com/android/internal/telephony/Sms7BitEncodingTranslator.java2
-rw-r--r--telephony/java/com/android/internal/telephony/TelephonyPermissions.java8
-rw-r--r--telephony/java/com/android/internal/telephony/util/ArrayUtils.java229
-rw-r--r--telephony/java/com/android/internal/telephony/util/XmlUtils.java75
-rw-r--r--test-mock/src/android/test/mock/MockContext.java7
-rw-r--r--tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java8
-rw-r--r--tests/net/Android.bp1
-rw-r--r--tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt5
-rw-r--r--tests/net/java/com/android/internal/util/BitUtilsTest.java87
-rw-r--r--tests/net/java/com/android/server/ConnectivityServiceTest.java57
-rw-r--r--tools/aapt2/cmd/Link.h4
-rw-r--r--tools/aapt2/cmd/Util.cpp4
-rw-r--r--tools/aapt2/cmd/Util_test.cpp22
-rw-r--r--tools/aapt2/java/JavaClassGenerator.cpp9
-rw-r--r--tools/aapt2/java/JavaClassGenerator_test.cpp12
-rw-r--r--wifi/java/android/net/wifi/SynchronousExecutor.java29
-rw-r--r--wifi/java/android/net/wifi/WifiConfiguration.java87
-rw-r--r--wifi/java/android/net/wifi/WifiFrameworkInitializer.java5
-rw-r--r--wifi/java/android/net/wifi/WifiManager.java539
-rw-r--r--wifi/java/android/net/wifi/WifiNetworkSuggestion.java54
-rw-r--r--wifi/java/android/net/wifi/WifiScanner.java221
-rw-r--r--wifi/java/android/net/wifi/aware/TlvBufferUtils.java66
-rw-r--r--wifi/java/android/net/wifi/aware/WifiAwareAgentNetworkSpecifier.java4
-rw-r--r--wifi/java/android/net/wifi/p2p/WifiP2pDevice.java8
-rw-r--r--wifi/java/android/net/wifi/rtt/package.html4
-rw-r--r--wifi/tests/src/android/net/wifi/WifiManagerTest.java9
-rw-r--r--wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java50
-rw-r--r--wifi/tests/src/android/net/wifi/WifiScannerTest.java166
505 files changed, 14542 insertions, 4944 deletions
diff --git a/Android.bp b/Android.bp
index a082085f6804..c1f6860980de 100644
--- a/Android.bp
+++ b/Android.bp
@@ -225,7 +225,6 @@ filegroup {
":framework-mca-filterfw-sources",
":framework-mca-filterpacks-sources",
":framework-media-sources",
- ":framework-mime-sources",
":framework-mms-sources",
":framework-opengl-sources",
":framework-rs-sources",
@@ -267,10 +266,19 @@ filegroup {
}
filegroup {
+ name: "framework-updatable-sources",
+ srcs: [
+ ":framework-sdkext-sources",
+ ":updatable-media-srcs",
+ ]
+}
+
+filegroup {
name: "framework-all-sources",
srcs: [
+ ":framework-mime-sources",
":framework-non-updatable-sources",
- ":updatable-media-srcs",
+ ":framework-updatable-sources",
],
}
@@ -375,7 +383,6 @@ java_defaults {
static_libs: [
"framework-internal-utils",
- "mimemap",
],
dxflags: [
@@ -438,6 +445,11 @@ java_library {
"media-provider-platform-compat-config",
"services-devicepolicy-platform-compat-config",
],
+ static_libs: [
+ // If MimeMap ever becomes its own APEX, then this dependency would need to be removed
+ // in favor of an API stubs dependency in java_library "framework" below.
+ "mimemap",
+ ],
// For backwards compatibility.
stem: "framework",
}
@@ -572,6 +584,12 @@ filegroup {
],
}
+java_library {
+ name: "framework-annotations-lib",
+ srcs: [ ":framework-annotations" ],
+ sdk_version: "current",
+}
+
filegroup {
name: "framework-networkstack-shared-srcs",
srcs: [
@@ -772,7 +790,7 @@ cc_library {
filegroup {
name: "incremental_aidl",
srcs: [
- "core/java/android/os/incremental/IIncrementalService.aidl",
+ "core/java/android/os/incremental/IIncrementalManager.aidl",
"core/java/android/os/incremental/IIncrementalServiceProxy.aidl",
"core/java/android/os/incremental/IncrementalDataLoaderParamsParcel.aidl",
"core/java/android/os/incremental/IncrementalFileSystemControlParcel.aidl",
@@ -1015,14 +1033,15 @@ packages_to_document = [
stubs_defaults {
name: "framework-doc-stubs-default",
srcs: [
+ ":framework-mime-sources",
":framework-non-updatable-sources",
+ ":framework-updatable-sources",
"core/java/**/*.logtags",
"test-base/src/**/*.java",
":opt-telephony-srcs",
":opt-net-voip-srcs",
":core-current-stubs-source",
":core_public_api_files",
- ":updatable-media-srcs",
"test-mock/src/**/*.java",
"test-runner/src/**/*.java",
],
@@ -1034,7 +1053,7 @@ stubs_defaults {
"sdk-dir",
"api-versions-jars-dir",
],
- previous_api: ":last-released-public-api-for-metalava-annotations",
+ previous_api: ":last-released-public-api",
merge_annotations_dirs: [
"metalava-manual",
],
@@ -1080,18 +1099,18 @@ stubs_defaults {
name: "metalava-api-stubs-default",
srcs: [
":framework-non-updatable-sources",
+ ":framework-updatable-sources",
"core/java/**/*.logtags",
":opt-telephony-srcs",
":opt-net-voip-srcs",
":core-current-stubs-source",
":core_public_api_files",
- ":updatable-media-srcs",
":ike-api-srcs",
],
libs: ["framework-internal-utils"],
installable: false,
annotations_enabled: true,
- previous_api: ":last-released-public-api-for-metalava-annotations",
+ previous_api: ":last-released-public-api",
merge_annotations_dirs: [
"metalava-manual",
],
@@ -1427,7 +1446,7 @@ droidstubs {
installable: false,
sdk_version: "core_platform",
annotations_enabled: true,
- previous_api: ":last-released-public-api-for-metalava-annotations",
+ previous_api: ":last-released-public-api",
merge_annotations_dirs: [
"metalava-manual",
],
@@ -1611,11 +1630,8 @@ filegroup {
"core/java/android/os/RegistrantList.java",
"core/java/android/os/Registrant.java",
"core/java/android/util/LocalLog.java",
- "core/java/android/util/Slog.java",
"core/java/android/util/TimeUtils.java",
"core/java/com/android/internal/os/SomeArgs.java",
- "core/java/com/android/internal/util/ArrayUtils.java",
- "core/java/com/android/internal/util/DumpUtils.java",
"core/java/com/android/internal/util/FastXmlSerializer.java",
"core/java/com/android/internal/util/HexDump.java",
"core/java/com/android/internal/util/IndentingPrintWriter.java",
@@ -1623,7 +1639,6 @@ filegroup {
"core/java/com/android/internal/util/State.java",
"core/java/com/android/internal/util/StateMachine.java",
"core/java/com/android/internal/util/UserIcons.java",
- "core/java/com/android/internal/util/XmlUtils.java",
],
}
@@ -1632,8 +1647,10 @@ filegroup {
filegroup {
name: "framework-cellbroadcast-shared-srcs",
srcs: [
+ "core/java/android/os/HandlerExecutor.java",
"core/java/android/util/LocalLog.java",
- "core/java/android/util/Slog.java",
+ "core/java/com/android/internal/util/IState.java",
+ "core/java/com/android/internal/util/Preconditions.java",
"core/java/com/android/internal/util/State.java",
"core/java/com/android/internal/util/StateMachine.java",
],
diff --git a/apex/appsearch/Android.bp b/apex/appsearch/Android.bp
new file mode 100644
index 000000000000..bcdcc7da8070
--- /dev/null
+++ b/apex/appsearch/Android.bp
@@ -0,0 +1,35 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+apex {
+ name: "com.android.appsearch",
+
+ manifest: "apex_manifest.json",
+
+ key: "com.android.appsearch.key",
+ certificate: ":com.android.appsearch.certificate",
+}
+
+apex_key {
+ name: "com.android.appsearch.key",
+ public_key: "com.android.appsearch.avbpubkey",
+ private_key: "com.android.appsearch.pem",
+}
+
+android_app_certificate {
+ name: "com.android.appsearch.certificate",
+ // This will use com.android.appsearch.x509.pem (the cert) and
+ // com.android.appsearch.pk8 (the private key)
+ certificate: "com.android.appsearch",
+}
diff --git a/apex/appsearch/apex_manifest.json b/apex/appsearch/apex_manifest.json
new file mode 100644
index 000000000000..273b867e8f98
--- /dev/null
+++ b/apex/appsearch/apex_manifest.json
@@ -0,0 +1,4 @@
+{
+ "name": "com.android.appsearch",
+ "version": 1
+}
diff --git a/apex/appsearch/com.android.appsearch.avbpubkey b/apex/appsearch/com.android.appsearch.avbpubkey
new file mode 100644
index 000000000000..4e5acae9c1e4
--- /dev/null
+++ b/apex/appsearch/com.android.appsearch.avbpubkey
Binary files differ
diff --git a/apex/appsearch/com.android.appsearch.pem b/apex/appsearch/com.android.appsearch.pem
new file mode 100644
index 000000000000..4ed5945acc86
--- /dev/null
+++ b/apex/appsearch/com.android.appsearch.pem
@@ -0,0 +1,51 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIJKQIBAAKCAgEAro9f/jvoIsj6ywuRmuUQS8UtprhohJitrovDMfm/T2R/WQvy
+AvUxgetyF4XvBPCDRqCsGxXCJMQOn1furrAeTmWbGHPhA0PI1Ys/qtfNMbh9THyn
+70I2c4X70CUQ+8/Y8BJ8CAB4iER/s9QtD28QLvM2BBUzRoKUSBGUYNMlYobjgRdK
+57V7yg48LkvUIg1fzIW3M5gCgOXa0u1xOadKX3m7tzCboHcXp5anfWX5PH1+okRu
+jzdI8OjtUq23qhoRw5Skz0Vbf4a+8t3kT3slF/Q7O8LoRPwpZsvIcvTyCGAqlra7
+2L2LN4H1p+u2ko3r/QmRbJn2eXW07elkyrggXMyn2rTxibQgk53wYfSavMyNd/E7
++de/uJ60l2aPa+5KUaR8eYwchXEELdqQ+zRgSZ2711xCaY4glEj7DT6VlEEdr26x
+akX0ra7e2sVGv1um/dvSyVO5aFKKjVvo4LqhWKWO8yvDMxmDDTNatvWhY2Bhd3RA
+0hilYpWQFb9Tv5f4E0tZmfvlddgux7sw++Y/RIimBFoSyf5AezAUIFYYoYvEzytB
+muq1/ecNHr+Z2tZMxN88sJVhzRzD9tKUyXhvxOV2Lg9TIeVTWGwQqgSnHWtIe+1p
+cw8inPfYEhP4Q+3W/RlPvNdu75x8Nj2aG7bxZnhoQDRDw5ddgma27I+a8esCAwEA
+AQKCAgBsNh9I6HRAVBz8kCBkSEnw3rwtFTZdtJQ+lw+bRHpvShqT5g7R/JQDOSTS
+JkoE4uBOgT4P0E45Inz6FLW2/yDacqxR3UwJDRVMI/WFACCJCRhLuR8V+BLvTIjN
+AJ1lrPSL5rmS8E/IEcakgQyp+6ypnkXHBCl0NXCcuKEl4N7VFE+mb/0UZPHnUSnH
+fWR085uGmwH17u7mXxdnGKDPH8DALSPMLUrcj9dPIdqUpwl5kUZWa1uqVphWF98/
+GMe5oE2Q0+3TO+i7xplKz3lAOFPHZLTvmCUK1tMHkZ6ifOwpewwLwB30/5N1BpB1
+126nrWk0xKCtFUixBOHzdnLwJHKSbi7chQU5q39oAJoTfxdmAJlaG0zQHUQZ44MQ
+gemzSA7uJbtoAOAZVF1K14xbIpnfidqTB7N3RCmiJE+/Hpkq6PxgPfu5rqocPbPC
+t0FgJ4NXNmKOAuJllSlrrHATcUOhF4g5pX7tvOc8X4y7bvfwOmtw5ez3INKMF0q6
+/y0vVCi6N1Z7CTa9eY8feZ1PImk/Fkq4NInSPyx7ZE3pLYmsvuJjliFrWo9TRVae
+Dt5vvBKBOpAfhDiHkeXbX7Raj2B6c6adF4no/3SAVlAjIq1iBVjfQWyHAGUoEW1O
+u3LdHTIb6gSTLJ4AfryEKrOE+1VMlYt92GwX692KKXMaJjytSQKCAQEA3pYbl8HD
+Y++UyEN5VzWAQedT3//GDwpDfgdERe2E4smYrkVNJ2WAG2SqY1A35DIl8be3eHvl
+soaL38j48ailfDYY9tI+IlapNh+VOLej+HiOytaPlLhcv2FpSC2qZT4EiU6IBXLo
++l6FrmD/VQXTjvoktzsDB/n1t4Dfa3Ogf+lLf1Jxr94YpEnDh18V5ofj78SplVLm
+NrzsHxAafE4Ni2a7dyWjcDYIuL7FTShT+0K4W45tRr+CGxThxu7LEe7zw4Z1IagU
+jJNtXjvDD/Zw4UTqI6RwWGZsu6UjPS6LHhOqnWqflWmFRIfMbDkuWvnGZTM9DkVg
+kk1+BNi1PECZXwKCAQEAyMOjbVo6XV3lFN0X8TpHyg/z9ar00/SE7WEJHqPSuzYT
+rSfU4vDDlaPAwkYvGi9ZKi9VM+R3CyBNxnK9Yq6NurHhhrYcAwdS/hGLT1K2o0Y8
+Pgv7gZCFb+SIwLBhlUG9otGULcBzLneqgVUqyMG6IoCjuC2LRyB71Xc2UMyg6n/f
+XpV2RTMb8f+26cgm6nj0SDAfgpr8HV6uNV80c6l1A8gq86nUWwiVAEUdmExSDe7J
+shsfWAj8RSErqDXf1BtEdPLJUSIPX5VXkzAXOXIkengwVno0vv0dBN8uraS8iQSG
+0JsJLLcw9b5kvnh6FEbE7POsIqKyCZV9VADwO6YW9QKCAQBYQsdwNqoGv6KMgozj
+8tgHyfWtVduwbQ50M+dznwpZbzz2pY5Bd/MDabhSpyVyfBwlrAa5ZM+hKc7fDu7/
+zDLKfR0LCjUPIrP4PS/LjK4dQZjFf6zxeOV2EedQcqMlgCEGXTh8iKMvXDm/+sBk
+c2n/QNs8OM8r44b2m8h78B6NefGw6/0ekn/M7V72F9M0VWAh3Cauim+09tbePmFy
+NvUR+MuPJEKZpSNyNltADCS49izqSSC1tAygNniMjHXDh6/rMS7TCLYVRARTIHlp
+o/wAp3X8aiEOPJcTFRlTElihtYSq5POgqHXqxbpek5H5CyALUvT76rCvcsDspQ3A
+dZEbAoIBAQCoLEmP5o8Rev/UdEgECB/uwWJIngYsLp3TAv/SrMRvkiL1X3JTD/+m
+L9/eXVBDjPoR/khPCcg2h77ex2qhaTrL8wnKAG6CkvYQYb3impTnPIRmLT9nDxrX
+2gY78wQrNUCXTRvlH1rcx90KLb+DH9S95ig+tdf/otRYwl27XU5GYQtJfcXuvZth
+IiWku8btjpiCh909WHpsV81yY+faI08j9d8U8WQzRYMbEMpzsyrhBO/rxBCDfDNl
+7R1W8JooYRb9KAs/bVqXZNBROW2a72RjOp6zMfdRLVHLrPC7AE32MNaFk/khfesD
+T5OwgdcxeP6oxo2hDcw5fwHXBlo2fTCpAoIBAQChgjv5AfQ50spqvHy6MNem4tV0
+L0IsxmNLsi8X2a6s4kStwUzOxDA8c/e54XabxQNZ0ERU1q+bgbG7PWC4twDMPR8i
+2DO6rgqSK4MjGOTgAoeDuy3mElFQmCLRs04Wf4jh8kPi217WFlYBynh2HmBKbh42
+JmIrLetbKEK13FXRvMkgZcX4OIDrT5TOvev4VZArU8PTRlWv3sqsKAVXjX0clGHf
+I0/2kSsr2qq1UY7JrYWZsZ9uqz2ZH0pF19a6O/Cq4uqTYoL+sYzFTSeFmChRjV1g
+ancTvTn9lcBqECDMgq5DE/p96Oxg/t8elalR6WDUlysafphVz3nTuyMTh7ka
+-----END RSA PRIVATE KEY-----
diff --git a/apex/appsearch/com.android.appsearch.pk8 b/apex/appsearch/com.android.appsearch.pk8
new file mode 100644
index 000000000000..77e98b20877b
--- /dev/null
+++ b/apex/appsearch/com.android.appsearch.pk8
Binary files differ
diff --git a/apex/appsearch/com.android.appsearch.x509.pem b/apex/appsearch/com.android.appsearch.x509.pem
new file mode 100644
index 000000000000..e37c4b9fcead
--- /dev/null
+++ b/apex/appsearch/com.android.appsearch.x509.pem
@@ -0,0 +1,35 @@
+-----BEGIN CERTIFICATE-----
+MIIGETCCA/mgAwIBAgIUGl+MIvpEi0+TWzj0ieh6WtjXmP8wDQYJKoZIhvcNAQEL
+BQAwgZYxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQH
+DA1Nb3VudGFpbiBWaWV3MRAwDgYDVQQKDAdBbmRyb2lkMRAwDgYDVQQLDAdBbmRy
+b2lkMRIwEAYDVQQDDAlhcHBzZWFyY2gxIjAgBgkqhkiG9w0BCQEWE2FuZHJvaWRA
+YW5kcm9pZC5jb20wIBcNMTkxMTIwMjMxNTM1WhgPNDc1NzEwMTYyMzE1MzVaMIGW
+MQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91
+bnRhaW4gVmlldzEQMA4GA1UECgwHQW5kcm9pZDEQMA4GA1UECwwHQW5kcm9pZDES
+MBAGA1UEAwwJYXBwc2VhcmNoMSIwIAYJKoZIhvcNAQkBFhNhbmRyb2lkQGFuZHJv
+aWQuY29tMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAsyPlp3q3P9Xg
+W1WhIwQiF9em9oqaGQ/3dbIxickAy591qcRbpHb4lDTZusRECfqlV215mV+lv5x4
+EhOnId3uPKBAJ/YDtL7zUW6TWL7to7zEnUqSIKTcoQzNF2EiCeGuRhrtgYvAD3HQ
+dwr4xrbSADbDArF04A49voLpsmq1fyNgl86VISiMRqoSLJnA6eghlduuOt+nf252
+6WgxDs/JrO/eK70q0+RwmWzVJ/tVr+36a65N4EHhfL4t2hdV0k0XFob7hBn7XWzC
+QrSR3jCvE3yAfAr3tq5c19/WWBA7V45nEHzXyAvBUHWubYvDi+vm/yzqU2rQwScC
+bzp4zK4CnhBHqb4gHoy0+kfFIwJ1A3GT2pl3ba/NsIYgliMtPQfkDV5PE5RTNcwH
+21ewH7vm2+spQv5Z/2TEV2lEHlp2vuAliyn2AT4u1ginr6vtBRFLmpPeziFcfB0y
+7h04GctZpX8odz+XI7aMDe47RNu9XyJX0vulntxmlDF76k8Z9DIXg02hY+yc/i7+
+2ztnj1eXL51p+HyhK5VbvJWbKkVaMQijlbuIMYNzMA6L0WHWRc2Cux9UDODMGoiC
+w09JpqudCS/95I/F1xaWJ/Kh3vKeQshHAz0hrL7v7wpjmfeXf6NGsWJGy+giCwZj
+ABtn9nFQoesgi7M1LeazD5Q/4v4AMaUCAwEAAaNTMFEwHQYDVR0OBBYEFJpHCy2Y
+3qaL6cLpE9fe53L61KEEMB8GA1UdIwQYMBaAFJpHCy2Y3qaL6cLpE9fe53L61KEE
+MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggIBAGDYAcOhbOYcDB2K
+WDZka+FCORFFvz4nLQGE7Z9TAn1g7XusM2KbXlb2drIN6CWOFlnKQrUsNsAHrc+s
+tl+A1vC3/NfYKKBVuizPx/kHUgz3k/UIJzbzEu/uCJd86idcJoUTqC/qEJAeeQqM
+XpsNP1Yg7oyzZT8sFlUAKeDeXJ7fIDXR6nduUQ6uJXkee/5JF3VedHdgHAUsC19/
+KHhyVU3MLDUNBdAmM79+DsdVYi2Pw31jojMu95Zz1MYTRBcgQAiEw5nncr38k6ac
+Gy+JffgJR68FzI4QLBSxnDRFD2zXJ09lpP6Sjb1FVcDzk7Bi/EQDLBkrkbeLsk5F
+a0xz9VoJ3kM7Cc4R9MXN4ZWuePjdJwgasnHmllsXn45R9odgJgmfzuUwtgNw/XKQ
+QcQl7Q9QUrBCqIoHijxscUZCBSmIHVNBBDckRAmSXHeWMRlO3uBR4IA/Jfrt//4f
+uc7CNUp+LQ6EzBXJOVFrXRtau6Oj+jM1+fzxKo1uV2+T+GdVEE5jeF/6nB3qna6h
+2NmyLqbqeqp2QxgzBWSGy8Ugs6zg4wItJBqOoRLKKFxTJu5OAzJ4fUA+g7WFXNhR
+kG56SJ863LZoORKHWE72oXYeIW98Tq0qKLH3NzH5L4tfX8DeBTq+APezHetH1ljA
+D0avPy62g0i643bbpwZgezBgRIKL
+-----END CERTIFICATE-----
diff --git a/apex/appsearch/service/Android.bp b/apex/appsearch/service/Android.bp
index 2cd7aa009c46..4ebafce84886 100644
--- a/apex/appsearch/service/Android.bp
+++ b/apex/appsearch/service/Android.bp
@@ -21,4 +21,7 @@ java_library {
"framework",
"services.core",
],
+ static_libs: [
+ "icing-java-proto-lite",
+ ]
}
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/impl/FakeIcing.java b/apex/appsearch/service/java/com/android/server/appsearch/impl/FakeIcing.java
new file mode 100644
index 000000000000..5ac922c4a9b6
--- /dev/null
+++ b/apex/appsearch/service/java/com/android/server/appsearch/impl/FakeIcing.java
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.appsearch.impl;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.SparseArray;
+
+import com.google.android.icing.proto.DocumentProto;
+import com.google.android.icing.proto.PropertyProto;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * Fake in-memory implementation of the Icing key-value store and reverse index.
+ * <p>
+ * Currently, only queries by single exact term are supported. There is no support for persistence,
+ * namespaces, i18n tokenization, or schema.
+ *
+ * @hide
+ */
+public class FakeIcing {
+ private final AtomicInteger mNextDocId = new AtomicInteger();
+ private final Map<String, Integer> mUriToDocIdMap = new ArrayMap<>();
+ /** Array of Documents where index into the array is the docId. */
+ private final SparseArray<DocumentProto> mDocStore = new SparseArray<>();
+ /** Map of term to posting-list (the set of DocIds containing that term). */
+ private final Map<String, Set<Integer>> mIndex = new ArrayMap<>();
+
+ /**
+ * Inserts a document into the index.
+ *
+ * @param document The document to insert.
+ */
+ public void put(@NonNull DocumentProto document) {
+ String uri = document.getUri();
+
+ // Update mDocIdMap
+ Integer docId = mUriToDocIdMap.get(uri);
+ if (docId != null) {
+ // Delete the old doc
+ mDocStore.remove(docId);
+ }
+
+ // Allocate a new docId
+ docId = mNextDocId.getAndIncrement();
+ mUriToDocIdMap.put(uri, docId);
+
+ // Update mDocStore
+ mDocStore.put(docId, document);
+
+ // Update mIndex
+ indexDocument(docId, document);
+ }
+
+ /**
+ * Retrieves a document from the index.
+ *
+ * @param uri The URI of the document to retrieve.
+ * @return The body of the document, or {@code null} if no such document exists.
+ */
+ @Nullable
+ public DocumentProto get(@NonNull String uri) {
+ Integer docId = mUriToDocIdMap.get(uri);
+ if (docId == null) {
+ return null;
+ }
+ return mDocStore.get(docId);
+ }
+
+ /**
+ * Returns documents containing the given term.
+ *
+ * @param term A single exact term to look up in the index.
+ * @return The matching documents, or an empty {@code List} if no documents match.
+ */
+ @NonNull
+ public List<DocumentProto> query(@NonNull String term) {
+ String normTerm = normalizeString(term);
+ Set<Integer> docIds = mIndex.get(normTerm);
+ if (docIds == null || docIds.isEmpty()) {
+ return Collections.emptyList();
+ }
+ List<DocumentProto> matches = new ArrayList<>(docIds.size());
+ for (int docId : docIds) {
+ DocumentProto document = mDocStore.get(docId);
+ if (document != null) {
+ matches.add(document);
+ }
+ }
+ return matches;
+ }
+
+ /**
+ * Deletes a document by its URI.
+ *
+ * @param uri The URI of the document to be deleted.
+ */
+ public void delete(@NonNull String uri) {
+ // Update mDocIdMap
+ Integer docId = mUriToDocIdMap.get(uri);
+ if (docId != null) {
+ // Delete the old doc
+ mDocStore.remove(docId);
+ mUriToDocIdMap.remove(uri);
+ }
+ }
+
+ private void indexDocument(int docId, DocumentProto document) {
+ for (PropertyProto property : document.getPropertiesList()) {
+ for (String stringValue : property.getStringValuesList()) {
+ String[] words = normalizeString(stringValue).split("\\s+");
+ for (String word : words) {
+ indexTerm(docId, word);
+ }
+ }
+ for (Long longValue : property.getInt64ValuesList()) {
+ indexTerm(docId, longValue.toString());
+ }
+ for (Double doubleValue : property.getDoubleValuesList()) {
+ indexTerm(docId, doubleValue.toString());
+ }
+ for (Boolean booleanValue : property.getBooleanValuesList()) {
+ indexTerm(docId, booleanValue.toString());
+ }
+ // Intentionally skipping bytes values
+ for (DocumentProto documentValue : property.getDocumentValuesList()) {
+ indexDocument(docId, documentValue);
+ }
+ }
+ }
+
+ private void indexTerm(int docId, String term) {
+ Set<Integer> postingList = mIndex.get(term);
+ if (postingList == null) {
+ postingList = new ArraySet<>();
+ mIndex.put(term, postingList);
+ }
+ postingList.add(docId);
+ }
+
+ /** Strips out punctuation and converts to lowercase. */
+ private static String normalizeString(String input) {
+ return input.replaceAll("\\p{P}", "").toLowerCase(Locale.getDefault());
+ }
+}
diff --git a/apex/jobscheduler/framework/java/android/app/job/JobSchedulerFrameworkInitializer.java b/apex/jobscheduler/framework/java/android/app/job/JobSchedulerFrameworkInitializer.java
index 3835d93ebeb9..0c4fcb4ec1b0 100644
--- a/apex/jobscheduler/framework/java/android/app/job/JobSchedulerFrameworkInitializer.java
+++ b/apex/jobscheduler/framework/java/android/app/job/JobSchedulerFrameworkInitializer.java
@@ -16,6 +16,7 @@
package android.app.job;
+import android.annotation.SystemApi;
import android.app.JobSchedulerImpl;
import android.app.SystemServiceRegistry;
import android.content.Context;
@@ -28,6 +29,7 @@ import android.os.PowerWhitelistManager;
*
* @hide
*/
+@SystemApi
public class JobSchedulerFrameworkInitializer {
private JobSchedulerFrameworkInitializer() {
}
@@ -38,8 +40,6 @@ public class JobSchedulerFrameworkInitializer {
* {@link Context#getSystemService} can return them.
*
* <p>If this is called from other places, it throws a {@link IllegalStateException).
- *
- * TODO Make it a system API
*/
public static void registerServiceWrappers() {
SystemServiceRegistry.registerStaticService(
diff --git a/apex/jobscheduler/framework/java/android/os/DeviceIdleManager.java b/apex/jobscheduler/framework/java/android/os/DeviceIdleManager.java
index 0568beb34e08..8019d4fdb870 100644
--- a/apex/jobscheduler/framework/java/android/os/DeviceIdleManager.java
+++ b/apex/jobscheduler/framework/java/android/os/DeviceIdleManager.java
@@ -44,6 +44,10 @@ public class DeviceIdleManager {
mService = service;
}
+ IDeviceIdleController getService() {
+ return mService;
+ }
+
/**
* @return package names the system has white-listed to opt out of power save restrictions,
* except for device idle mode.
diff --git a/apex/jobscheduler/framework/java/android/os/IDeviceIdleController.aidl b/apex/jobscheduler/framework/java/android/os/IDeviceIdleController.aidl
index 21ce5ccd3ccc..643d47ca5c6a 100644
--- a/apex/jobscheduler/framework/java/android/os/IDeviceIdleController.aidl
+++ b/apex/jobscheduler/framework/java/android/os/IDeviceIdleController.aidl
@@ -45,6 +45,7 @@ interface IDeviceIdleController {
void addPowerSaveTempWhitelistApp(String name, long duration, int userId, String reason);
long addPowerSaveTempWhitelistAppForMms(String name, int userId, String reason);
long addPowerSaveTempWhitelistAppForSms(String name, int userId, String reason);
+ long whitelistAppTemporarily(String name, int userId, String reason);
void exitIdle(String reason);
int setPreIdleTimeoutMode(int Mode);
void resetPreIdleTimeoutMode();
diff --git a/apex/jobscheduler/framework/java/android/os/PowerWhitelistManager.java b/apex/jobscheduler/framework/java/android/os/PowerWhitelistManager.java
index 06ed52d7f586..7a3ed92c1556 100644
--- a/apex/jobscheduler/framework/java/android/os/PowerWhitelistManager.java
+++ b/apex/jobscheduler/framework/java/android/os/PowerWhitelistManager.java
@@ -16,12 +16,17 @@
package android.os;
+import android.annotation.IntDef;
import android.annotation.NonNull;
+import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.annotation.TestApi;
import android.content.Context;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
/**
* Interface to access and modify the power save whitelist.
*
@@ -32,11 +37,91 @@ import android.content.Context;
@SystemService(Context.POWER_WHITELIST_MANAGER)
public class PowerWhitelistManager {
private final Context mContext;
+ // Proxy to DeviceIdleController for now
+ // TODO: migrate to PowerWhitelistController
+ private final IDeviceIdleController mService;
+
+ /**
+ * Indicates that an unforeseen event has occurred and the app should be whitelisted to handle
+ * it.
+ */
+ public static final int EVENT_UNSPECIFIED = 0;
+
+ /**
+ * Indicates that an SMS event has occurred and the app should be whitelisted to handle it.
+ */
+ public static final int EVENT_SMS = 1;
+
+ /**
+ * Indicates that an MMS event has occurred and the app should be whitelisted to handle it.
+ */
+ public static final int EVENT_MMS = 2;
+
+ /**
+ * @hide
+ */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = {"EVENT_"}, value = {
+ EVENT_UNSPECIFIED,
+ EVENT_SMS,
+ EVENT_MMS,
+ })
+ public @interface WhitelistEvent {
+ }
/**
* @hide
*/
public PowerWhitelistManager(@NonNull Context context) {
mContext = context;
+ mService = context.getSystemService(DeviceIdleManager.class).getService();
+ }
+
+ /**
+ * Add an app to the temporary whitelist for a short amount of time.
+ *
+ * @param packageName The package to add to the temp whitelist
+ * @param durationMs How long to keep the app on the temp whitelist for (in milliseconds)
+ */
+ @RequiresPermission(android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST)
+ public void whitelistAppTemporarily(@NonNull String packageName, long durationMs) {
+ String reason = "from:" + UserHandle.formatUid(Binder.getCallingUid());
+ try {
+ mService.addPowerSaveTempWhitelistApp(packageName, durationMs, mContext.getUserId(),
+ reason);
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Add an app to the temporary whitelist for a short amount of time for a specific reason.
+ *
+ * @param packageName The package to add to the temp whitelist
+ * @param event The reason to add the app to the temp whitelist
+ * @param reason A human-readable reason explaining why the app is temp whitelisted. Only used
+ * for logging purposes
+ * @return The duration (in milliseconds) that the app is whitelisted for
+ */
+ @RequiresPermission(android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST)
+ public long whitelistAppTemporarilyForEvent(@NonNull String packageName,
+ @WhitelistEvent int event, @NonNull String reason) {
+ try {
+ switch (event) {
+ case EVENT_MMS:
+ return mService.addPowerSaveTempWhitelistAppForMms(
+ packageName, mContext.getUserId(), reason);
+ case EVENT_SMS:
+ return mService.addPowerSaveTempWhitelistAppForSms(
+ packageName, mContext.getUserId(), reason);
+ case EVENT_UNSPECIFIED:
+ default:
+ return mService.whitelistAppTemporarily(
+ packageName, mContext.getUserId(), reason);
+ }
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ return 0;
+ }
}
}
diff --git a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
index dfe7a90ba246..701ea849c38f 100644
--- a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
+++ b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
@@ -1662,7 +1662,17 @@ public class DeviceIdleController extends SystemService
return isPowerSaveWhitelistAppInternal(name);
}
- @Override public void addPowerSaveTempWhitelistApp(String packageName, long duration,
+ @Override
+ public long whitelistAppTemporarily(String packageName, int userId, String reason)
+ throws RemoteException {
+ // At least 10 seconds.
+ long duration = Math.max(10_000L, mConstants.MAX_TEMP_APP_WHITELIST_DURATION / 2);
+ addPowerSaveTempWhitelistAppChecked(packageName, duration, userId, reason);
+ return duration;
+ }
+
+ @Override
+ public void addPowerSaveTempWhitelistApp(String packageName, long duration,
int userId, String reason) throws RemoteException {
addPowerSaveTempWhitelistAppChecked(packageName, duration, userId, reason);
}
diff --git a/apex/sdkext/Android.bp b/apex/sdkext/Android.bp
new file mode 100644
index 000000000000..b8dcb90057d2
--- /dev/null
+++ b/apex/sdkext/Android.bp
@@ -0,0 +1,32 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+apex {
+ name: "com.android.sdkext",
+ manifest: "manifest.json",
+ java_libs: [ "framework-sdkext" ],
+ key: "com.android.sdkext.key",
+ certificate: ":com.android.sdkext.certificate",
+}
+
+apex_key {
+ name: "com.android.sdkext.key",
+ public_key: "com.android.sdkext.avbpubkey",
+ private_key: "com.android.sdkext.pem",
+}
+
+android_app_certificate {
+ name: "com.android.sdkext.certificate",
+ certificate: "com.android.sdkext",
+}
diff --git a/apex/sdkext/OWNERS b/apex/sdkext/OWNERS
new file mode 100644
index 000000000000..feb274262bef
--- /dev/null
+++ b/apex/sdkext/OWNERS
@@ -0,0 +1 @@
+hansson@google.com
diff --git a/apex/sdkext/com.android.sdkext.avbpubkey b/apex/sdkext/com.android.sdkext.avbpubkey
new file mode 100644
index 000000000000..8f47741ed3b8
--- /dev/null
+++ b/apex/sdkext/com.android.sdkext.avbpubkey
Binary files differ
diff --git a/apex/sdkext/com.android.sdkext.pem b/apex/sdkext/com.android.sdkext.pem
new file mode 100644
index 000000000000..816460183aa3
--- /dev/null
+++ b/apex/sdkext/com.android.sdkext.pem
@@ -0,0 +1,51 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIJKQIBAAKCAgEAr72pTSavrziDP54AtQZlRclDxJf9HXRZwFRbYx9hWZ4z7ZtO
+pNBDPvPJCiAOVUsILgCQhBUolz2dyLob25Fd0PVp0n9ibIPEQYjTfHjOK40qb57N
+LhEp2ceGiAfsywPSi0TH1PQ6JgbCe/RM4TefI/sj3gYJPka3ksMvylhMIgUVLgME
+kYizhzwHqlLMspB858SioREZdGwcdZrMMIajGFU69Q9ZRDBzhPvxyKhYoObcOtk1
+uVaiE/fNoi3wKGJz2l2vhUuNrQW7MWlVMag+Qes4YACUTk9LZrOVFEJFjWc8xGUi
+ABtfKGs5JgNr/sWnhvifLn8lJuf0/BJmjD+L5QwXYs2cS7gcZJtTM12J94r0Twgw
+wF2lNmIxAE9sYqj5Rh3dIlTPE5vMUECmQEGjIBB/hzT65VxVqSjU/IlS506JTg3p
+IOQtZ15cUzTBpda4jrvqcq6RNVvgBCu2bV5D8Z4z9FUlPyvD+Zq/6lcoJfLtznAs
+G2463hyPAHTGBIcZ5p5bTuGxoAb6ivyqo4b9Qi4yYA6je9HJmuy8T3Mn5JROoeu9
+BH1K54r/mpT4TQPwuKUvRRtBAV2OPHjo+zp0Gd4Y6rxDYxEIdfEae7pQr/QExSPB
+q/QCr9RhixR1mO373LHuja+MxdAxIxugb2HTS61PQo+PbYrhJMcVuxTwJOECAwEA
+AQKCAgAH7ToRrMkH0ji5SdsmTx+KQkW4PFLCXVke/68PjX7KmAQnl3W4oVwnHr/W
+oROEbVn1GTlre7jU+YaAY0SWZrwgjLE1OWGrG1ZizlUbrCdAd6GOX09J4KROml1L
+DXB0x7tbZMLOrCVjSbLD/ITrM6MN8Gnxvbv0/yOQjxU8vzbP4gLOjHxMRCo001RV
+Ll7lPvcjTQ84zJilU6sE8vJ6zdfVZSK/ou2X0cekG+kP7+fvefo8/UcbEPlGhUrV
+IdVPPQGUu90K2hmN0FBdLi8Vik0klAN68Qu/bHwuKbNzsnmIoztucFFUR+fG3u84
+87aPS0L/J3+mjT2Tv6qhJANUGBmrK/h7MkelpKXlRTCITJLX9xP7hfSbJ4f6aLVq
+ZYPPciGxSBbUDgAwvPtOlMDzccg7YsYyiBBO28wh8MN97rePmc0z6nGmjeXhcbCC
+QktG50VYFCyqp5muKgqQmRfRjHFHLWs8GEqgxMeEL3U3HjYfCYr+6E8Sr5OnOBeH
+3buCi1+zgnNYCvbamgY/OJmW7f9h5O31hxmTplc2E1ZuxUGQZthabt1rN3bmNkyf
+KUmPwnIYkDkWBSV5lzyQExfS3/EVvj0EnHhx8faamimNrGo8xCcfnLT3c0WEFVmo
+yIyVRX3EpXJFM2JkeJ21/IEZXTzHSoNxk12CBG8i8lLSflWSMQKCAQEA2ZqVnOuV
+SZfLCUYUUh8Hvhc5zONstfq7ma1Zsttsdaj9t68nLRiBDvLOGnMjDkYZzoSd4fyl
+oy+YqWGBqcqa5kg1NOCH0I46p9d8RcWAfDnB4sqbLgWh70qsvni6igRijmsMDvkA
+U9HeEdPaLCjQ4UXw7GQvN5rRxuRt+OSqV3tV/Pk9JYyYjz7faC8dmbKDrWHHuOvm
+/9y6Xy+L5IgftykNlUeddSCIoMOAadM7BiRjsrHnOYBQ8xBcn0OYafpIswItrgVi
+IrsPJaBFidx8QYK4MVibyka6U0cm28OocDSPtSk/4jrnCEEhLjFUnWwuMXuBGlrd
+W7wP/muoJqb1VwKCAQEAzsAT90kkOCvAcrfGRE3KkUjwWAsQyP8u2+27JIQPqrpW
+GfWAzJXFt80TSp0Zf/Lrq3/SQ9n4AaL4K9dcMoreedoQN9C9JI7zPtZAWNrJVUcV
+dq2gZjBQ78+oK7uQgvFNWxga5D+Nh+Y+9Tp537fc5HIh0Y13PgsxxPk2OnZJTvLX
+HM5H7Aua9ssmqChsrKihuUsDSPozfBz+H7FNHEdKMqVLqJJSK6m0uMxuLovdVfka
+5S7iBMjEGZc46Iz3ckE0pdOiQLooNqfEQqFe5Uou/KZxxKI1NW25rEEBTVyQWt+2
+BNUCfKP7noZ45u5sUY3eJrgI7BrPEDbNS81WYaLchwKCAQA8Q4mHyd6wYO+EA/qA
+u8NDK9+AFMP4qhXme5HJ7Obetwx9IG7zGEQ1xZy6yoQ84cEn5qZq/bNJvFbFIhHs
+2gWIHRtPJ5e1dI5eCVmLYSUyQjSmAIJ1fm3YfY/VuE3BB3HcC11tkBw9GnQr78YO
+UMd4fAw7C4vgFGpgcMbcFUfvrmKkCsqaaZOeqETq75F9DWlWTSwo1HxHA/RBhENz
+6RcPfLkcTJcY5wevrjUUGcHQ86cAyDBHRngkuLVODkRZpU0Y9lN8TFVfVPre6sIX
+ag6nffJRCD8tB+V2RtBGMKunV4ctHt1oY/Oz34W260aJynoIjjG1ANEpJK4xQdNx
+0O9FAoIBAQCz2AGGKemHswdEwveEkuaSWpA3Bekj7lYkmTchHH9EU7JyAkx3qhDD
+QXB2hxGXawf1tsqAmypQwiJ+gGeCz6mW9UkGRF1DX9XX4yc2I5rew2a4RXAxc/Xz
+pP70i8O5I43Wn7FEusOyY2aAis1Y/eb4EQ+56QTAw5wXa3DwidRbCIJ2XDnT6oRy
+CWUnAYMG7ek/9TB2Wq5OWCn2B5S79IdmZsLZb+5qbMT3u1xcwO1Xy8jJc27IGpv6
+ZsDqCTV1/aJ+XQnWpBg28tiV3Sle6pjUzTRJh5AhWcEZRbKMSOiJI/CBY4k2Qq6t
+xuuEdgFjL7T+mTepqehUglcyiPuLEtAhAoIBAQDDQ5pTFOlunfYzm+CIvvImAgy7
+vrEabJYABATytAbXRMMbrKoEdU2ApEDyEW7PgysDnYLAZ+icObnJlBTYvNdlWFly
+XiviGVfpjFWDT9U/gUwFQu2lfEjoiivoGS92USHUy4UMVHiiznnm20VLLkgd3xna
+HUNSDdHIEgzOTmDsKJwMfA9zGckx23JJimPR5ekv6vr6QllYtECs4lTC1gVQAp2f
+5daxHRbkmO6gw1RgQADLkAnYz3aI1jNuHm5VyAZGt/d3JCtZ3Wwwejll8uJ4J09G
+oEtqyY9RVeHK50bLO4lyAXFiE+J6qqXjsGC20cpxeZYW5llMY/dhA6WV4YXV
+-----END RSA PRIVATE KEY-----
diff --git a/apex/sdkext/com.android.sdkext.pk8 b/apex/sdkext/com.android.sdkext.pk8
new file mode 100644
index 000000000000..ccc0bf438cd1
--- /dev/null
+++ b/apex/sdkext/com.android.sdkext.pk8
Binary files differ
diff --git a/apex/sdkext/com.android.sdkext.x509.pem b/apex/sdkext/com.android.sdkext.x509.pem
new file mode 100644
index 000000000000..45d2ade354d4
--- /dev/null
+++ b/apex/sdkext/com.android.sdkext.x509.pem
@@ -0,0 +1,35 @@
+-----BEGIN CERTIFICATE-----
+MIIGIzCCBAugAwIBAgIUXuDL7QvzQh7S6rihWz2KRvCFVT0wDQYJKoZIhvcNAQEL
+BQAwgZ8xCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQH
+DA1Nb3VudGFpbiBWaWV3MRAwDgYDVQQKDAdBbmRyb2lkMRAwDgYDVQQLDAdBbmRy
+b2lkMRswGQYDVQQDDBJjb20uYW5kcm9pZC5zZGtleHQxIjAgBgkqhkiG9w0BCQEW
+E2FuZHJvaWRAYW5kcm9pZC5jb20wIBcNMTkxMjAyMTQyNDM0WhgPNDc1NzEwMjgx
+NDI0MzRaMIGfMQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQG
+A1UEBwwNTW91bnRhaW4gVmlldzEQMA4GA1UECgwHQW5kcm9pZDEQMA4GA1UECwwH
+QW5kcm9pZDEbMBkGA1UEAwwSY29tLmFuZHJvaWQuc2RrZXh0MSIwIAYJKoZIhvcN
+AQkBFhNhbmRyb2lkQGFuZHJvaWQuY29tMIICIjANBgkqhkiG9w0BAQEFAAOCAg8A
+MIICCgKCAgEAxFvZZ6ES1oqAu1K74/ZxnC3SOhHnLISLBgJEe7DqtdpuNFAwvdVO
+RL/HULhDbjYlOhpU2x3SavDIZZ2lRfiS9Q+M25WftxTRHVjBcpgwbV77TVxPKlAa
+tVN2lUVOY+s4QAVMNIXjC4kCKK/pCQtacH715EtdV47fWdg/Nx4iP/Aord8k3KGI
+9iI2ZOUjaugTRxu5lKRNDrv0bw5rEzyYmDyMud+kR/iS3/5oog57wPE0ffAkZXWE
+p3L2Cejre3ekCizsvVh6EmH6ForKLtL6f0z5Zir1f4R9+YcENspTlJR3pDhg7y3I
+uTQT/iDCtV0l+g2PjGZPEeAQHND3+kDQR7Sno/WC1Nhws6vcu1MdrC+kIh1ewx4y
+8moy/yqb5M98PJDzTSi/AOTB/OiqLXo/T8rjLBmirs9y3fTT6gJ6qXxOWgt8dle9
+7TBfa84Xi8uVY61c+A+YI0nLal7QDPsP3RPv5sJSQ9x9YnweVfD9Q0EOi52sSNu+
+QuN/kcUrMgPgha20VhfH/CkkPDyIp6aZyHHM69MIl+cYEm8vPa5uy3dosuRomT0f
+I4HOBjULDIuj+rIi+Rg3qHvmpuejwZXI/FBNWIhLEUG3ytgksjMaBoYAYflGdrcj
+BQexuF3EO+j4uo7JGjNcaT7wRoCH9gt29VHckDg2qz6VWXrlpmME4UkCAwEAAaNT
+MFEwHQYDVR0OBBYEFISN2nmUHllgPZMZ62U7mU3ZxzlXMB8GA1UdIwQYMBaAFISN
+2nmUHllgPZMZ62U7mU3ZxzlXMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEL
+BQADggIBAFHIwyBNIVyHXUsDUdcjxfojXQsF/BCL9ehE3pgdkvDfQanaIREWn0nc
+oCFDFkYMRqaXOGC5TKq4OCjXOLsdfODt8HQ3F9J1B0ghQ5tfOdw7xDugNAszqP/Q
+h7kpvqLTycjrqOeZ5KjxEEYtP/KlUmALgOKcTcSH+XhWyxhjF4j24T9F2yJRr3/A
+r1NGU/djH953bHKC8OpJ2teUpDLA4TxVp/EhslH2eVigF80c/w74QPLEWkD9zv/4
+YeRg/R5N83zHs99NtlWMIeHfK6fUbzMyaSZtvm+jK20tkByQb/OQRed+drk25MtL
+68IRvxqri367qRScdpTZbu0ByLO4X8gFdubRUWr+tcO4pZX+DJRVriExbOkU2xhS
+Vtslq23V/hwTuUNm1CXjR70mPS13BTmHrIQDqLoIw/WTQlGh+vxnlAFRIHM3KB2c
+OdzUBu+NcB4aZEd0KKtct600A0DKPr1MQPb5jDq9wEtPSQYwMF0nRFNnXltbrXMd
+4hhwnhKr74fVMUmb+7eQP56XE/Nk4D+npMO54vv1pav+DI2/nxCND9BOLBweY38p
+Tvd2RjesMok0zXuVXiCIu4GEpwo7WkSnv25xrb0Ey2M8QWnGNnCcX7Kv6ip3RdWy
+HiN0G8RJrs/yNEVSDRx8ZhtwTpXVPQxbARbmhNF4/fnolElkmrMP
+-----END CERTIFICATE-----
diff --git a/apex/sdkext/framework/Android.bp b/apex/sdkext/framework/Android.bp
new file mode 100644
index 000000000000..b17f0f84d6fa
--- /dev/null
+++ b/apex/sdkext/framework/Android.bp
@@ -0,0 +1,30 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+filegroup {
+ name: "framework-sdkext-sources",
+ srcs: [
+ "java/**/*.java",
+ ],
+ path: "java",
+}
+
+java_library {
+ name: "framework-sdkext",
+ srcs: [ ":framework-sdkext-sources" ],
+ sdk_version: "system_current",
+ libs: [ "framework-annotations-lib" ],
+ permitted_packages: [ "android.os.ext" ],
+ installable: true,
+}
diff --git a/apex/sdkext/framework/java/android/os/ext/SdkExtensions.java b/apex/sdkext/framework/java/android/os/ext/SdkExtensions.java
new file mode 100644
index 000000000000..c039a820fc04
--- /dev/null
+++ b/apex/sdkext/framework/java/android/os/ext/SdkExtensions.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os.ext;
+
+import android.annotation.IntDef;
+import android.os.Build.VERSION_CODES;
+import android.os.SystemProperties;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/** @hide */
+public class SdkExtensions {
+
+ private static final int R_EXTENSION_INT;
+ static {
+ R_EXTENSION_INT = SystemProperties.getInt("persist.com.android.sdkext.sdk_info", 0);
+ }
+
+ /** Values suitable as parameters for {@link #getExtensionVersion(int)}. */
+ @IntDef(value = { VERSION_CODES.R })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface SdkVersion {}
+
+ /**
+ * Return the version of the extension to the given SDK.
+ *
+ * @param sdk the SDK version to get the extension version of.
+ * @see SdkVersion
+ * @throws IllegalArgumentException if sdk is not an sdk version with extensions
+ */
+ public static int getExtensionVersion(@SdkVersion int sdk) {
+ if (sdk < VERSION_CODES.R) {
+ throw new IllegalArgumentException();
+ }
+ return R_EXTENSION_INT;
+ }
+
+}
diff --git a/apex/sdkext/framework/java/android/os/ext/package.html b/apex/sdkext/framework/java/android/os/ext/package.html
new file mode 100644
index 000000000000..34c1697c01fd
--- /dev/null
+++ b/apex/sdkext/framework/java/android/os/ext/package.html
@@ -0,0 +1,5 @@
+<HTML>
+<BODY>
+Provides APIs to interface with the SDK extensions.
+</BODY>
+</HTML>
diff --git a/apex/sdkext/framework/tests/Android.bp b/apex/sdkext/framework/tests/Android.bp
new file mode 100644
index 000000000000..3d5dbb3d8a2d
--- /dev/null
+++ b/apex/sdkext/framework/tests/Android.bp
@@ -0,0 +1,10 @@
+android_test {
+ name: "framework-sdkext-tests",
+ srcs: ["src/**/*.java"],
+ libs: [
+ "android.test.base",
+ "android.test.runner",
+ ],
+ static_libs: [ "framework-sdkext" ],
+ platform_apis: true,
+}
diff --git a/apex/sdkext/framework/tests/AndroidManifest.xml b/apex/sdkext/framework/tests/AndroidManifest.xml
new file mode 100644
index 000000000000..831f1328c006
--- /dev/null
+++ b/apex/sdkext/framework/tests/AndroidManifest.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.sdkext.tests">
+
+ <application>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation android:name="android.test.InstrumentationTestRunner"
+ android:targetPackage="com.android.sdkext.tests" />
+
+</manifest>
diff --git a/apex/sdkext/framework/tests/src/android/os/ext/SdkExtensionsTest.java b/apex/sdkext/framework/tests/src/android/os/ext/SdkExtensionsTest.java
new file mode 100644
index 000000000000..688511096a43
--- /dev/null
+++ b/apex/sdkext/framework/tests/src/android/os/ext/SdkExtensionsTest.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os.ext;
+
+import android.os.Build;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import junit.framework.TestCase;
+
+public class SdkExtensionsTest extends TestCase {
+
+ @SmallTest
+ public void testBadArgument() throws Exception {
+ try {
+ SdkExtensions.getExtensionVersion(Build.VERSION_CODES.Q);
+ fail("expected IllegalArgumentException");
+ } catch (IllegalArgumentException expected) { }
+
+ try {
+ SdkExtensions.getExtensionVersion(999999);
+ fail("expected IllegalArgumentException");
+ } catch (IllegalArgumentException expected) { }
+ }
+
+ @SmallTest
+ public void testDefault() throws Exception {
+ int r = SdkExtensions.getExtensionVersion(Build.VERSION_CODES.R);
+ assertTrue(r >= 0);
+ }
+
+}
diff --git a/apex/sdkext/manifest.json b/apex/sdkext/manifest.json
new file mode 100644
index 000000000000..048f5c4f177b
--- /dev/null
+++ b/apex/sdkext/manifest.json
@@ -0,0 +1,4 @@
+{
+ "name": "com.android.sdkext",
+ "version": 1
+}
diff --git a/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java b/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java
index a6cc06fad7eb..62c77ef20871 100644
--- a/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java
+++ b/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java
@@ -18,6 +18,7 @@ package com.android.server.stats;
import static android.app.AppOpsManager.OP_FLAGS_ALL_TRUSTED;
import static android.content.pm.PackageInfo.REQUESTED_PERMISSION_GRANTED;
import static android.content.pm.PermissionInfo.PROTECTION_DANGEROUS;
+import static android.os.Process.THREAD_PRIORITY_BACKGROUND;
import static android.os.Process.getUidForPid;
import static android.os.storage.VolumeInfo.TYPE_PRIVATE;
import static android.os.storage.VolumeInfo.TYPE_PUBLIC;
@@ -115,7 +116,6 @@ import android.util.proto.ProtoStream;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.app.procstats.IProcessStats;
import com.android.internal.app.procstats.ProcessStats;
-import com.android.internal.os.BackgroundThread;
import com.android.internal.os.BatterySipper;
import com.android.internal.os.BatteryStatsHelper;
import com.android.internal.os.BinderCallsStats.ExportedCallStat;
@@ -535,7 +535,7 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
// Assumes that sStatsdLock is held.
@GuardedBy("sStatsdLock")
- private final void informAllUidsLocked(Context context) throws RemoteException {
+ private void informAllUidsLocked(Context context) throws RemoteException {
UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE);
PackageManager pm = context.getPackageManager();
final List<UserInfo> users = um.getUsers(true);
@@ -557,7 +557,11 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
Slog.e(TAG, "Failed to close the read side of the pipe.", e);
}
final ParcelFileDescriptor writeFd = fds[1];
- BackgroundThread.getHandler().post(() -> {
+ HandlerThread backgroundThread = new HandlerThread(
+ "statsCompanionService.bg", THREAD_PRIORITY_BACKGROUND);
+ backgroundThread.start();
+ Handler handler = new Handler(backgroundThread.getLooper());
+ handler.post(() -> {
FileOutputStream fout = new ParcelFileDescriptor.AutoCloseOutputStream(writeFd);
try {
ProtoOutputStream output = new ProtoOutputStream(fout);
@@ -565,7 +569,8 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
// Add in all the apps for every user/profile.
for (UserInfo profile : users) {
List<PackageInfo> pi =
- pm.getInstalledPackagesAsUser(PackageManager.MATCH_KNOWN_PACKAGES,
+ pm.getInstalledPackagesAsUser(PackageManager.MATCH_UNINSTALLED_PACKAGES
+ | PackageManager.MATCH_ANY_USER,
profile.id);
for (int j = 0; j < pi.size(); j++) {
if (pi.get(j).applicationInfo != null) {
@@ -606,6 +611,8 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
}
} finally {
IoUtils.closeQuietly(fout);
+ backgroundThread.quit();
+ backgroundThread.interrupt();
}
});
}
@@ -2736,23 +2743,20 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
filter.addAction(Intent.ACTION_PACKAGE_ADDED);
filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
filter.addDataScheme("package");
- mContext.registerReceiverAsUser(mAppUpdateReceiver, UserHandle.ALL, filter,
- null,
- null);
+ mContext.registerReceiverForAllUsers(mAppUpdateReceiver, filter, null, null);
// Setup receiver for user initialize (which happens once for a new user)
// and
// if a user is removed.
filter = new IntentFilter(Intent.ACTION_USER_INITIALIZE);
filter.addAction(Intent.ACTION_USER_REMOVED);
- mContext.registerReceiverAsUser(mUserUpdateReceiver, UserHandle.ALL,
- filter, null, null);
+ mContext.registerReceiverForAllUsers(mUserUpdateReceiver, filter, null, null);
// Setup receiver for device reboots or shutdowns.
filter = new IntentFilter(Intent.ACTION_REBOOT);
filter.addAction(Intent.ACTION_SHUTDOWN);
- mContext.registerReceiverAsUser(
- mShutdownEventReceiver, UserHandle.ALL, filter, null, null);
+ mContext.registerReceiverForAllUsers(
+ mShutdownEventReceiver, filter, null, null);
final long token = Binder.clearCallingIdentity();
try {
// Pull the latest state of UID->app name, version mapping when
diff --git a/api/current.txt b/api/current.txt
index f1c03a4e576d..b1eac5947c7a 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -9899,6 +9899,7 @@ package android.content {
method public abstract void sendOrderedBroadcast(@RequiresPermission android.content.Intent, @Nullable String);
method public abstract void sendOrderedBroadcast(@NonNull @RequiresPermission android.content.Intent, @Nullable String, @Nullable android.content.BroadcastReceiver, @Nullable android.os.Handler, int, @Nullable String, @Nullable android.os.Bundle);
method public void sendOrderedBroadcast(@NonNull android.content.Intent, @Nullable String, @Nullable String, @Nullable android.content.BroadcastReceiver, @Nullable android.os.Handler, int, @Nullable String, @Nullable android.os.Bundle);
+ method public void sendOrderedBroadcast(@NonNull @RequiresPermission android.content.Intent, @Nullable String, @Nullable String, @Nullable android.os.Bundle, @Nullable android.content.BroadcastReceiver, @Nullable android.os.Handler, int, @Nullable String, @Nullable android.os.Bundle);
method @RequiresPermission("android.permission.INTERACT_ACROSS_USERS") public abstract void sendOrderedBroadcastAsUser(@RequiresPermission android.content.Intent, android.os.UserHandle, @Nullable String, android.content.BroadcastReceiver, @Nullable android.os.Handler, int, @Nullable String, @Nullable android.os.Bundle);
method @Deprecated @RequiresPermission(android.Manifest.permission.BROADCAST_STICKY) public abstract void sendStickyBroadcast(@RequiresPermission android.content.Intent);
method @Deprecated @RequiresPermission(allOf={"android.permission.INTERACT_ACROSS_USERS", android.Manifest.permission.BROADCAST_STICKY}) public abstract void sendStickyBroadcastAsUser(@RequiresPermission android.content.Intent, android.os.UserHandle);
@@ -23063,6 +23064,7 @@ package android.location {
public final class GnssStatus {
method @FloatRange(from=0, to=360) public float getAzimuthDegrees(@IntRange(from=0) int);
+ method @FloatRange(from=0, to=63) public float getBasebandCn0DbHz(@IntRange(from=0) int);
method @FloatRange(from=0) public float getCarrierFrequencyHz(@IntRange(from=0) int);
method @FloatRange(from=0, to=63) public float getCn0DbHz(@IntRange(from=0) int);
method public int getConstellationType(@IntRange(from=0) int);
@@ -23070,6 +23072,7 @@ package android.location {
method @IntRange(from=0) public int getSatelliteCount();
method @IntRange(from=1, to=200) public int getSvid(@IntRange(from=0) int);
method public boolean hasAlmanacData(@IntRange(from=0) int);
+ method public boolean hasBasebandCn0DbHz(@IntRange(from=0) int);
method public boolean hasCarrierFrequencyHz(@IntRange(from=0) int);
method public boolean hasEphemerisData(@IntRange(from=0) int);
method public boolean usedInFix(@IntRange(from=0) int);
@@ -23085,7 +23088,7 @@ package android.location {
public static final class GnssStatus.Builder {
ctor public GnssStatus.Builder();
- method @NonNull public android.location.GnssStatus.Builder addSatellite(int, @IntRange(from=1, to=200) int, @FloatRange(from=0, to=63) float, @FloatRange(from=0xffffffa6, to=90) float, @FloatRange(from=0, to=360) float, boolean, boolean, boolean, boolean, @FloatRange(from=0) float);
+ method @NonNull public android.location.GnssStatus.Builder addSatellite(int, @IntRange(from=1, to=200) int, @FloatRange(from=0, to=63) float, @FloatRange(from=0xffffffa6, to=90) float, @FloatRange(from=0, to=360) float, boolean, boolean, boolean, boolean, @FloatRange(from=0) float, boolean, @FloatRange(from=0, to=63) float);
method @NonNull public android.location.GnssStatus build();
method @NonNull public android.location.GnssStatus.Builder clearSatellites();
}
@@ -28925,6 +28928,7 @@ package android.net {
method @Nullable public String getInterfaceName();
method @NonNull public java.util.List<android.net.LinkAddress> getLinkAddresses();
method public int getMtu();
+ method @Nullable public android.net.IpPrefix getNat64Prefix();
method @Nullable public String getPrivateDnsServerName();
method @NonNull public java.util.List<android.net.RouteInfo> getRoutes();
method public boolean isPrivateDnsActive();
@@ -28935,6 +28939,7 @@ package android.net {
method public void setInterfaceName(@Nullable String);
method public void setLinkAddresses(@NonNull java.util.Collection<android.net.LinkAddress>);
method public void setMtu(int);
+ method public void setNat64Prefix(@Nullable android.net.IpPrefix);
method public void writeToParcel(android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.net.LinkProperties> CREATOR;
}
@@ -29889,6 +29894,7 @@ package android.net.wifi {
ctor @Deprecated public WifiConfiguration();
method public int describeContents();
method @Deprecated public android.net.ProxyInfo getHttpProxy();
+ method @Deprecated @NonNull public String getKey();
method @Deprecated @NonNull public android.net.MacAddress getRandomizedMacAddress();
method @Deprecated public boolean isPasspoint();
method @Deprecated public void setHttpProxy(android.net.ProxyInfo);
@@ -30243,6 +30249,7 @@ package android.net.wifi {
method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setIsEnhancedOpen(boolean);
method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setIsHiddenSsid(boolean);
method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setIsMetered(boolean);
+ method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setIsUserAllowedToManuallyConnect(boolean);
method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setIsUserInteractionRequired(boolean);
method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setPasspointConfig(@NonNull android.net.wifi.hotspot2.PasspointConfiguration);
method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setPriority(@IntRange(from=0) int);
@@ -30564,6 +30571,7 @@ package android.net.wifi.p2p {
method @Nullable public android.net.wifi.p2p.WifiP2pWfdInfo getWfdInfo();
method public boolean isGroupOwner();
method public boolean isServiceDiscoveryCapable();
+ method public void update(@NonNull android.net.wifi.p2p.WifiP2pDevice);
method public boolean wpsDisplaySupported();
method public boolean wpsKeypadSupported();
method public boolean wpsPbcSupported();
@@ -41525,6 +41533,7 @@ package android.service.autofill {
field public static final int FLAG_DONT_SAVE_ON_FINISH = 2; // 0x2
field public static final int FLAG_SAVE_ON_ALL_VIEWS_INVISIBLE = 1; // 0x1
field public static final int NEGATIVE_BUTTON_STYLE_CANCEL = 0; // 0x0
+ field public static final int NEGATIVE_BUTTON_STYLE_NEVER = 2; // 0x2
field public static final int NEGATIVE_BUTTON_STYLE_REJECT = 1; // 0x1
field public static final int POSITIVE_BUTTON_STYLE_CONTINUE = 1; // 0x1
field public static final int POSITIVE_BUTTON_STYLE_SAVE = 0; // 0x0
@@ -52497,6 +52506,9 @@ package android.view {
package android.view.accessibility {
public final class AccessibilityEvent extends android.view.accessibility.AccessibilityRecord implements android.os.Parcelable {
+ ctor public AccessibilityEvent();
+ ctor public AccessibilityEvent(int);
+ ctor public AccessibilityEvent(@NonNull android.view.accessibility.AccessibilityEvent);
method public void appendRecord(android.view.accessibility.AccessibilityRecord);
method public int describeContents();
method public static String eventTypeToString(int);
@@ -52607,6 +52619,10 @@ package android.view.accessibility {
}
public class AccessibilityNodeInfo implements android.os.Parcelable {
+ ctor public AccessibilityNodeInfo();
+ ctor public AccessibilityNodeInfo(@NonNull android.view.View);
+ ctor public AccessibilityNodeInfo(@NonNull android.view.View, int);
+ ctor public AccessibilityNodeInfo(@NonNull android.view.accessibility.AccessibilityNodeInfo);
method public void addAction(android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction);
method @Deprecated public void addAction(int);
method public void addChild(android.view.View);
@@ -52840,6 +52856,8 @@ package android.view.accessibility {
}
public static final class AccessibilityNodeInfo.CollectionInfo {
+ ctor public AccessibilityNodeInfo.CollectionInfo(int, int, boolean);
+ ctor public AccessibilityNodeInfo.CollectionInfo(int, int, boolean, int);
method public int getColumnCount();
method public int getRowCount();
method public int getSelectionMode();
@@ -52852,6 +52870,8 @@ package android.view.accessibility {
}
public static final class AccessibilityNodeInfo.CollectionItemInfo {
+ ctor public AccessibilityNodeInfo.CollectionItemInfo(int, int, int, int, boolean);
+ ctor public AccessibilityNodeInfo.CollectionItemInfo(int, int, int, int, boolean, boolean);
method public int getColumnIndex();
method public int getColumnSpan();
method public int getRowIndex();
@@ -52863,6 +52883,7 @@ package android.view.accessibility {
}
public static final class AccessibilityNodeInfo.RangeInfo {
+ ctor public AccessibilityNodeInfo.RangeInfo(int, float, float, float);
method public float getCurrent();
method public float getMax();
method public float getMin();
@@ -52894,6 +52915,8 @@ package android.view.accessibility {
}
public class AccessibilityRecord {
+ ctor public AccessibilityRecord();
+ ctor public AccessibilityRecord(@NonNull android.view.accessibility.AccessibilityRecord);
method public int getAddedCount();
method public CharSequence getBeforeText();
method public CharSequence getClassName();
@@ -52954,6 +52977,8 @@ package android.view.accessibility {
}
public final class AccessibilityWindowInfo implements android.os.Parcelable {
+ ctor public AccessibilityWindowInfo();
+ ctor public AccessibilityWindowInfo(@NonNull android.view.accessibility.AccessibilityWindowInfo);
method public int describeContents();
method public android.view.accessibility.AccessibilityNodeInfo getAnchor();
method public void getBoundsInScreen(android.graphics.Rect);
diff --git a/api/system-current.txt b/api/system-current.txt
index adfda2fe527a..5ff6778f64ba 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -75,7 +75,7 @@ package android {
field public static final String GET_PROCESS_STATE_AND_OOM_SCORE = "android.permission.GET_PROCESS_STATE_AND_OOM_SCORE";
field public static final String GET_RUNTIME_PERMISSIONS = "android.permission.GET_RUNTIME_PERMISSIONS";
field public static final String GET_TOP_ACTIVITY_INFO = "android.permission.GET_TOP_ACTIVITY_INFO";
- field public static final String GRANT_PROFILE_OWNER_DEVICE_IDS_ACCESS = "android.permission.GRANT_PROFILE_OWNER_DEVICE_IDS_ACCESS";
+ field @Deprecated public static final String GRANT_PROFILE_OWNER_DEVICE_IDS_ACCESS = "android.permission.GRANT_PROFILE_OWNER_DEVICE_IDS_ACCESS";
field public static final String GRANT_RUNTIME_PERMISSIONS = "android.permission.GRANT_RUNTIME_PERMISSIONS";
field public static final String GRANT_RUNTIME_PERMISSIONS_TO_TELEPHONY_DEFAULTS = "android.permission.GRANT_RUNTIME_PERMISSIONS_TO_TELEPHONY_DEFAULTS";
field public static final String HANDLE_CAR_MODE_CHANGES = "android.permission.HANDLE_CAR_MODE_CHANGES";
@@ -213,6 +213,8 @@ package android {
field public static final String USER_ACTIVITY = "android.permission.USER_ACTIVITY";
field public static final String USE_RESERVED_DISK = "android.permission.USE_RESERVED_DISK";
field public static final String WHITELIST_RESTRICTED_PERMISSIONS = "android.permission.WHITELIST_RESTRICTED_PERMISSIONS";
+ field public static final String WIFI_SET_DEVICE_MOBILITY_STATE = "android.permission.WIFI_SET_DEVICE_MOBILITY_STATE";
+ field public static final String WIFI_UPDATE_USABILITY_STATS_SCORE = "android.permission.WIFI_UPDATE_USABILITY_STATS_SCORE";
field public static final String WRITE_DEVICE_CONFIG = "android.permission.WRITE_DEVICE_CONFIG";
field public static final String WRITE_DREAM_STATE = "android.permission.WRITE_DREAM_STATE";
field public static final String WRITE_EMBEDDED_SUBSCRIPTIONS = "android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS";
@@ -652,6 +654,29 @@ package android.app {
method public boolean isStatusBarExpansionDisabled();
}
+ public final class SystemServiceRegistry {
+ method public static <TServiceClass> void registerContextAwareService(@NonNull String, @NonNull Class<TServiceClass>, @NonNull android.app.SystemServiceRegistry.ContextAwareServiceProducerWithBinder<TServiceClass>);
+ method public static <TServiceClass> void registerContextAwareService(@NonNull String, @NonNull Class<TServiceClass>, @NonNull android.app.SystemServiceRegistry.ContextAwareServiceProducerWithoutBinder<TServiceClass>);
+ method public static <TServiceClass> void registerStaticService(@NonNull String, @NonNull Class<TServiceClass>, @NonNull android.app.SystemServiceRegistry.StaticServiceProducerWithBinder<TServiceClass>);
+ method public static <TServiceClass> void registerStaticService(@NonNull String, @NonNull Class<TServiceClass>, @NonNull android.app.SystemServiceRegistry.StaticServiceProducerWithoutBinder<TServiceClass>);
+ }
+
+ public static interface SystemServiceRegistry.ContextAwareServiceProducerWithBinder<TServiceClass> {
+ method @NonNull public TServiceClass createService(@NonNull android.content.Context, @NonNull android.os.IBinder);
+ }
+
+ public static interface SystemServiceRegistry.ContextAwareServiceProducerWithoutBinder<TServiceClass> {
+ method @NonNull public TServiceClass createService(@NonNull android.content.Context);
+ }
+
+ public static interface SystemServiceRegistry.StaticServiceProducerWithBinder<TServiceClass> {
+ method @NonNull public TServiceClass createService(@NonNull android.os.IBinder);
+ }
+
+ public static interface SystemServiceRegistry.StaticServiceProducerWithoutBinder<TServiceClass> {
+ method @NonNull public TServiceClass createService();
+ }
+
public class UiModeManager {
method @RequiresPermission(android.Manifest.permission.ENTER_CAR_MODE_PRIORITIZED) public void enableCarMode(@IntRange(from=0) int, int);
field public static final String ACTION_ENTER_CAR_MODE_PRIORITIZED = "android.app.action.ENTER_CAR_MODE_PRIORITIZED";
@@ -745,7 +770,7 @@ package android.app.admin {
method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) public boolean packageHasActiveAdmins(String);
method @Deprecated @RequiresPermission("android.permission.MANAGE_DEVICE_ADMINS") public boolean setActiveProfileOwner(@NonNull android.content.ComponentName, String) throws java.lang.IllegalArgumentException;
method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public void setDeviceProvisioningConfigApplied();
- method @RequiresPermission(value=android.Manifest.permission.GRANT_PROFILE_OWNER_DEVICE_IDS_ACCESS, conditional=true) public void setProfileOwnerCanAccessDeviceIds(@NonNull android.content.ComponentName);
+ method @Deprecated @RequiresPermission(value=android.Manifest.permission.GRANT_PROFILE_OWNER_DEVICE_IDS_ACCESS, conditional=true) public void setProfileOwnerCanAccessDeviceIds(@NonNull android.content.ComponentName);
field public static final String ACCOUNT_FEATURE_DEVICE_OR_PROFILE_OWNER_ALLOWED = "android.account.DEVICE_OR_PROFILE_OWNER_ALLOWED";
field public static final String ACCOUNT_FEATURE_DEVICE_OR_PROFILE_OWNER_DISALLOWED = "android.account.DEVICE_OR_PROFILE_OWNER_DISALLOWED";
field public static final String ACTION_PROVISION_FINALIZATION = "android.app.action.PROVISION_FINALIZATION";
@@ -805,6 +830,7 @@ package android.app.backup {
method @RequiresPermission(android.Manifest.permission.BACKUP) public void backupNow();
method @RequiresPermission(android.Manifest.permission.BACKUP) public android.app.backup.RestoreSession beginRestoreSession();
method @RequiresPermission(android.Manifest.permission.BACKUP) public void cancelBackups();
+ method @RequiresPermission(android.Manifest.permission.BACKUP) public void excludeKeysFromRestore(@NonNull String, @NonNull java.util.List<java.lang.String>);
method @RequiresPermission(android.Manifest.permission.BACKUP) public long getAvailableRestoreToken(String);
method @RequiresPermission(android.Manifest.permission.BACKUP) public android.content.Intent getConfigurationIntent(String);
method @RequiresPermission(android.Manifest.permission.BACKUP) public String getCurrentTransport();
@@ -1091,6 +1117,10 @@ package android.app.job {
method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public abstract int scheduleAsPackage(@NonNull android.app.job.JobInfo, @NonNull String, int, String);
}
+ public class JobSchedulerFrameworkInitializer {
+ method public static void registerServiceWrappers();
+ }
+
}
package android.app.prediction {
@@ -1283,7 +1313,7 @@ package android.app.usage {
method @RequiresPermission(allOf={android.Manifest.permission.SUSPEND_APPS, android.Manifest.permission.OBSERVE_APP_USAGE}) public void unregisterAppUsageLimitObserver(int);
method @RequiresPermission(android.Manifest.permission.OBSERVE_APP_USAGE) public void unregisterAppUsageObserver(int);
method @RequiresPermission(android.Manifest.permission.OBSERVE_APP_USAGE) public void unregisterUsageSessionObserver(int);
- method @RequiresPermission(android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST) public void whitelistAppTemporarily(String, long, android.os.UserHandle);
+ method @Deprecated @RequiresPermission(android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST) public void whitelistAppTemporarily(String, long, android.os.UserHandle);
field public static final String EXTRA_OBSERVER_ID = "android.app.usage.extra.OBSERVER_ID";
field public static final String EXTRA_TIME_LIMIT = "android.app.usage.extra.TIME_LIMIT";
field public static final String EXTRA_TIME_USED = "android.app.usage.extra.TIME_USED";
@@ -1453,6 +1483,7 @@ package android.content {
method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public abstract void sendBroadcastAsUser(@RequiresPermission android.content.Intent, android.os.UserHandle, @Nullable String, @Nullable android.os.Bundle);
method public abstract void sendOrderedBroadcast(@NonNull android.content.Intent, @Nullable String, @Nullable android.os.Bundle, @Nullable android.content.BroadcastReceiver, @Nullable android.os.Handler, int, @Nullable String, @Nullable android.os.Bundle);
method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) public void startActivityAsUser(@NonNull @RequiresPermission android.content.Intent, @NonNull android.os.UserHandle);
+ field public static final String APP_INTEGRITY_SERVICE = "app_integrity";
field public static final String APP_PREDICTION_SERVICE = "app_prediction";
field public static final String BACKUP_SERVICE = "backup";
field public static final String BATTERY_STATS_SERVICE = "batterystats";
@@ -1505,6 +1536,7 @@ package android.content {
field public static final String ACTION_MANAGE_PERMISSION_APPS = "android.intent.action.MANAGE_PERMISSION_APPS";
field @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public static final String ACTION_MANAGE_SPECIAL_APP_ACCESSES = "android.intent.action.MANAGE_SPECIAL_APP_ACCESSES";
field public static final String ACTION_MASTER_CLEAR_NOTIFICATION = "android.intent.action.MASTER_CLEAR_NOTIFICATION";
+ field public static final String ACTION_PACKAGE_NEEDS_INTEGRITY_VERIFICATION = "android.intent.action.PACKAGE_NEEDS_INTEGRITY_VERIFICATION";
field public static final String ACTION_PENDING_INCIDENT_REPORTS_CHANGED = "android.intent.action.PENDING_INCIDENT_REPORTS_CHANGED";
field public static final String ACTION_PRE_BOOT_COMPLETED = "android.intent.action.PRE_BOOT_COMPLETED";
field public static final String ACTION_QUERY_PACKAGE_RESTART = "android.intent.action.QUERY_PACKAGE_RESTART";
@@ -1552,6 +1584,150 @@ package android.content {
}
+package android.content.integrity {
+
+ public final class AppInstallMetadata {
+ method @NonNull public String getAppCertificate();
+ method @Nullable public String getInstallerCertificate();
+ method @Nullable public String getInstallerName();
+ method @NonNull public String getPackageName();
+ method public int getVersionCode();
+ method public boolean isPreInstalled();
+ }
+
+ public static final class AppInstallMetadata.Builder {
+ ctor public AppInstallMetadata.Builder();
+ method @NonNull public android.content.integrity.AppInstallMetadata build();
+ method @NonNull public android.content.integrity.AppInstallMetadata.Builder setAppCertificate(@NonNull String);
+ method @NonNull public android.content.integrity.AppInstallMetadata.Builder setInstallerCertificate(@NonNull String);
+ method @NonNull public android.content.integrity.AppInstallMetadata.Builder setInstallerName(@NonNull String);
+ method @NonNull public android.content.integrity.AppInstallMetadata.Builder setIsPreInstalled(boolean);
+ method @NonNull public android.content.integrity.AppInstallMetadata.Builder setPackageName(@NonNull String);
+ method @NonNull public android.content.integrity.AppInstallMetadata.Builder setVersionCode(int);
+ }
+
+ public class AppIntegrityManager {
+ method @NonNull public String getCurrentRuleSetProvider();
+ method @NonNull public String getCurrentRuleSetVersion();
+ method public void updateRuleSet(@NonNull android.content.integrity.RuleSet, @NonNull android.content.IntentSender);
+ field public static final String EXTRA_STATUS = "android.content.integrity.extra.STATUS";
+ field public static final int STATUS_FAILURE = 1; // 0x1
+ field public static final int STATUS_SUCCESS = 0; // 0x0
+ }
+
+ public abstract class AtomicFormula implements android.content.integrity.Formula {
+ ctor public AtomicFormula(@android.content.integrity.AtomicFormula.Key int);
+ method public int getKey();
+ field public static final int APP_CERTIFICATE = 1; // 0x1
+ field public static final int EQ = 0; // 0x0
+ field public static final int GE = 4; // 0x4
+ field public static final int GT = 3; // 0x3
+ field public static final int INSTALLER_CERTIFICATE = 3; // 0x3
+ field public static final int INSTALLER_NAME = 2; // 0x2
+ field public static final int LE = 2; // 0x2
+ field public static final int LT = 1; // 0x1
+ field public static final int PACKAGE_NAME = 0; // 0x0
+ field public static final int PRE_INSTALLED = 5; // 0x5
+ field public static final int VERSION_CODE = 4; // 0x4
+ }
+
+ public static final class AtomicFormula.BooleanAtomicFormula extends android.content.integrity.AtomicFormula implements android.os.Parcelable {
+ ctor public AtomicFormula.BooleanAtomicFormula(@android.content.integrity.AtomicFormula.Key int, boolean);
+ method public int describeContents();
+ method public int getTag();
+ method public boolean getValue();
+ method public boolean isSatisfied(@NonNull android.content.integrity.AppInstallMetadata);
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.content.integrity.AtomicFormula.BooleanAtomicFormula> CREATOR;
+ }
+
+ public static final class AtomicFormula.IntAtomicFormula extends android.content.integrity.AtomicFormula implements android.os.Parcelable {
+ ctor public AtomicFormula.IntAtomicFormula(@android.content.integrity.AtomicFormula.Key int, @android.content.integrity.AtomicFormula.Operator int, int);
+ method public int describeContents();
+ method public int getOperator();
+ method public int getTag();
+ method public int getValue();
+ method public boolean isSatisfied(@NonNull android.content.integrity.AppInstallMetadata);
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.content.integrity.AtomicFormula.IntAtomicFormula> CREATOR;
+ }
+
+ @IntDef({android.content.integrity.AtomicFormula.PACKAGE_NAME, android.content.integrity.AtomicFormula.APP_CERTIFICATE, android.content.integrity.AtomicFormula.INSTALLER_NAME, android.content.integrity.AtomicFormula.INSTALLER_CERTIFICATE, android.content.integrity.AtomicFormula.VERSION_CODE, android.content.integrity.AtomicFormula.PRE_INSTALLED}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface AtomicFormula.Key {
+ }
+
+ @IntDef({android.content.integrity.AtomicFormula.EQ, android.content.integrity.AtomicFormula.LT, android.content.integrity.AtomicFormula.LE, android.content.integrity.AtomicFormula.GT, android.content.integrity.AtomicFormula.GE}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface AtomicFormula.Operator {
+ }
+
+ public static final class AtomicFormula.StringAtomicFormula extends android.content.integrity.AtomicFormula implements android.os.Parcelable {
+ ctor public AtomicFormula.StringAtomicFormula(@android.content.integrity.AtomicFormula.Key int, @NonNull String, boolean);
+ method public int describeContents();
+ method public boolean getIsHashedValue();
+ method public int getTag();
+ method @NonNull public String getValue();
+ method public boolean isSatisfied(@NonNull android.content.integrity.AppInstallMetadata);
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.content.integrity.AtomicFormula.StringAtomicFormula> CREATOR;
+ }
+
+ public final class CompoundFormula implements android.content.integrity.Formula android.os.Parcelable {
+ ctor public CompoundFormula(@android.content.integrity.CompoundFormula.Connector int, @NonNull java.util.List<android.content.integrity.Formula>);
+ method public int describeContents();
+ method @android.content.integrity.CompoundFormula.Connector public int getConnector();
+ method @NonNull public java.util.List<android.content.integrity.Formula> getFormulas();
+ method public int getTag();
+ method public boolean isSatisfied(@NonNull android.content.integrity.AppInstallMetadata);
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field public static final int AND = 0; // 0x0
+ field @NonNull public static final android.os.Parcelable.Creator<android.content.integrity.CompoundFormula> CREATOR;
+ field public static final int NOT = 2; // 0x2
+ field public static final int OR = 1; // 0x1
+ }
+
+ @IntDef({android.content.integrity.CompoundFormula.AND, android.content.integrity.CompoundFormula.OR, android.content.integrity.CompoundFormula.NOT}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface CompoundFormula.Connector {
+ }
+
+ public interface Formula {
+ method @android.content.integrity.Formula.Tag public int getTag();
+ method public boolean isSatisfied(@NonNull android.content.integrity.AppInstallMetadata);
+ method @NonNull public static android.content.integrity.Formula readFromParcel(@NonNull android.os.Parcel);
+ method public static void writeToParcel(@NonNull android.content.integrity.Formula, @NonNull android.os.Parcel, int);
+ field public static final int BOOLEAN_ATOMIC_FORMULA_TAG = 3; // 0x3
+ field public static final int COMPOUND_FORMULA_TAG = 0; // 0x0
+ field public static final int INT_ATOMIC_FORMULA_TAG = 2; // 0x2
+ field public static final int STRING_ATOMIC_FORMULA_TAG = 1; // 0x1
+ }
+
+ @IntDef({android.content.integrity.Formula.COMPOUND_FORMULA_TAG, android.content.integrity.Formula.STRING_ATOMIC_FORMULA_TAG, android.content.integrity.Formula.INT_ATOMIC_FORMULA_TAG, android.content.integrity.Formula.BOOLEAN_ATOMIC_FORMULA_TAG}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface Formula.Tag {
+ }
+
+ public final class Rule implements android.os.Parcelable {
+ ctor public Rule(@NonNull android.content.integrity.Formula, @android.content.integrity.Rule.Effect int);
+ method public int describeContents();
+ method @android.content.integrity.Rule.Effect public int getEffect();
+ method @NonNull public android.content.integrity.Formula getFormula();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.content.integrity.Rule> CREATOR;
+ field public static final int DENY = 0; // 0x0
+ field public static final int FORCE_ALLOW = 1; // 0x1
+ }
+
+ @IntDef({android.content.integrity.Rule.DENY, android.content.integrity.Rule.FORCE_ALLOW}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface Rule.Effect {
+ }
+
+ public class RuleSet {
+ method @NonNull public java.util.List<android.content.integrity.Rule> getRules();
+ method @NonNull public String getVersion();
+ }
+
+ public static class RuleSet.Builder {
+ ctor public RuleSet.Builder();
+ method @NonNull public android.content.integrity.RuleSet.Builder addRules(@NonNull java.util.List<android.content.integrity.Rule>);
+ method @NonNull public android.content.integrity.RuleSet build();
+ method @NonNull public android.content.integrity.RuleSet.Builder setVersion(@NonNull String);
+ }
+
+}
+
package android.content.om {
public final class OverlayInfo implements android.os.Parcelable {
@@ -1843,7 +2019,6 @@ package android.content.pm {
field public static final int PROTECTION_FLAG_SYSTEM_TEXT_CLASSIFIER = 65536; // 0x10000
field public static final int PROTECTION_FLAG_TELEPHONY = 4194304; // 0x400000
field public static final int PROTECTION_FLAG_WELLBEING = 131072; // 0x20000
- field public static final int PROTECTION_FLAG_WIFI = 8388608; // 0x800000
field @Nullable public final String backgroundPermission;
field @StringRes public int requestRes;
}
@@ -4206,6 +4381,7 @@ package android.net {
public final class IpConfiguration implements android.os.Parcelable {
ctor public IpConfiguration();
ctor public IpConfiguration(@NonNull android.net.IpConfiguration);
+ method public int describeContents();
method @Nullable public android.net.ProxyInfo getHttpProxy();
method @NonNull public android.net.IpConfiguration.IpAssignment getIpAssignment();
method @NonNull public android.net.IpConfiguration.ProxySettings getProxySettings();
@@ -4214,6 +4390,7 @@ package android.net {
method public void setIpAssignment(@NonNull android.net.IpConfiguration.IpAssignment);
method public void setProxySettings(@NonNull android.net.IpConfiguration.ProxySettings);
method public void setStaticIpConfiguration(@Nullable android.net.StaticIpConfiguration);
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.net.IpConfiguration> CREATOR;
}
@@ -4266,7 +4443,6 @@ package android.net {
ctor public LinkProperties(@Nullable android.net.LinkProperties);
method public boolean addDnsServer(@NonNull java.net.InetAddress);
method public boolean addLinkAddress(@NonNull android.net.LinkAddress);
- method @Nullable public android.net.IpPrefix getNat64Prefix();
method @NonNull public java.util.List<java.net.InetAddress> getPcscfServers();
method @Nullable public String getTcpBufferSizes();
method @NonNull public java.util.List<java.net.InetAddress> getValidatedPrivateDnsServers();
@@ -4280,7 +4456,6 @@ package android.net {
method public boolean removeDnsServer(@NonNull java.net.InetAddress);
method public boolean removeLinkAddress(@NonNull android.net.LinkAddress);
method public boolean removeRoute(@NonNull android.net.RouteInfo);
- method public void setNat64Prefix(@Nullable android.net.IpPrefix);
method public void setPcscfServers(@NonNull java.util.Collection<java.net.InetAddress>);
method public void setPrivateDnsServerName(@Nullable String);
method public void setTcpBufferSizes(@Nullable String);
@@ -5250,7 +5425,7 @@ package android.net.wifi {
}
public class WifiManager {
- method @RequiresPermission("android.permission.WIFI_UPDATE_USABILITY_STATS_SCORE") public void addOnWifiUsabilityStatsListener(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.WifiManager.OnWifiUsabilityStatsListener);
+ method @RequiresPermission(android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE) public void addOnWifiUsabilityStatsListener(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.WifiManager.OnWifiUsabilityStatsListener);
method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void allowAutojoin(int, boolean);
method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK}) public void connect(@NonNull android.net.wifi.WifiConfiguration, @Nullable android.net.wifi.WifiManager.ActionListener);
method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK}) public void connect(int, @Nullable android.net.wifi.WifiManager.ActionListener);
@@ -5283,12 +5458,12 @@ package android.net.wifi {
method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void registerSoftApCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.WifiManager.SoftApCallback);
method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void registerTrafficStateCallback(@NonNull android.net.wifi.WifiManager.TrafficStateCallback);
method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void registerTrafficStateCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.WifiManager.TrafficStateCallback);
- method @RequiresPermission("android.permission.WIFI_UPDATE_USABILITY_STATS_SCORE") public void removeOnWifiUsabilityStatsListener(@NonNull android.net.wifi.WifiManager.OnWifiUsabilityStatsListener);
+ method @RequiresPermission(android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE) public void removeOnWifiUsabilityStatsListener(@NonNull android.net.wifi.WifiManager.OnWifiUsabilityStatsListener);
method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void restoreBackupData(@NonNull byte[]);
method @Deprecated @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void restoreSupplicantBackupData(@NonNull byte[], @NonNull byte[]);
method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public byte[] retrieveBackupData();
method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK}) public void save(@NonNull android.net.wifi.WifiConfiguration, @Nullable android.net.wifi.WifiManager.ActionListener);
- method @RequiresPermission("android.permission.WIFI_SET_DEVICE_MOBILITY_STATE") public void setDeviceMobilityState(int);
+ method @RequiresPermission(android.Manifest.permission.WIFI_SET_DEVICE_MOBILITY_STATE) public void setDeviceMobilityState(int);
method @RequiresPermission(android.Manifest.permission.CHANGE_WIFI_STATE) public boolean setWifiApConfiguration(android.net.wifi.WifiConfiguration);
method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public void startEasyConnectAsConfiguratorInitiator(@NonNull String, int, int, @NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.EasyConnectStatusCallback);
method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public void startEasyConnectAsEnrolleeInitiator(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.EasyConnectStatusCallback);
@@ -5302,7 +5477,7 @@ package android.net.wifi {
method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void unregisterSoftApCallback(@NonNull android.net.wifi.WifiManager.SoftApCallback);
method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void unregisterTrafficStateCallback(@NonNull android.net.wifi.WifiManager.TrafficStateCallback);
method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void updateInterfaceIpState(@Nullable String, int);
- method @RequiresPermission("android.permission.WIFI_UPDATE_USABILITY_STATS_SCORE") public void updateWifiUsabilityScore(int, int, int);
+ method @RequiresPermission(android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE) public void updateWifiUsabilityScore(int, int, int);
field public static final String ACTION_LINK_CONFIGURATION_CHANGED = "android.net.wifi.LINK_CONFIGURATION_CHANGED";
field public static final String ACTION_PASSPOINT_LAUNCH_OSU_VIEW = "android.net.wifi.action.PASSPOINT_LAUNCH_OSU_VIEW";
field public static final String ACTION_REQUEST_DISABLE = "android.net.wifi.action.REQUEST_DISABLE";
@@ -5405,6 +5580,7 @@ package android.net.wifi {
method @NonNull @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public java.util.List<java.lang.Integer> getAvailableChannels(int);
method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public boolean getScanResults();
method @NonNull @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public java.util.List<android.net.wifi.ScanResult> getSingleScanResults();
+ method @RequiresPermission(android.Manifest.permission.NETWORK_STACK) public void registerScanListener(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.WifiScanner.ScanListener);
method @RequiresPermission(android.Manifest.permission.NETWORK_STACK) public void setScanningEnabled(boolean);
method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void startBackgroundScan(android.net.wifi.WifiScanner.ScanSettings, android.net.wifi.WifiScanner.ScanListener);
method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void startBackgroundScan(android.net.wifi.WifiScanner.ScanSettings, android.net.wifi.WifiScanner.ScanListener, android.os.WorkSource);
@@ -5416,6 +5592,7 @@ package android.net.wifi {
method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void stopScan(android.net.wifi.WifiScanner.ScanListener);
method @Deprecated public void stopTrackingBssids(android.net.wifi.WifiScanner.BssidListener);
method @Deprecated public void stopTrackingWifiChange(android.net.wifi.WifiScanner.WifiChangeListener);
+ method public void unregisterScanListener(@NonNull android.net.wifi.WifiScanner.ScanListener);
field public static final int MAX_SCAN_PERIOD_MS = 1024000; // 0xfa000
field public static final int MIN_SCAN_PERIOD_MS = 1000; // 0x3e8
field public static final int REASON_DUPLICATE_REQEUST = -5; // 0xfffffffb
@@ -5428,6 +5605,9 @@ package android.net.wifi {
field public static final int REPORT_EVENT_AFTER_EACH_SCAN = 1; // 0x1
field public static final int REPORT_EVENT_FULL_SCAN_RESULT = 2; // 0x2
field public static final int REPORT_EVENT_NO_BATCH = 4; // 0x4
+ field public static final int SCAN_TYPE_HIGH_ACCURACY = 2; // 0x2
+ field public static final int SCAN_TYPE_LOW_LATENCY = 0; // 0x0
+ field public static final int SCAN_TYPE_LOW_POWER = 1; // 0x1
field public static final int WIFI_BAND_24_GHZ = 1; // 0x1
field public static final int WIFI_BAND_5_GHZ = 2; // 0x2
field public static final int WIFI_BAND_5_GHZ_DFS_ONLY = 4; // 0x4
@@ -5496,6 +5676,7 @@ package android.net.wifi {
ctor public WifiScanner.ScanSettings();
field public int band;
field public android.net.wifi.WifiScanner.ChannelSpec[] channels;
+ field @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_STACK) public final java.util.List<android.net.wifi.WifiScanner.ScanSettings.HiddenNetwork> hiddenNetworks;
field public boolean hideFromAppOps;
field public boolean ignoreLocationSettings;
field public int maxPeriodInMs;
@@ -5504,6 +5685,12 @@ package android.net.wifi {
field public int periodInMs;
field public int reportEvents;
field public int stepCount;
+ field @RequiresPermission(android.Manifest.permission.NETWORK_STACK) public int type;
+ }
+
+ public static class WifiScanner.ScanSettings.HiddenNetwork {
+ ctor public WifiScanner.ScanSettings.HiddenNetwork(@NonNull String);
+ field @NonNull public final String ssid;
}
@Deprecated public static interface WifiScanner.WifiChangeListener extends android.net.wifi.WifiScanner.ActionListener {
@@ -6111,6 +6298,11 @@ package android.os {
}
public class PowerWhitelistManager {
+ method @RequiresPermission(android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST) public void whitelistAppTemporarily(@NonNull String, long);
+ method @RequiresPermission(android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST) public long whitelistAppTemporarilyForEvent(@NonNull String, int, @NonNull String);
+ field public static final int EVENT_MMS = 2; // 0x2
+ field public static final int EVENT_SMS = 1; // 0x1
+ field public static final int EVENT_UNSPECIFIED = 0; // 0x0
}
public class RecoverySystem {
@@ -6239,6 +6431,7 @@ package android.os {
}
public final class UserHandle implements android.os.Parcelable {
+ method @NonNull public static String formatUid(int);
method public static int getAppId(int);
method public int getIdentifier();
method @Deprecated public boolean isOwner();
@@ -6842,6 +7035,7 @@ package android.provider {
field public static final String LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS = "lock_screen_allow_private_notifications";
field public static final String LOCK_SCREEN_SHOW_NOTIFICATIONS = "lock_screen_show_notifications";
field public static final String ODI_CAPTIONS_ENABLED = "odi_captions_enabled";
+ field public static final String SECURE_FRP_MODE = "secure_frp_mode";
field public static final String THEME_CUSTOMIZATION_OVERLAY_PACKAGES = "theme_customization_overlay_packages";
field public static final String USER_SETUP_COMPLETE = "user_setup_complete";
field public static final int USER_SETUP_PERSONALIZATION_COMPLETE = 10; // 0xa
@@ -7828,6 +8022,10 @@ package android.telecom {
field public static final int PROPERTY_REMOTELY_HOSTED = 2048; // 0x800
}
+ public final class ConnectionRequest implements android.os.Parcelable {
+ method @Nullable public String getTelecomCallId();
+ }
+
public abstract class ConnectionService extends android.app.Service {
method public final void addExistingConnection(@NonNull android.telecom.PhoneAccountHandle, @NonNull android.telecom.Connection, @NonNull android.telecom.Conference);
}
@@ -8035,6 +8233,7 @@ package android.telecom {
method public java.util.List<android.telecom.PhoneAccountHandle> getAllPhoneAccountHandles();
method public java.util.List<android.telecom.PhoneAccount> getAllPhoneAccounts();
method public int getAllPhoneAccountsCount();
+ method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public java.util.List<android.telecom.PhoneAccountHandle> getCallCapablePhoneAccounts(boolean);
method public int getCallState();
method public android.telecom.PhoneAccountHandle getConnectionManager();
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getCurrentTtyMode();
@@ -8993,6 +9192,7 @@ package android.telephony {
method @NonNull public android.content.ContentValues getContentValues();
method @Nullable public android.telephony.SmsCbEtwsInfo getEtwsWarningInfo();
method public int getGeographicalScope();
+ method @NonNull public java.util.List<android.telephony.CbGeoUtils.Geometry> getGeometries();
method @Nullable public String getLanguageCode();
method @NonNull public android.telephony.SmsCbLocation getLocation();
method public int getMaximumWaitingDuration();
@@ -9037,6 +9237,7 @@ package android.telephony {
}
public class SubscriptionManager {
+ method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean canDisablePhysicalSubscription();
method public java.util.List<android.telephony.SubscriptionInfo> getAvailableSubscriptionInfoList();
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getEnabledSubscriptionId(int);
method @NonNull public static android.content.res.Resources getResourcesForSubId(@NonNull android.content.Context, int);
diff --git a/api/system-lint-baseline.txt b/api/system-lint-baseline.txt
index ab0f0f987d54..fcf5178716e1 100644
--- a/api/system-lint-baseline.txt
+++ b/api/system-lint-baseline.txt
@@ -65,7 +65,7 @@ MissingNullability: android.media.tv.TvRecordingClient.RecordingCallback#onEvent
MissingNullability: android.media.tv.TvRecordingClient.RecordingCallback#onEvent(String, String, android.os.Bundle) parameter #1:
MissingNullability: android.media.tv.TvRecordingClient.RecordingCallback#onEvent(String, String, android.os.Bundle) parameter #2:
-
+
MissingNullability: android.net.wifi.rtt.RangingRequest.Builder#addResponder(android.net.wifi.rtt.ResponderConfig):
MissingNullability: android.printservice.recommendation.RecommendationService#attachBaseContext(android.content.Context) parameter #0:
@@ -181,6 +181,8 @@ MutableBareField: android.net.wifi.WifiConfiguration#saePasswordId:
Bare field saePasswordId must be marked final, or moved behind accessors if mutable
MutableBareField: android.net.wifi.WifiConfiguration#shared:
Bare field shared must be marked final, or moved behind accessors if mutable
+MutableBareField: android.net.wifi.WifiScanner.ScanSettings#type:
+ Bare field type must be marked final, or moved behind accessors if mutable
NoClone: android.service.contentcapture.ContentCaptureService#dump(java.io.FileDescriptor, java.io.PrintWriter, String[]) parameter #0:
diff --git a/api/test-current.txt b/api/test-current.txt
index dacc5d67b730..9ac789edba9a 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -812,7 +812,6 @@ package android.content.pm {
field public static final int PROTECTION_FLAG_TELEPHONY = 4194304; // 0x400000
field public static final int PROTECTION_FLAG_VENDOR_PRIVILEGED = 32768; // 0x8000
field public static final int PROTECTION_FLAG_WELLBEING = 131072; // 0x20000
- field public static final int PROTECTION_FLAG_WIFI = 8388608; // 0x800000
field @Nullable public final String backgroundPermission;
}
@@ -1467,7 +1466,6 @@ package android.net {
ctor public LinkProperties(@Nullable android.net.LinkProperties);
method public boolean addDnsServer(@NonNull java.net.InetAddress);
method public boolean addLinkAddress(@NonNull android.net.LinkAddress);
- method @Nullable public android.net.IpPrefix getNat64Prefix();
method @NonNull public java.util.List<java.net.InetAddress> getPcscfServers();
method @Nullable public String getTcpBufferSizes();
method @NonNull public java.util.List<java.net.InetAddress> getValidatedPrivateDnsServers();
@@ -1481,7 +1479,6 @@ package android.net {
method public boolean removeDnsServer(@NonNull java.net.InetAddress);
method public boolean removeLinkAddress(@NonNull android.net.LinkAddress);
method public boolean removeRoute(@NonNull android.net.RouteInfo);
- method public void setNat64Prefix(@Nullable android.net.IpPrefix);
method public void setPcscfServers(@NonNull java.util.Collection<java.net.InetAddress>);
method public void setPrivateDnsServerName(@Nullable String);
method public void setTcpBufferSizes(@Nullable String);
@@ -2044,6 +2041,11 @@ package android.os {
}
public class PowerWhitelistManager {
+ method @RequiresPermission("android.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST") public void whitelistAppTemporarily(@NonNull String, long);
+ method @RequiresPermission("android.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST") public long whitelistAppTemporarilyForEvent(@NonNull String, int, @NonNull String);
+ field public static final int EVENT_MMS = 2; // 0x2
+ field public static final int EVENT_SMS = 1; // 0x1
+ field public static final int EVENT_UNSPECIFIED = 0; // 0x0
}
public class Process {
@@ -2970,6 +2972,23 @@ package android.telecom {
field public static final int PROPERTY_REMOTELY_HOSTED = 2048; // 0x800
}
+ public final class ConnectionRequest implements android.os.Parcelable {
+ method @Nullable public String getTelecomCallId();
+ }
+
+ public static final class ConnectionRequest.Builder {
+ ctor public ConnectionRequest.Builder();
+ method @NonNull public android.telecom.ConnectionRequest build();
+ method @NonNull public android.telecom.ConnectionRequest.Builder setAccountHandle(@NonNull android.telecom.PhoneAccountHandle);
+ method @NonNull public android.telecom.ConnectionRequest.Builder setAddress(@NonNull android.net.Uri);
+ method @NonNull public android.telecom.ConnectionRequest.Builder setExtras(@NonNull android.os.Bundle);
+ method @NonNull public android.telecom.ConnectionRequest.Builder setRttPipeFromInCall(@NonNull android.os.ParcelFileDescriptor);
+ method @NonNull public android.telecom.ConnectionRequest.Builder setRttPipeToInCall(@NonNull android.os.ParcelFileDescriptor);
+ method @NonNull public android.telecom.ConnectionRequest.Builder setShouldShowIncomingCallUi(boolean);
+ method @NonNull public android.telecom.ConnectionRequest.Builder setTelecomCallId(@NonNull String);
+ method @NonNull public android.telecom.ConnectionRequest.Builder setVideoState(int);
+ }
+
public static class PhoneAccount.Builder {
method @NonNull public android.telecom.PhoneAccount.Builder setGroupId(@NonNull String);
}
@@ -2983,6 +3002,7 @@ package android.telecom {
}
public class TelecomManager {
+ method @NonNull @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public java.util.List<android.telecom.PhoneAccountHandle> getCallCapablePhoneAccounts(boolean);
method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public int getCurrentTtyMode();
method @Nullable @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public String getDefaultDialerPackage(int);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean isInEmergencyCall();
@@ -4270,6 +4290,7 @@ package android.util {
field public static final String PERSIST_PREFIX = "persist.sys.fflag.override.";
field public static final String SCREENRECORD_LONG_PRESS = "settings_screenrecord_long_press";
field public static final String SEAMLESS_TRANSFER = "settings_seamless_transfer";
+ field public static final String SETTINGS_FUSE_FLAG = "settings_fuse";
field public static final String SETTINGS_WIFITRACKER2 = "settings_wifitracker2";
}
diff --git a/cmds/dpm/src/com/android/commands/dpm/Dpm.java b/cmds/dpm/src/com/android/commands/dpm/Dpm.java
index 6c6797a328c9..d0c2a24d5314 100644
--- a/cmds/dpm/src/com/android/commands/dpm/Dpm.java
+++ b/cmds/dpm/src/com/android/commands/dpm/Dpm.java
@@ -48,8 +48,8 @@ public final class Dpm extends BaseCommand {
private static final String COMMAND_CLEAR_FREEZE_PERIOD_RECORD = "clear-freeze-period-record";
private static final String COMMAND_FORCE_NETWORK_LOGS = "force-network-logs";
private static final String COMMAND_FORCE_SECURITY_LOGS = "force-security-logs";
- private static final String COMMAND_GRANT_PO_DEVICE_ID_ACCESS =
- "grant-profile-owner-device-ids-access";
+ private static final String COMMAND_MARK_PO_ON_ORG_OWNED_DEVICE =
+ "mark-profile-owner-on-organization-owned-device";
private IDevicePolicyManager mDevicePolicyManager;
private int mUserId = UserHandle.USER_SYSTEM;
@@ -93,7 +93,7 @@ public final class Dpm extends BaseCommand {
"dpm " + COMMAND_FORCE_SECURITY_LOGS + ": makes all security logs available to " +
"the DPC and triggers DeviceAdminReceiver.onSecurityLogsAvailable() if needed."
+ "\n"
- + "usage: dpm " + COMMAND_GRANT_PO_DEVICE_ID_ACCESS + ": "
+ + "usage: dpm " + COMMAND_MARK_PO_ON_ORG_OWNED_DEVICE + ": "
+ "[ --user <USER_ID> | current ] <COMPONENT>\n");
}
@@ -129,8 +129,8 @@ public final class Dpm extends BaseCommand {
case COMMAND_FORCE_SECURITY_LOGS:
runForceSecurityLogs();
break;
- case COMMAND_GRANT_PO_DEVICE_ID_ACCESS:
- runGrantProfileOwnerDeviceIdsAccess();
+ case COMMAND_MARK_PO_ON_ORG_OWNED_DEVICE:
+ runMarkProfileOwnerOnOrganizationOwnedDevice();
break;
default:
throw new IllegalArgumentException ("unknown command '" + command + "'");
@@ -251,9 +251,9 @@ public final class Dpm extends BaseCommand {
}
- private void runGrantProfileOwnerDeviceIdsAccess() throws RemoteException {
+ private void runMarkProfileOwnerOnOrganizationOwnedDevice() throws RemoteException {
parseArgs(/*canHaveName=*/ false);
- mDevicePolicyManager.grantDeviceIdsAccessToProfileOwner(mComponent, mUserId);
+ mDevicePolicyManager.markProfileOwnerOnOrganizationOwnedDevice(mComponent, mUserId);
System.out.println("Success");
}
diff --git a/cmds/statsd/Android.bp b/cmds/statsd/Android.bp
index 360ddd44955a..17427a20b90e 100644
--- a/cmds/statsd/Android.bp
+++ b/cmds/statsd/Android.bp
@@ -117,6 +117,10 @@ cc_defaults {
"src/uid_data.proto",
],
+ cflags: [
+ // "-DNEW_ENCODING_SCHEME",
+ ],
+
local_include_dirs: [
"src",
],
@@ -282,7 +286,10 @@ cc_test {
include_dirs: ["external/protobuf/src"],
},
- shared_libs: ["libprotobuf-cpp-lite"],
+ shared_libs: [
+ "libprotobuf-cpp-lite",
+ "libstatssocket"
+ ],
}
@@ -325,7 +332,7 @@ cc_benchmark {
"-Wno-unused-function",
// Bug: http://b/29823425 Disable -Wvarargs for Clang update to r271374
- "-Wno-varargs"
+ "-Wno-varargs",
],
static_libs: [
@@ -334,8 +341,9 @@ cc_benchmark {
shared_libs: [
"libgtest_prod",
- "libstatslog",
"libprotobuf-cpp-lite",
+ "libstatslog",
+ "libstatssocket",
],
}
diff --git a/cmds/statsd/benchmark/log_event_benchmark.cpp b/cmds/statsd/benchmark/log_event_benchmark.cpp
index 26034695906b..bdfdb2e00ac0 100644
--- a/cmds/statsd/benchmark/log_event_benchmark.cpp
+++ b/cmds/statsd/benchmark/log_event_benchmark.cpp
@@ -16,55 +16,30 @@
#include <vector>
#include "benchmark/benchmark.h"
#include "logd/LogEvent.h"
+#include "stats_event.h"
namespace android {
namespace os {
namespace statsd {
-using std::vector;
-
-/* Special markers for android_log_list_element type */
-static const char EVENT_TYPE_LIST_STOP = '\n'; /* declare end of list */
-static const char EVENT_TYPE_UNKNOWN = '?'; /* protocol error */
-
-static const char EVENT_TYPE_INT = 0;
-static const char EVENT_TYPE_LONG = 1;
-static const char EVENT_TYPE_STRING = 2;
-static const char EVENT_TYPE_LIST = 3;
-static const char EVENT_TYPE_FLOAT = 4;
-
-static const int kLogMsgHeaderSize = 28;
-
-static void write4Bytes(int val, vector<char>* buffer) {
- buffer->push_back(static_cast<char>(val));
- buffer->push_back(static_cast<char>((val >> 8) & 0xFF));
- buffer->push_back(static_cast<char>((val >> 16) & 0xFF));
- buffer->push_back(static_cast<char>((val >> 24) & 0xFF));
-}
-
-static void getSimpleLogMsgData(log_msg* msg) {
- vector<char> buffer;
- // stats_log tag id
- write4Bytes(1937006964, &buffer);
- buffer.push_back(EVENT_TYPE_LIST);
- buffer.push_back(2); // field counts;
- buffer.push_back(EVENT_TYPE_INT);
- write4Bytes(10 /* atom id */, &buffer);
- buffer.push_back(EVENT_TYPE_INT);
- write4Bytes(99 /* a value to log*/, &buffer);
- buffer.push_back(EVENT_TYPE_LIST_STOP);
-
- msg->entry.len = buffer.size();
- msg->entry.hdr_size = kLogMsgHeaderSize;
- msg->entry.sec = time(nullptr);
- std::copy(buffer.begin(), buffer.end(), msg->buf + kLogMsgHeaderSize);
+static size_t createAndParseStatsEvent(uint8_t* msg) {
+ struct stats_event* event = stats_event_obtain();
+ stats_event_set_atom_id(event, 100);
+ stats_event_write_int32(event, 2);
+ stats_event_write_float(event, 2.0);
+ stats_event_build(event);
+
+ size_t size;
+ uint8_t* buf = stats_event_get_buffer(event, &size);
+ memcpy(msg, buf, size);
+ return size;
}
static void BM_LogEventCreation(benchmark::State& state) {
- log_msg msg;
- getSimpleLogMsgData(&msg);
+ uint8_t msg[LOGGER_ENTRY_MAX_PAYLOAD];
+ size_t size = createAndParseStatsEvent(msg);
while (state.KeepRunning()) {
- benchmark::DoNotOptimize(LogEvent(msg));
+ benchmark::DoNotOptimize(LogEvent(msg, size, /*uid=*/ 1000));
}
}
BENCHMARK(BM_LogEventCreation);
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 49cc3c4c059e..2f22b4949410 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -6362,7 +6362,8 @@ message DeviceIdentifierAccessDenied {
optional bool is_preinstalled = 3;
// True if the package is privileged.
- optional bool is_priv_app = 4;
+ // Starting from Android 11, this boolean is not set and will always be false.
+ optional bool is_priv_app = 4 [deprecated = true];
}
/**
diff --git a/cmds/statsd/src/logd/LogEvent.cpp b/cmds/statsd/src/logd/LogEvent.cpp
index 262921e5163c..67022a078b01 100644
--- a/cmds/statsd/src/logd/LogEvent.cpp
+++ b/cmds/statsd/src/logd/LogEvent.cpp
@@ -35,16 +35,21 @@ using android::util::ProtoOutputStream;
using std::string;
using std::vector;
-LogEvent::LogEvent(log_msg& msg) {
- mContext =
- create_android_log_parser(msg.msg() + sizeof(uint32_t), msg.len() - sizeof(uint32_t));
- mLogdTimestampNs = msg.entry.sec * NS_PER_SEC + msg.entry.nsec;
- mLogUid = msg.entry.uid;
+// Msg is expected to begin at the start of the serialized atom -- it should not
+// include the android_log_header_t or the StatsEventTag.
+LogEvent::LogEvent(uint8_t* msg, uint32_t len, uint32_t uid)
+ : mBuf(msg),
+ mRemainingLen(len),
+ mLogdTimestampNs(time(nullptr)),
+ mLogUid(uid)
+{
+#ifdef NEW_ENCODING_SCHEME
+ initNew();
+# else
+ mContext = create_android_log_parser((char*)msg, len);
init(mContext);
- if (mContext) {
- // android_log_destroy will set mContext to NULL
- android_log_destroy(&mContext);
- }
+ if (mContext) android_log_destroy(&mContext); // set mContext to NULL
+#endif
}
LogEvent::LogEvent(const LogEvent& event) {
@@ -438,6 +443,186 @@ bool LogEvent::write(const AttributionNodeInternal& node) {
return false;
}
+void LogEvent::parseInt32(int32_t* pos, int32_t depth, bool* last) {
+ int32_t value = readNextValue<int32_t>();
+ addToValues(pos, depth, value, last);
+}
+
+void LogEvent::parseInt64(int32_t* pos, int32_t depth, bool* last) {
+ int64_t value = readNextValue<int64_t>();
+ addToValues(pos, depth, value, last);
+}
+
+void LogEvent::parseString(int32_t* pos, int32_t depth, bool* last) {
+ int32_t numBytes = readNextValue<int32_t>();
+ if ((uint32_t)numBytes > mRemainingLen) {
+ mValid = false;
+ return;
+ }
+
+ string value = string((char*)mBuf, numBytes);
+ mBuf += numBytes;
+ mRemainingLen -= numBytes;
+ addToValues(pos, depth, value, last);
+}
+
+void LogEvent::parseFloat(int32_t* pos, int32_t depth, bool* last) {
+ float value = readNextValue<float>();
+ addToValues(pos, depth, value, last);
+}
+
+void LogEvent::parseBool(int32_t* pos, int32_t depth, bool* last) {
+ // cast to int32_t because FieldValue does not support bools
+ int32_t value = (int32_t)readNextValue<uint8_t>();
+ addToValues(pos, depth, value, last);
+}
+
+void LogEvent::parseByteArray(int32_t* pos, int32_t depth, bool* last) {
+ int32_t numBytes = readNextValue<int32_t>();
+ if ((uint32_t)numBytes > mRemainingLen) {
+ mValid = false;
+ return;
+ }
+
+ vector<uint8_t> value(mBuf, mBuf + numBytes);
+ mBuf += numBytes;
+ mRemainingLen -= numBytes;
+ addToValues(pos, depth, value, last);
+}
+
+void LogEvent::parseKeyValuePairs(int32_t* pos, int32_t depth, bool* last) {
+ int32_t numPairs = readNextValue<uint8_t>();
+
+ for (pos[1] = 1; pos[1] <= numPairs; pos[1]++) {
+ last[1] = (pos[1] == numPairs);
+
+ // parse key
+ pos[2] = 1;
+ parseInt32(pos, 2, last);
+
+ // parse value
+ last[2] = true;
+ uint8_t typeId = getTypeId(readNextValue<uint8_t>());
+ switch (typeId) {
+ case INT32_TYPE:
+ pos[2] = 2; // pos[2] determined by index of type in KeyValuePair in atoms.proto
+ parseInt32(pos, 2, last);
+ break;
+ case INT64_TYPE:
+ pos[2] = 3;
+ parseInt64(pos, 2, last);
+ break;
+ case STRING_TYPE:
+ pos[2] = 4;
+ parseString(pos, 2, last);
+ break;
+ case FLOAT_TYPE:
+ pos[2] = 5;
+ parseFloat(pos, 2, last);
+ break;
+ default:
+ mValid = false;
+ }
+ }
+
+ pos[1] = pos[2] = 1;
+ last[1] = last[2] = false;
+}
+
+void LogEvent::parseAttributionChain(int32_t* pos, int32_t depth, bool* last) {
+ int32_t numNodes = readNextValue<uint8_t>();
+ for (pos[1] = 1; pos[1] <= numNodes; pos[1]++) {
+ last[1] = (pos[1] == numNodes);
+
+ // parse uid
+ pos[2] = 1;
+ parseInt32(pos, 2, last);
+
+ // parse tag
+ pos[2] = 2;
+ last[2] = true;
+ parseString(pos, 2, last);
+ }
+
+ pos[1] = pos[2] = 1;
+ last[1] = last[2] = false;
+}
+
+
+// This parsing logic is tied to the encoding scheme used in StatsEvent.java and
+// stats_event.c
+void LogEvent::initNew() {
+ int32_t pos[] = {1, 1, 1};
+ bool last[] = {false, false, false};
+
+ // Beginning of buffer is OBJECT_TYPE | NUM_FIELDS | TIMESTAMP | ATOM_ID
+ uint8_t typeInfo = readNextValue<uint8_t>();
+ if (getTypeId(typeInfo) != OBJECT_TYPE) mValid = false;
+
+ uint8_t numElements = readNextValue<uint8_t>();
+ if (numElements < 2 || numElements > 127) mValid = false;
+
+ typeInfo = readNextValue<uint8_t>();
+ if (getTypeId(typeInfo) != INT64_TYPE) mValid = false;
+ mElapsedTimestampNs = readNextValue<int64_t>();
+ numElements--;
+
+ typeInfo = readNextValue<uint8_t>();
+ if (getTypeId(typeInfo) != INT32_TYPE) mValid = false;
+ mTagId = readNextValue<int32_t>();
+ numElements--;
+
+
+ for (pos[0] = 1; pos[0] <= numElements && mValid; pos[0]++) {
+ typeInfo = readNextValue<uint8_t>();
+ uint8_t typeId = getTypeId(typeInfo);
+
+ last[0] = (pos[0] == numElements);
+
+ // TODO(b/144373276): handle errors passed to the socket
+ // TODO(b/144373257): parse annotations
+ switch(typeId) {
+ case BOOL_TYPE:
+ parseBool(pos, 0, last);
+ break;
+ case INT32_TYPE:
+ parseInt32(pos, 0, last);
+ break;
+ case INT64_TYPE:
+ parseInt64(pos, 0, last);
+ break;
+ case FLOAT_TYPE:
+ parseFloat(pos, 0, last);
+ break;
+ case BYTE_ARRAY_TYPE:
+ parseByteArray(pos, 0, last);
+ break;
+ case STRING_TYPE:
+ parseString(pos, 0, last);
+ break;
+ case KEY_VALUE_PAIRS_TYPE:
+ parseKeyValuePairs(pos, 0, last);
+ break;
+ case ATTRIBUTION_CHAIN_TYPE:
+ parseAttributionChain(pos, 0, last);
+ break;
+ default:
+ mValid = false;
+ }
+ }
+
+ if (mRemainingLen != 0) mValid = false;
+ mBuf = nullptr;
+}
+
+uint8_t LogEvent::getTypeId(uint8_t typeInfo) {
+ return typeInfo & 0x0F; // type id in lower 4 bytes
+}
+
+uint8_t LogEvent::getNumAnnotations(uint8_t typeInfo) {
+ return (typeInfo >> 4) & 0x0F;
+}
+
/**
* The elements of each log event are stored as a vector of android_log_list_elements.
* The goal is to do as little preprocessing as possible, because we read a tiny fraction
diff --git a/cmds/statsd/src/logd/LogEvent.h b/cmds/statsd/src/logd/LogEvent.h
index f1f45a2d3bc7..1ff95f7240ac 100644
--- a/cmds/statsd/src/logd/LogEvent.h
+++ b/cmds/statsd/src/logd/LogEvent.h
@@ -24,6 +24,7 @@
#include <log/log_read.h>
#include <private/android_logger.h>
#include <stats_event_list.h>
+#include <stats_event.h>
#include <utils/Errors.h>
#include <string>
@@ -69,9 +70,9 @@ struct InstallTrainInfo {
class LogEvent {
public:
/**
- * Read a LogEvent from a log_msg.
+ * Read a LogEvent from the socket
*/
- explicit LogEvent(log_msg& msg);
+ explicit LogEvent(uint8_t* msg, uint32_t len, uint32_t uid);
/**
* Creates LogEvent from StatsLogEventWrapper.
@@ -206,6 +207,10 @@ public:
return &mValues;
}
+ bool isValid() {
+ return mValid;
+ }
+
inline LogEvent makeCopy() {
return LogEvent(*this);
}
@@ -216,6 +221,69 @@ private:
*/
LogEvent(const LogEvent&);
+
+ /**
+ * Parsing function for new encoding scheme.
+ */
+ void initNew();
+
+ void parseInt32(int32_t* pos, int32_t depth, bool* last);
+ void parseInt64(int32_t* pos, int32_t depth, bool* last);
+ void parseString(int32_t* pos, int32_t depth, bool* last);
+ void parseFloat(int32_t* pos, int32_t depth, bool* last);
+ void parseBool(int32_t* pos, int32_t depth, bool* last);
+ void parseByteArray(int32_t* pos, int32_t depth, bool* last);
+ void parseKeyValuePairs(int32_t* pos, int32_t depth, bool* last);
+ void parseAttributionChain(int32_t* pos, int32_t depth, bool* last);
+
+ /**
+ * mBuf is a pointer to the current location in the buffer being parsed.
+ * Because the buffer lives on the StatsSocketListener stack, this pointer
+ * is only valid during the LogEvent constructor. It will be set to null at
+ * the end of initNew.
+ */
+ uint8_t* mBuf;
+
+ uint32_t mRemainingLen; // number of valid bytes left in the buffer being parsed
+ bool mValid = true; // stores whether the event we received from the socket is valid
+
+ /**
+ * Side-effects:
+ * If there is enough space in buffer to read value of type T
+ * - move mBuf past the value that was just read
+ * - decrement mRemainingLen by size of T
+ * Else
+ * - set mValid to false
+ */
+ template <class T>
+ T readNextValue() {
+ T value;
+ if (mRemainingLen < sizeof(T)) {
+ mValid = false;
+ value = 0; // all primitive types can successfully cast 0
+ } else {
+ value = *((T*)mBuf);
+ mBuf += sizeof(T);
+ mRemainingLen -= sizeof(T);
+ }
+ return value;
+ }
+
+ template <class T>
+ void addToValues(int32_t* pos, int32_t depth, T& value, bool* last) {
+ Field f = Field(mTagId, pos, depth);
+ // do not decorate last position at depth 0
+ for (int i = 1; i < depth; i++) {
+ if (last[i]) f.decorateLastPos(i);
+ }
+
+ Value v = Value(value);
+ mValues.push_back(FieldValue(f, v));
+ }
+
+ uint8_t getTypeId(uint8_t typeInfo);
+ uint8_t getNumAnnotations(uint8_t typeInfo);
+
/**
* Parses a log_msg into a LogEvent object.
*/
diff --git a/cmds/statsd/src/socket/StatsSocketListener.cpp b/cmds/statsd/src/socket/StatsSocketListener.cpp
index b59d88dc1cea..4308a1107039 100755
--- a/cmds/statsd/src/socket/StatsSocketListener.cpp
+++ b/cmds/statsd/src/socket/StatsSocketListener.cpp
@@ -39,8 +39,6 @@ namespace android {
namespace os {
namespace statsd {
-static const int kLogMsgHeaderSize = 28;
-
StatsSocketListener::StatsSocketListener(std::shared_ptr<LogEventQueue> queue)
: SocketListener(getLogSocket(), false /*start listen*/), mQueue(queue) {
}
@@ -95,7 +93,7 @@ bool StatsSocketListener::onDataAvailable(SocketClient* cli) {
cred->uid = DEFAULT_OVERFLOWUID;
}
- char* ptr = ((char*)buffer) + sizeof(android_log_header_t);
+ uint8_t* ptr = ((uint8_t*)buffer) + sizeof(android_log_header_t);
n -= sizeof(android_log_header_t);
// When a log failed to write to statsd socket (e.g., due ot EBUSY), a special message would
@@ -124,18 +122,13 @@ bool StatsSocketListener::onDataAvailable(SocketClient* cli) {
}
}
- log_msg msg;
-
- msg.entry.len = n;
- msg.entry.hdr_size = kLogMsgHeaderSize;
- msg.entry.sec = time(nullptr);
- msg.entry.pid = cred->pid;
- msg.entry.uid = cred->uid;
-
- memcpy(msg.buf + kLogMsgHeaderSize, ptr, n + 1);
+ // move past the 4-byte StatsEventTag
+ uint8_t* msg = ptr + sizeof(uint32_t);
+ uint32_t len = n - sizeof(uint32_t);
+ uint32_t uid = cred->uid;
int64_t oldestTimestamp;
- if (!mQueue->push(std::make_unique<LogEvent>(msg), &oldestTimestamp)) {
+ if (!mQueue->push(std::make_unique<LogEvent>(msg, len, uid), &oldestTimestamp)) {
StatsdStats::getInstance().noteEventQueueOverflow(oldestTimestamp);
}
diff --git a/cmds/statsd/tests/LogEvent_test.cpp b/cmds/statsd/tests/LogEvent_test.cpp
index 0743480bf4ee..9f50701d5e9e 100644
--- a/cmds/statsd/tests/LogEvent_test.cpp
+++ b/cmds/statsd/tests/LogEvent_test.cpp
@@ -17,6 +17,8 @@
#include <log/log_event_list.h>
#include "frameworks/base/cmds/statsd/src/atoms.pb.h"
#include "frameworks/base/core/proto/android/stats/launcher/launcher.pb.h"
+#include <stats_event.h>
+
#ifdef __ANDROID__
@@ -25,9 +27,277 @@ namespace os {
namespace statsd {
using std::string;
+using std::vector;
using util::ProtoOutputStream;
using util::ProtoReader;
+
+#ifdef NEW_ENCODING_SCHEME
+
+Field getField(int32_t tag, const vector<int32_t>& pos, int32_t depth, const vector<bool>& last) {
+ Field f(tag, (int32_t*)pos.data(), depth);
+
+ // For loop starts at 1 because the last field at depth 0 is not decorated.
+ for (int i = 1; i < depth; i++) {
+ if (last[i]) f.decorateLastPos(i);
+ }
+
+ return f;
+}
+
+TEST(LogEventTest, TestPrimitiveParsing) {
+ struct stats_event* event = stats_event_obtain();
+ stats_event_set_atom_id(event, 100);
+ stats_event_write_int32(event, 10);
+ stats_event_write_int64(event, 0x123456789);
+ stats_event_write_float(event, 2.0);
+ stats_event_write_bool(event, true);
+ stats_event_build(event);
+
+ size_t size;
+ uint8_t* buf = stats_event_get_buffer(event, &size);
+
+ LogEvent logEvent(buf, size, /*uid=*/ 1000);
+ EXPECT_TRUE(logEvent.isValid());
+ EXPECT_EQ(100, logEvent.GetTagId());
+
+ const vector<FieldValue>& values = logEvent.getValues();
+ EXPECT_EQ(4, values.size());
+
+ const FieldValue& int32Item = values[0];
+ Field expectedField = getField(100, {1, 1, 1}, 0, {false, false, false});
+ EXPECT_EQ(expectedField, int32Item.mField);
+ EXPECT_EQ(Type::INT, int32Item.mValue.getType());
+ EXPECT_EQ(10, int32Item.mValue.int_value);
+
+ const FieldValue& int64Item = values[1];
+ expectedField = getField(100, {2, 1, 1}, 0, {false, false, false});
+ EXPECT_EQ(expectedField, int64Item.mField);
+ EXPECT_EQ(Type::LONG, int64Item.mValue.getType());
+ EXPECT_EQ(0x123456789, int64Item.mValue.long_value);
+
+ const FieldValue& floatItem = values[2];
+ expectedField = getField(100, {3, 1, 1}, 0, {false, false, false});
+ EXPECT_EQ(expectedField, floatItem.mField);
+ EXPECT_EQ(Type::FLOAT, floatItem.mValue.getType());
+ EXPECT_EQ(2.0, floatItem.mValue.float_value);
+
+ const FieldValue& boolItem = values[3];
+ expectedField = getField(100, {4, 1, 1}, 0, {true, false, false});
+ EXPECT_EQ(expectedField, boolItem.mField);
+ EXPECT_EQ(Type::INT, boolItem.mValue.getType()); // FieldValue does not support boolean type
+ EXPECT_EQ(1, boolItem.mValue.int_value);
+
+ stats_event_release(event);
+}
+
+
+TEST(LogEventTest, TestStringAndByteArrayParsing) {
+ struct stats_event* event = stats_event_obtain();
+ stats_event_set_atom_id(event, 100);
+ string str = "test";
+ stats_event_write_string8(event, str.c_str());
+ stats_event_write_byte_array(event, (uint8_t*)str.c_str(), str.length());
+ stats_event_build(event);
+
+ size_t size;
+ uint8_t* buf = stats_event_get_buffer(event, &size);
+
+ LogEvent logEvent(buf, size, /*uid=*/ 1000);
+ EXPECT_TRUE(logEvent.isValid());
+ EXPECT_EQ(100, logEvent.GetTagId());
+
+ const vector<FieldValue>& values = logEvent.getValues();
+ EXPECT_EQ(2, values.size());
+
+ const FieldValue& stringItem = values[0];
+ Field expectedField = getField(100, {1, 1, 1}, 0, {false, false, false});
+ EXPECT_EQ(expectedField, stringItem.mField);
+ EXPECT_EQ(Type::STRING, stringItem.mValue.getType());
+ EXPECT_EQ(str, stringItem.mValue.str_value);
+
+ const FieldValue& storageItem = values[1];
+ expectedField = getField(100, {2, 1, 1}, 0, {true, false, false});
+ EXPECT_EQ(expectedField, storageItem.mField);
+ EXPECT_EQ(Type::STORAGE, storageItem.mValue.getType());
+ vector<uint8_t> expectedValue = {'t', 'e', 's', 't'};
+ EXPECT_EQ(expectedValue, storageItem.mValue.storage_value);
+
+ stats_event_release(event);
+}
+
+TEST(LogEventTest, TestEmptyString) {
+ struct stats_event* event = stats_event_obtain();
+ stats_event_set_atom_id(event, 100);
+ string empty = "";
+ stats_event_write_string8(event, empty.c_str());
+ stats_event_build(event);
+
+ size_t size;
+ uint8_t* buf = stats_event_get_buffer(event, &size);
+
+ LogEvent logEvent(buf, size, /*uid=*/ 1000);
+ EXPECT_TRUE(logEvent.isValid());
+ EXPECT_EQ(100, logEvent.GetTagId());
+
+ const vector<FieldValue>& values = logEvent.getValues();
+ EXPECT_EQ(1, values.size());
+
+ const FieldValue& item = values[0];
+ Field expectedField = getField(100, {1, 1, 1}, 0, {true, false, false});
+ EXPECT_EQ(expectedField, item.mField);
+ EXPECT_EQ(Type::STRING, item.mValue.getType());
+ EXPECT_EQ(empty, item.mValue.str_value);
+
+ stats_event_release(event);
+}
+
+TEST(LogEventTest, TestByteArrayWithNullCharacter) {
+ struct stats_event* event = stats_event_obtain();
+ stats_event_set_atom_id(event, 100);
+ uint8_t message[] = {'\t', 'e', '\0', 's', 't'};
+ stats_event_write_byte_array(event, message, 5);
+ stats_event_build(event);
+
+ size_t size;
+ uint8_t* buf = stats_event_get_buffer(event, &size);
+
+ LogEvent logEvent(buf, size, /*uid=*/ 1000);
+ EXPECT_TRUE(logEvent.isValid());
+ EXPECT_EQ(100, logEvent.GetTagId());
+
+ const vector<FieldValue>& values = logEvent.getValues();
+ EXPECT_EQ(1, values.size());
+
+ const FieldValue& item = values[0];
+ Field expectedField = getField(100, {1, 1, 1}, 0, {true, false, false});
+ EXPECT_EQ(expectedField, item.mField);
+ EXPECT_EQ(Type::STORAGE, item.mValue.getType());
+ vector<uint8_t> expectedValue(message, message + 5);
+ EXPECT_EQ(expectedValue, item.mValue.storage_value);
+
+ stats_event_release(event);
+}
+
+TEST(LogEventTest, TestKeyValuePairs) {
+ struct stats_event* event = stats_event_obtain();
+ stats_event_set_atom_id(event, 100);
+
+ struct key_value_pair pairs[4];
+ pairs[0] = {.key = 0, .valueType = INT32_TYPE, .int32Value = 1};
+ pairs[1] = {.key = 1, .valueType = INT64_TYPE, .int64Value = 0x123456789};
+ pairs[2] = {.key = 2, .valueType = FLOAT_TYPE, .floatValue = 2.0};
+ string str = "test";
+ pairs[3] = {.key = 3, .valueType = STRING_TYPE, .stringValue = str.c_str()};
+
+ stats_event_write_key_value_pairs(event, pairs, 4);
+ stats_event_build(event);
+
+ size_t size;
+ uint8_t* buf = stats_event_get_buffer(event, &size);
+
+ LogEvent logEvent(buf, size, /*uid=*/ 1000);
+ EXPECT_TRUE(logEvent.isValid());
+ EXPECT_EQ(100, logEvent.GetTagId());
+
+ const vector<FieldValue>& values = logEvent.getValues();
+ EXPECT_EQ(8, values.size()); // 2 FieldValues per key-value pair
+
+ // Check the keys first
+ for (int i = 0; i < values.size() / 2; i++) {
+ const FieldValue& item = values[2 * i];
+ int32_t depth1Pos = i + 1;
+ bool depth1Last = i == (values.size() / 2 - 1);
+ Field expectedField = getField(100, {1, depth1Pos, 1}, 2, {true, depth1Last, false});
+
+ EXPECT_EQ(expectedField, item.mField);
+ EXPECT_EQ(Type::INT, item.mValue.getType());
+ EXPECT_EQ(i, item.mValue.int_value);
+ }
+
+ // Check the values now
+ // Note: pos[2] = index of type in KeyValuePair in atoms.proto
+ const FieldValue& int32Item = values[1];
+ Field expectedField = getField(100, {1, 1, 2}, 2, {true, false, true});
+ EXPECT_EQ(expectedField, int32Item.mField);
+ EXPECT_EQ(Type::INT, int32Item.mValue.getType());
+ EXPECT_EQ(1, int32Item.mValue.int_value);
+
+ const FieldValue& int64Item = values[3];
+ expectedField = getField(100, {1, 2, 3}, 2, {true, false, true});
+ EXPECT_EQ(expectedField, int64Item.mField);
+ EXPECT_EQ(Type::LONG, int64Item.mValue.getType());
+ EXPECT_EQ(0x123456789, int64Item.mValue.long_value);
+
+ const FieldValue& floatItem = values[5];
+ expectedField = getField(100, {1, 3, 5}, 2, {true, false, true});
+ EXPECT_EQ(expectedField, floatItem.mField);
+ EXPECT_EQ(Type::FLOAT, floatItem.mValue.getType());
+ EXPECT_EQ(2.0, floatItem.mValue.float_value);
+
+ const FieldValue& stringItem = values[7];
+ expectedField = getField(100, {1, 4, 4}, 2, {true, true, true});
+ EXPECT_EQ(expectedField, stringItem.mField);
+ EXPECT_EQ(Type::STRING, stringItem.mValue.getType());
+ EXPECT_EQ(str, stringItem.mValue.str_value);
+
+ stats_event_release(event);
+}
+
+TEST(LogEventTest, TestAttributionChain) {
+ struct stats_event* event = stats_event_obtain();
+ stats_event_set_atom_id(event, 100);
+
+ string tag1 = "tag1";
+ string tag2 = "tag2";
+
+ uint32_t uids[] = {1001, 1002};
+ const char* tags[] = {tag1.c_str(), tag2.c_str()};
+
+ stats_event_write_attribution_chain(event, uids, tags, 2);
+ stats_event_build(event);
+
+ size_t size;
+ uint8_t* buf = stats_event_get_buffer(event, &size);
+
+ LogEvent logEvent(buf, size, /*uid=*/ 1000);
+ EXPECT_TRUE(logEvent.isValid());
+ EXPECT_EQ(100, logEvent.GetTagId());
+
+ const vector<FieldValue>& values = logEvent.getValues();
+ EXPECT_EQ(4, values.size()); // 2 per attribution node
+
+ // Check first attribution node
+ const FieldValue& uid1Item = values[0];
+ Field expectedField = getField(100, {1, 1, 1}, 2, {true, false, false});
+ EXPECT_EQ(expectedField, uid1Item.mField);
+ EXPECT_EQ(Type::INT, uid1Item.mValue.getType());
+ EXPECT_EQ(1001, uid1Item.mValue.int_value);
+
+ const FieldValue& tag1Item = values[1];
+ expectedField = getField(100, {1, 1, 2}, 2, {true, false, true});
+ EXPECT_EQ(expectedField, tag1Item.mField);
+ EXPECT_EQ(Type::STRING, tag1Item.mValue.getType());
+ EXPECT_EQ(tag1, tag1Item.mValue.str_value);
+
+ // Check second attribution nodes
+ const FieldValue& uid2Item = values[2];
+ expectedField = getField(100, {1, 2, 1}, 2, {true, true, false});
+ EXPECT_EQ(expectedField, uid2Item.mField);
+ EXPECT_EQ(Type::INT, uid2Item.mValue.getType());
+ EXPECT_EQ(1002, uid2Item.mValue.int_value);
+
+ const FieldValue& tag2Item = values[3];
+ expectedField = getField(100, {1, 2, 2}, 2, {true, true, true});
+ EXPECT_EQ(expectedField, tag2Item.mField);
+ EXPECT_EQ(Type::STRING, tag2Item.mValue.getType());
+ EXPECT_EQ(tag2, tag2Item.mValue.str_value);
+
+ stats_event_release(event);
+}
+
+#else // NEW_ENCODING_SCHEME
+
TEST(LogEventTest, TestLogParsing) {
LogEvent event1(1, 2000);
@@ -659,6 +929,7 @@ TEST(LogEventTest, TestWriteExperimentIdsToProto) {
EXPECT_EQ(proto[1], 0xae);
EXPECT_EQ(proto[2], 0x27);
}
+#endif // NEW_ENCODING_SCHEME
} // namespace statsd
diff --git a/core/TEST_MAPPING b/core/TEST_MAPPING
new file mode 100644
index 000000000000..fd571c95f568
--- /dev/null
+++ b/core/TEST_MAPPING
@@ -0,0 +1,24 @@
+{
+ "presubmit": [
+ {
+ "name": "FrameworksCoreTests",
+ "options": [
+ {
+ "include-filter": "android.view.inputmethod"
+ },
+ {
+ "include-filter": "com.android.internal.inputmethod"
+ },
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ }
+ ],
+ "file_patterns": [
+ "core/java/com/android/internal/inputmethod/.*",
+ "core/java/android/view/inputmethod/.*",
+ "core/tests/coretests/src/android/view/inputmethod/.*",
+ "core/tests/coretests/src/com/android/internal/inputmethod/.*"
+ ]
+ }
+ ]
+}
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index f54e841fd2a0..6bea68b446a4 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -769,17 +769,6 @@ public class Activity extends ContextThemeWrapper
private static final String KEYBOARD_SHORTCUTS_RECEIVER_PKG_NAME = "com.android.systemui";
- private static final int LOG_AM_ON_CREATE_CALLED = 30057;
- private static final int LOG_AM_ON_START_CALLED = 30059;
- private static final int LOG_AM_ON_RESUME_CALLED = 30022;
- private static final int LOG_AM_ON_PAUSE_CALLED = 30021;
- private static final int LOG_AM_ON_STOP_CALLED = 30049;
- private static final int LOG_AM_ON_RESTART_CALLED = 30058;
- private static final int LOG_AM_ON_DESTROY_CALLED = 30060;
- private static final int LOG_AM_ON_ACTIVITY_RESULT_CALLED = 30062;
- private static final int LOG_AM_ON_TOP_RESUMED_GAINED_CALLED = 30064;
- private static final int LOG_AM_ON_TOP_RESUMED_LOST_CALLED = 30065;
-
private static class ManagedDialog {
Dialog mDialog;
Bundle mArgs;
@@ -1863,8 +1852,13 @@ public class Activity extends ContextThemeWrapper
final void performTopResumedActivityChanged(boolean isTopResumedActivity, String reason) {
onTopResumedActivityChanged(isTopResumedActivity);
- writeEventLog(isTopResumedActivity
- ? LOG_AM_ON_TOP_RESUMED_GAINED_CALLED : LOG_AM_ON_TOP_RESUMED_LOST_CALLED, reason);
+ if (isTopResumedActivity) {
+ EventLogTags.writeWmOnTopResumedGainedCalled(mIdent, getComponentName().getClassName(),
+ reason);
+ } else {
+ EventLogTags.writeWmOnTopResumedLostCalled(mIdent, getComponentName().getClassName(),
+ reason);
+ }
}
void setVoiceInteractor(IVoiceInteractor voiceInteractor) {
@@ -7898,7 +7892,8 @@ public class Activity extends ContextThemeWrapper
} else {
onCreate(icicle);
}
- writeEventLog(LOG_AM_ON_CREATE_CALLED, "performCreate");
+ EventLogTags.writeWmOnCreateCalled(mIdent, getComponentName().getClassName(),
+ "performCreate");
mActivityTransitionState.readState(icicle);
mVisibleFromClient = !mWindow.getWindowStyle().getBoolean(
@@ -7920,7 +7915,7 @@ public class Activity extends ContextThemeWrapper
mCalled = false;
mFragments.execPendingActions();
mInstrumentation.callActivityOnStart(this);
- writeEventLog(LOG_AM_ON_START_CALLED, reason);
+ EventLogTags.writeWmOnStartCalled(mIdent, getComponentName().getClassName(), reason);
if (!mCalled) {
throw new SuperNotCalledException(
@@ -7998,7 +7993,7 @@ public class Activity extends ContextThemeWrapper
mCalled = false;
mInstrumentation.callActivityOnRestart(this);
- writeEventLog(LOG_AM_ON_RESTART_CALLED, reason);
+ EventLogTags.writeWmOnRestartCalled(mIdent, getComponentName().getClassName(), reason);
if (!mCalled) {
throw new SuperNotCalledException(
"Activity " + mComponent.toShortString() +
@@ -8031,7 +8026,7 @@ public class Activity extends ContextThemeWrapper
mCalled = false;
// mResumed is set by the instrumentation
mInstrumentation.callActivityOnResume(this);
- writeEventLog(LOG_AM_ON_RESUME_CALLED, reason);
+ EventLogTags.writeWmOnResumeCalled(mIdent, getComponentName().getClassName(), reason);
if (!mCalled) {
throw new SuperNotCalledException(
"Activity " + mComponent.toShortString() +
@@ -8070,7 +8065,8 @@ public class Activity extends ContextThemeWrapper
mFragments.dispatchPause();
mCalled = false;
onPause();
- writeEventLog(LOG_AM_ON_PAUSE_CALLED, "performPause");
+ EventLogTags.writeWmOnPausedCalled(mIdent, getComponentName().getClassName(),
+ "performPause");
mResumed = false;
if (!mCalled && getApplicationInfo().targetSdkVersion
>= android.os.Build.VERSION_CODES.GINGERBREAD) {
@@ -8110,7 +8106,7 @@ public class Activity extends ContextThemeWrapper
mCalled = false;
mInstrumentation.callActivityOnStop(this);
- writeEventLog(LOG_AM_ON_STOP_CALLED, reason);
+ EventLogTags.writeWmOnStopCalled(mIdent, getComponentName().getClassName(), reason);
if (!mCalled) {
throw new SuperNotCalledException(
"Activity " + mComponent.toShortString() +
@@ -8140,7 +8136,8 @@ public class Activity extends ContextThemeWrapper
mWindow.destroy();
mFragments.dispatchDestroy();
onDestroy();
- writeEventLog(LOG_AM_ON_DESTROY_CALLED, "performDestroy");
+ EventLogTags.writeWmOnDestroyCalled(mIdent, getComponentName().getClassName(),
+ "performDestroy");
mFragments.doLoaderDestroy();
if (mVoiceInteractor != null) {
mVoiceInteractor.detachActivity();
@@ -8233,7 +8230,9 @@ public class Activity extends ContextThemeWrapper
frag.onActivityResult(requestCode, resultCode, data);
}
}
- writeEventLog(LOG_AM_ON_ACTIVITY_RESULT_CALLED, reason);
+
+ EventLogTags.writeWmOnActivityResultCalled(mIdent, getComponentName().getClassName(),
+ reason);
}
/**
@@ -8660,11 +8659,6 @@ public class Activity extends ContextThemeWrapper
}
}
- /** Log a lifecycle event for current user id and component class. */
- private void writeEventLog(int event, String reason) {
- EventLog.writeEvent(event, mIdent, getComponentName().getClassName(), reason);
- }
-
class HostCallbacks extends FragmentHostCallback<Activity> {
public HostCallbacks() {
super(Activity.this /*activity*/);
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 1c8f4948eb85..46f88d5c81e4 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -1362,6 +1362,18 @@ class ContextImpl extends Context {
}
@Override
+ public void sendOrderedBroadcast(Intent intent, String receiverPermission, String receiverAppOp,
+ Bundle options, BroadcastReceiver resultReceiver, Handler scheduler, int initialCode,
+ String initialData, @Nullable Bundle initialExtras) {
+ int intAppOp = AppOpsManager.OP_NONE;
+ if (!TextUtils.isEmpty(receiverAppOp)) {
+ intAppOp = AppOpsManager.strOpToOp(receiverAppOp);
+ }
+ sendOrderedBroadcastAsUser(intent, getUser(), receiverPermission, intAppOp, options,
+ resultReceiver, scheduler, initialCode, initialData, initialExtras);
+ }
+
+ @Override
@Deprecated
public void sendStickyBroadcast(Intent intent) {
warnIfCallingFromSystemProcess();
diff --git a/core/java/android/app/EventLogTags.logtags b/core/java/android/app/EventLogTags.logtags
new file mode 100644
index 000000000000..6296a689b6dd
--- /dev/null
+++ b/core/java/android/app/EventLogTags.logtags
@@ -0,0 +1,36 @@
+# See system/core/logcat/event.logtags for a description of the format of this file.
+
+option java_package android.app
+
+# Do not change these names without updating the checkin_events setting in
+# google3/googledata/wireless/android/provisioning/gservices.config !!
+#
+# The activity's onPause has been called.
+30021 wm_on_paused_called (Token|1|5),(Component Name|3),(Reason|3)
+# The activity's onResume has been called.
+30022 wm_on_resume_called (Token|1|5),(Component Name|3),(Reason|3)
+
+# Attempting to stop an activity
+30048 wm_stop_activity (User|1|5),(Token|1|5),(Component Name|3)
+# The activity's onStop has been called.
+30049 wm_on_stop_called (Token|1|5),(Component Name|3),(Reason|3)
+
+# The activity's onCreate has been called.
+30057 wm_on_create_called (Token|1|5),(Component Name|3),(Reason|3)
+# The activity's onRestart has been called.
+30058 wm_on_restart_called (Token|1|5),(Component Name|3),(Reason|3)
+# The activity's onStart has been called.
+30059 wm_on_start_called (Token|1|5),(Component Name|3),(Reason|3)
+# The activity's onDestroy has been called.
+30060 wm_on_destroy_called (Token|1|5),(Component Name|3),(Reason|3)
+# The activity's onActivityResult has been called.
+30062 wm_on_activity_result_called (Token|1|5),(Component Name|3),(Reason|3)
+
+# The activity's onTopResumedActivityChanged(true) has been called.
+30064 wm_on_top_resumed_gained_called (Token|1|5),(Component Name|3),(Reason|3)
+# The activity's onTopResumedActivityChanged(false) has been called.
+30065 wm_on_top_resumed_lost_called (Token|1|5),(Component Name|3),(Reason|3)
+
+# An activity been add into stopping list
+30066 wm_add_to_stopping (User|1|5),(Token|1|5),(Component Name|3),(Reason|3)
+
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index 9aca22360fd8..0957dba4eac1 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -21,6 +21,7 @@ import android.app.ITransientNotification;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationChannelGroup;
+import android.app.NotificationHistory;
import android.app.NotificationManager;
import android.content.ComponentName;
import android.content.Intent;
@@ -119,6 +120,8 @@ interface INotificationManager
@UnsupportedAppUsage
StatusBarNotification[] getHistoricalNotifications(String callingPkg, int count);
+ NotificationHistory getNotificationHistory(String callingPkg);
+
void registerListener(in INotificationListener listener, in ComponentName component, int userid);
void unregisterListener(in INotificationListener listener, int userid);
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 0bfd2c6f5f70..1829f74700fd 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -19,6 +19,7 @@ package android.app;
import android.accounts.AccountManager;
import android.accounts.IAccountManager;
import android.annotation.NonNull;
+import android.annotation.SystemApi;
import android.app.ContextImpl.ServiceInitializationState;
import android.app.admin.DevicePolicyManager;
import android.app.admin.IDevicePolicyManager;
@@ -33,6 +34,7 @@ import android.app.role.RoleManager;
import android.app.slice.SliceManager;
import android.app.timedetector.TimeDetector;
import android.app.timezone.RulesManager;
+import android.app.timezonedetector.TimeZoneDetector;
import android.app.trust.TrustManager;
import android.app.usage.IStorageStatsManager;
import android.app.usage.IUsageStatsManager;
@@ -193,6 +195,7 @@ import java.util.Map;
*
* @hide
*/
+@SystemApi
public final class SystemServiceRegistry {
private static final String TAG = "SystemServiceRegistry";
@@ -1123,6 +1126,14 @@ public final class SystemServiceRegistry {
return new TimeDetector();
}});
+ registerService(Context.TIME_ZONE_DETECTOR_SERVICE, TimeZoneDetector.class,
+ new CachedServiceFetcher<TimeZoneDetector>() {
+ @Override
+ public TimeZoneDetector createService(ContextImpl ctx)
+ throws ServiceNotFoundException {
+ return new TimeZoneDetector();
+ }});
+
registerService(Context.PERMISSION_SERVICE, PermissionManager.class,
new CachedServiceFetcher<PermissionManager>() {
@Override
@@ -1191,7 +1202,6 @@ public final class SystemServiceRegistry {
try {
// Note: the following functions need to be @SystemApis, once they become mainline
// modules.
-
JobSchedulerFrameworkInitializer.registerServiceWrappers();
BlobStoreManagerFrameworkInitializer.initialize();
TelephonyFrameworkInitializer.registerServiceWrappers();
@@ -1246,18 +1256,20 @@ public final class SystemServiceRegistry {
/**
* Callback interface used as a parameter to {@link #registerStaticService(
- * String, Class, StaticServiceProducerNoBinder)}, which generates a service wrapper instance
- * that's not tied to any context and does not take a service binder object in the constructor.
+ * String, Class, StaticServiceProducerWithoutBinder)}, which generates a service wrapper
+ * instance that's not tied to any context and does not take a service binder object in the
+ * constructor.
*
* @param <TServiceClass> type of the service wrapper class.
*
* @hide
*/
- //@SystemApi TODO Make it a system API.
- public interface StaticServiceProducerNoBinder<TServiceClass> {
+ @SystemApi
+ public interface StaticServiceProducerWithoutBinder<TServiceClass> {
/**
* Return a new service wrapper of type {@code TServiceClass}.
*/
+ @NonNull
TServiceClass createService();
}
@@ -1270,18 +1282,19 @@ public final class SystemServiceRegistry {
*
* @hide
*/
- //@SystemApi TODO Make it a system API.
+ @SystemApi
public interface StaticServiceProducerWithBinder<TServiceClass> {
/**
* Return a new service wrapper of type {@code TServiceClass} backed by a given
* service binder object.
*/
- TServiceClass createService(IBinder serviceBinder);
+ @NonNull
+ TServiceClass createService(@NonNull IBinder serviceBinder);
}
/**
* Callback interface used as a parameter to {@link #registerContextAwareService(
- * String, Class, ContextAwareServiceProducerNoBinder)},
+ * String, Class, ContextAwareServiceProducerWithoutBinder)},
* which generates a service wrapper instance
* that's tied to a specific context and does not take a service binder object in the
* constructor.
@@ -1290,15 +1303,15 @@ public final class SystemServiceRegistry {
*
* @hide
*/
- //@SystemApi TODO Make it a system API.
- public interface ContextAwareServiceProducerNoBinder<TServiceClass> {
+ @SystemApi
+ public interface ContextAwareServiceProducerWithoutBinder<TServiceClass> {
/**
* Return a new service wrapper of type {@code TServiceClass} tied to a given
* {@code context}.
- *
- * TODO Do we need to pass the "base context" too?
*/
- TServiceClass createService(Context context);
+ @NonNull
+ //TODO Do we need to pass the "base context" too?
+ TServiceClass createService(@NonNull Context context);
}
/**
@@ -1311,15 +1324,15 @@ public final class SystemServiceRegistry {
*
* @hide
*/
- //@SystemApi TODO Make it a system API.
+ @SystemApi
public interface ContextAwareServiceProducerWithBinder<TServiceClass> {
/**
* Return a new service wrapper of type {@code TServiceClass} backed by a given
* service binder object that's tied to a given {@code context}.
- *
- * TODO Do we need to pass the "base context" too?
*/
- TServiceClass createService(Context context, IBinder serviceBinder);
+ @NonNull
+ //TODO Do we need to pass the "base context" too?
+ TServiceClass createService(@NonNull Context context, @NonNull IBinder serviceBinder);
}
/**
@@ -1337,7 +1350,7 @@ public final class SystemServiceRegistry {
*
* @hide
*/
- //@SystemApi TODO Make it a system API.
+ @SystemApi
public static <TServiceClass> void registerStaticService(
@NonNull String serviceName, @NonNull Class<TServiceClass> serviceWrapperClass,
@NonNull StaticServiceProducerWithBinder<TServiceClass> serviceProducer) {
@@ -1361,10 +1374,10 @@ public final class SystemServiceRegistry {
*
* @hide
*/
- //@SystemApi TODO Make it a system API.
+ @SystemApi
public static <TServiceClass> void registerStaticService(
@NonNull String serviceName, @NonNull Class<TServiceClass> serviceWrapperClass,
- @NonNull StaticServiceProducerNoBinder<TServiceClass> serviceProducer) {
+ @NonNull StaticServiceProducerWithoutBinder<TServiceClass> serviceProducer) {
ensureInitializing("registerStaticService");
Preconditions.checkStringNotEmpty(serviceName);
Preconditions.checkNotNull(serviceWrapperClass);
@@ -1394,7 +1407,7 @@ public final class SystemServiceRegistry {
*
* @hide
*/
- //@SystemApi TODO Make it a system API.
+ @SystemApi
public static <TServiceClass> void registerContextAwareService(
@NonNull String serviceName, @NonNull Class<TServiceClass> serviceWrapperClass,
@NonNull ContextAwareServiceProducerWithBinder<TServiceClass> serviceProducer) {
@@ -1422,10 +1435,10 @@ public final class SystemServiceRegistry {
*
* @hide
*/
- //@SystemApi TODO Make it a system API.
+ @SystemApi
public static <TServiceClass> void registerContextAwareService(
@NonNull String serviceName, @NonNull Class<TServiceClass> serviceWrapperClass,
- @NonNull ContextAwareServiceProducerNoBinder<TServiceClass> serviceProducer) {
+ @NonNull ContextAwareServiceProducerWithoutBinder<TServiceClass> serviceProducer) {
ensureInitializing("registerContextAwareService");
Preconditions.checkStringNotEmpty(serviceName);
Preconditions.checkNotNull(serviceWrapperClass);
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 9a5444cfcd57..47fd87d446ff 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -6363,6 +6363,9 @@ public class DevicePolicyManager {
/**
* Sets the device owner information to be shown on the lock screen.
* <p>
+ * Device owner information set using this method overrides any owner information manually set
+ * by the user and prevents the user from further changing it.
+ * <p>
* If the device owner information is {@code null} or empty then the device owner info is
* cleared and the user owner info is shown on the lock screen if it is set.
* <p>
@@ -6372,6 +6375,8 @@ public class DevicePolicyManager {
* If the device owner information needs to be localized, it is the responsibility of the
* {@link DeviceAdminReceiver} to listen to the {@link Intent#ACTION_LOCALE_CHANGED} broadcast
* and set a new version of this string accordingly.
+ * <p>
+ * May be called by the device owner or the profile owner of an organization-owned device.
*
* @param admin The name of the admin component to check.
* @param info Device owner information which will be displayed instead of the user owner info.
@@ -10832,28 +10837,38 @@ public class DevicePolicyManager {
}
/**
- * Grants the profile owner of the given user access to device identifiers (such as
- * serial number, IMEI and MEID).
- *
- * <p>This lets the profile owner request inclusion of device identifiers when calling
- * {@link generateKeyPair}.
+ * Deprecated. Use {@code markProfileOwnerOnOrganizationOwnedDevice} instead.
+ * Throws UnsupportedOperationException when called.
*
- * <p>This grant is necessary to guarantee that profile owners can access device identifiers.
- *
- * <p>Privileged system API - meant to be called by the system, particularly the managed
- * provisioning app, when a work profile is set up.
+ * @deprecated Use {@link #markProfileOwnerOnOrganizationOwnedDevice} instead.
*
* @hide
*/
+ @Deprecated
@SystemApi
@RequiresPermission(value = android.Manifest.permission.GRANT_PROFILE_OWNER_DEVICE_IDS_ACCESS,
conditional = true)
public void setProfileOwnerCanAccessDeviceIds(@NonNull ComponentName who) {
+ throw new UnsupportedOperationException(
+ "This method is deprecated. use markProfileOwnerOnOrganizationOwnedDevice instead"
+ + ".");
+ }
+
+ /**
+ * Marks the profile owner of the given user as managing an organization-owned device.
+ * That will give it access to device identifiers (such as serial number, IMEI and MEID)
+ * as well as other privileges.
+ *
+ * @hide
+ */
+ @RequiresPermission(value = android.Manifest.permission.MARK_DEVICE_ORGANIZATION_OWNED,
+ conditional = true)
+ public void markProfileOwnerOnOrganizationOwnedDevice(@NonNull ComponentName who) {
if (mService == null) {
return;
}
try {
- mService.grantDeviceIdsAccessToProfileOwner(who, myUserId());
+ mService.markProfileOwnerOnOrganizationOwnedDevice(who, myUserId());
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
}
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 591d1510e6f4..df4b55483be5 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -426,7 +426,7 @@ interface IDevicePolicyManager {
int getGlobalPrivateDnsMode(in ComponentName admin);
String getGlobalPrivateDnsHost(in ComponentName admin);
- void grantDeviceIdsAccessToProfileOwner(in ComponentName who, int userId);
+ void markProfileOwnerOnOrganizationOwnedDevice(in ComponentName who, int userId);
void installUpdateFromFile(in ComponentName admin, in ParcelFileDescriptor updateFileDescriptor, in StartInstallingUpdateCallback listener);
diff --git a/core/java/android/app/backup/BackupManager.java b/core/java/android/app/backup/BackupManager.java
index 25caaaa6e5ad..93d1e7166708 100644
--- a/core/java/android/app/backup/BackupManager.java
+++ b/core/java/android/app/backup/BackupManager.java
@@ -34,6 +34,8 @@ import android.os.UserHandle;
import android.util.Log;
import android.util.Pair;
+import java.util.List;
+
/**
* The interface through which an application interacts with the Android backup service to
* request backup and restore operations.
@@ -948,6 +950,29 @@ public class BackupManager {
return null;
}
+ /**
+ * Excludes keys from KV restore for a given package. The corresponding data will be excluded
+ * from the data set available the backup agent during restore. However, final list of keys
+ * that have been excluded will be passed to the agent to make it aware of the exclusions.
+ *
+ * @param packageName The name of the package for which to exclude keys.
+ * @param keys The list of keys to exclude.
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.BACKUP)
+ public void excludeKeysFromRestore(@NonNull String packageName, @NonNull List<String> keys) {
+ checkServiceBinder();
+ if (sService != null) {
+ try {
+ sService.excludeKeysFromRestore(packageName, keys);
+ } catch (RemoteException e) {
+ Log.e(TAG, "excludeKeysFromRestore() couldn't connect");
+ }
+ }
+ }
+
/*
* We wrap incoming binder calls with a private class implementation that
* redirects them into main-thread actions. This serializes the backup
diff --git a/core/java/android/app/backup/IBackupManager.aidl b/core/java/android/app/backup/IBackupManager.aidl
index 2dfaad759d3f..099272d8e3ec 100644
--- a/core/java/android/app/backup/IBackupManager.aidl
+++ b/core/java/android/app/backup/IBackupManager.aidl
@@ -710,4 +710,10 @@ interface IBackupManager {
*/
void setAncestralSerialNumber(in long ancestralSerialNumber);
+ /**
+ * Excludes keys from KV restore for a given package. The corresponding data will be excluded
+ * from the data set available the backup agent during restore. However, final list of keys
+ * that have been excluded will be passed to the agent to make it aware of the exclusions.
+ */
+ void excludeKeysFromRestore(String packageName, in List<String> keys);
}
diff --git a/core/java/android/app/timedetector/ITimeDetectorService.aidl b/core/java/android/app/timedetector/ITimeDetectorService.aidl
index ddc4932d6fec..9877fc741b7b 100644
--- a/core/java/android/app/timedetector/ITimeDetectorService.aidl
+++ b/core/java/android/app/timedetector/ITimeDetectorService.aidl
@@ -16,6 +16,7 @@
package android.app.timedetector;
+import android.app.timedetector.ManualTimeSuggestion;
import android.app.timedetector.PhoneTimeSuggestion;
/**
@@ -33,4 +34,5 @@ import android.app.timedetector.PhoneTimeSuggestion;
*/
interface ITimeDetectorService {
void suggestPhoneTime(in PhoneTimeSuggestion timeSuggestion);
+ void suggestManualTime(in ManualTimeSuggestion timeSuggestion);
}
diff --git a/services/wifi/java/android/net/wifi/IWifiStackConnector.aidl b/core/java/android/app/timedetector/ManualTimeSuggestion.aidl
index 3af4666b8d9c..213940493114 100644
--- a/services/wifi/java/android/net/wifi/IWifiStackConnector.aidl
+++ b/core/java/android/app/timedetector/ManualTimeSuggestion.aidl
@@ -1,23 +1,19 @@
-/**
- * Copyright (c) 2019, The Android Open Source Project
+/*
+ * Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing perNmissions and
+ * See the License for the specific language governing permissions and
* limitations under the License.
*/
-package android.net.wifi;
-import android.net.wifi.WifiApiServiceInfo;
+package android.app.timedetector;
-/** @hide */
-interface IWifiStackConnector {
- List<WifiApiServiceInfo> getWifiApiServiceInfos();
-}
+parcelable ManualTimeSuggestion;
diff --git a/core/java/android/app/timedetector/ManualTimeSuggestion.java b/core/java/android/app/timedetector/ManualTimeSuggestion.java
new file mode 100644
index 000000000000..e7d619a27607
--- /dev/null
+++ b/core/java/android/app/timedetector/ManualTimeSuggestion.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.timedetector;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.TimestampedValue;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * A time signal from a manual (user provided) source. The value consists of the number of
+ * milliseconds elapsed since 1/1/1970 00:00:00 UTC and the time according to the elapsed realtime
+ * clock when that number was established. The elapsed realtime clock is considered accurate but
+ * volatile, so time signals must not be persisted across device resets.
+ *
+ * @hide
+ */
+public final class ManualTimeSuggestion implements Parcelable {
+
+ public static final @NonNull Creator<ManualTimeSuggestion> CREATOR =
+ new Creator<ManualTimeSuggestion>() {
+ public ManualTimeSuggestion createFromParcel(Parcel in) {
+ return ManualTimeSuggestion.createFromParcel(in);
+ }
+
+ public ManualTimeSuggestion[] newArray(int size) {
+ return new ManualTimeSuggestion[size];
+ }
+ };
+
+ @NonNull
+ private final TimestampedValue<Long> mUtcTime;
+ @Nullable
+ private ArrayList<String> mDebugInfo;
+
+ public ManualTimeSuggestion(@NonNull TimestampedValue<Long> utcTime) {
+ mUtcTime = Objects.requireNonNull(utcTime);
+ }
+
+ private static ManualTimeSuggestion createFromParcel(Parcel in) {
+ TimestampedValue<Long> utcTime = in.readParcelable(null /* classLoader */);
+ ManualTimeSuggestion suggestion = new ManualTimeSuggestion(utcTime);
+ @SuppressWarnings("unchecked")
+ ArrayList<String> debugInfo = (ArrayList<String>) in.readArrayList(null /* classLoader */);
+ suggestion.mDebugInfo = debugInfo;
+ return suggestion;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeParcelable(mUtcTime, 0);
+ dest.writeList(mDebugInfo);
+ }
+
+ @NonNull
+ public TimestampedValue<Long> getUtcTime() {
+ return mUtcTime;
+ }
+
+ @NonNull
+ public List<String> getDebugInfo() {
+ return Collections.unmodifiableList(mDebugInfo);
+ }
+
+ /**
+ * Associates information with the instance that can be useful for debugging / logging. The
+ * information is present in {@link #toString()} but is not considered for
+ * {@link #equals(Object)} and {@link #hashCode()}.
+ */
+ public void addDebugInfo(String... debugInfos) {
+ if (mDebugInfo == null) {
+ mDebugInfo = new ArrayList<>();
+ }
+ mDebugInfo.addAll(Arrays.asList(debugInfos));
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ ManualTimeSuggestion that = (ManualTimeSuggestion) o;
+ return Objects.equals(mUtcTime, that.mUtcTime);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mUtcTime);
+ }
+
+ @Override
+ public String toString() {
+ return "ManualTimeSuggestion{"
+ + "mUtcTime=" + mUtcTime
+ + ", mDebugInfo=" + mDebugInfo
+ + '}';
+ }
+}
diff --git a/core/java/android/app/timedetector/PhoneTimeSuggestion.java b/core/java/android/app/timedetector/PhoneTimeSuggestion.java
index 475a4aafd929..233dbbc42f50 100644
--- a/core/java/android/app/timedetector/PhoneTimeSuggestion.java
+++ b/core/java/android/app/timedetector/PhoneTimeSuggestion.java
@@ -29,7 +29,9 @@ import java.util.List;
import java.util.Objects;
/**
- * A time signal from a telephony source. The value consists of the number of milliseconds elapsed
+ * A time signal from a telephony source. The value can be {@code null} to indicate that the
+ * telephony source has entered an "un-opinionated" state and any previously sent suggestions are
+ * being withdrawn. When not {@code null}, the value consists of the number of milliseconds elapsed
* since 1/1/1970 00:00:00 UTC and the time according to the elapsed realtime clock when that number
* was established. The elapsed realtime clock is considered accurate but volatile, so time signals
* must not be persisted across device resets.
@@ -50,20 +52,17 @@ public final class PhoneTimeSuggestion implements Parcelable {
};
private final int mPhoneId;
- @NonNull
- private final TimestampedValue<Long> mUtcTime;
- @Nullable
- private ArrayList<String> mDebugInfo;
+ @Nullable private TimestampedValue<Long> mUtcTime;
+ @Nullable private ArrayList<String> mDebugInfo;
- public PhoneTimeSuggestion(int phoneId, @NonNull TimestampedValue<Long> utcTime) {
+ public PhoneTimeSuggestion(int phoneId) {
mPhoneId = phoneId;
- mUtcTime = Objects.requireNonNull(utcTime);
}
private static PhoneTimeSuggestion createFromParcel(Parcel in) {
int phoneId = in.readInt();
- TimestampedValue<Long> utcTime = in.readParcelable(null /* classLoader */);
- PhoneTimeSuggestion suggestion = new PhoneTimeSuggestion(phoneId, utcTime);
+ PhoneTimeSuggestion suggestion = new PhoneTimeSuggestion(phoneId);
+ suggestion.setUtcTime(in.readParcelable(null /* classLoader */));
@SuppressWarnings("unchecked")
ArrayList<String> debugInfo = (ArrayList<String>) in.readArrayList(null /* classLoader */);
suggestion.mDebugInfo = debugInfo;
@@ -86,7 +85,11 @@ public final class PhoneTimeSuggestion implements Parcelable {
return mPhoneId;
}
- @NonNull
+ public void setUtcTime(@Nullable TimestampedValue<Long> utcTime) {
+ mUtcTime = utcTime;
+ }
+
+ @Nullable
public TimestampedValue<Long> getUtcTime() {
return mUtcTime;
}
diff --git a/core/java/android/app/timedetector/TimeDetector.java b/core/java/android/app/timedetector/TimeDetector.java
index 334e9582a145..48d5cd2d65a5 100644
--- a/core/java/android/app/timedetector/TimeDetector.java
+++ b/core/java/android/app/timedetector/TimeDetector.java
@@ -17,19 +17,22 @@
package android.app.timedetector;
import android.annotation.NonNull;
+import android.annotation.RequiresPermission;
import android.annotation.SystemService;
import android.content.Context;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.ServiceManager.ServiceNotFoundException;
+import android.os.SystemClock;
import android.util.Log;
+import android.util.TimestampedValue;
/**
* The interface through which system components can send signals to the TimeDetectorService.
* @hide
*/
@SystemService(Context.TIME_DETECTOR_SERVICE)
-public final class TimeDetector {
+public class TimeDetector {
private static final String TAG = "timedetector.TimeDetector";
private static final boolean DEBUG = false;
@@ -41,10 +44,11 @@ public final class TimeDetector {
}
/**
- * Suggests the current time to the detector. The detector may ignore the signal if better
- * signals are available such as those that come from more reliable sources or were
- * determined more recently.
+ * Suggests the current phone-signal derived time to the detector. The detector may ignore the
+ * signal if better signals are available such as those that come from more reliable sources or
+ * were determined more recently.
*/
+ @RequiresPermission(android.Manifest.permission.SET_TIME)
public void suggestPhoneTime(@NonNull PhoneTimeSuggestion timeSuggestion) {
if (DEBUG) {
Log.d(TAG, "suggestPhoneTime called: " + timeSuggestion);
@@ -56,4 +60,29 @@ public final class TimeDetector {
}
}
+ /**
+ * Suggests the user's manually entered current time to the detector.
+ */
+ @RequiresPermission(android.Manifest.permission.SET_TIME)
+ public void suggestManualTime(@NonNull ManualTimeSuggestion timeSuggestion) {
+ if (DEBUG) {
+ Log.d(TAG, "suggestManualTime called: " + timeSuggestion);
+ }
+ try {
+ mITimeDetectorService.suggestManualTime(timeSuggestion);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * A shared utility method to create a {@link ManualTimeSuggestion}.
+ */
+ public static ManualTimeSuggestion createManualTimeSuggestion(long when, String why) {
+ TimestampedValue<Long> utcTime =
+ new TimestampedValue<>(SystemClock.elapsedRealtime(), when);
+ ManualTimeSuggestion manualTimeSuggestion = new ManualTimeSuggestion(utcTime);
+ manualTimeSuggestion.addDebugInfo(why);
+ return manualTimeSuggestion;
+ }
}
diff --git a/core/java/android/app/timezonedetector/ITimeZoneDetectorService.aidl b/core/java/android/app/timezonedetector/ITimeZoneDetectorService.aidl
new file mode 100644
index 000000000000..260c7df72fba
--- /dev/null
+++ b/core/java/android/app/timezonedetector/ITimeZoneDetectorService.aidl
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.timezonedetector;
+
+import android.app.timezonedetector.PhoneTimeZoneSuggestion;
+
+/**
+ * System private API to communicate with time zone detector service.
+ *
+ * <p>Used to provide information to the Time Zone Detector Service from other parts of the Android
+ * system that have access to time zone-related signals, e.g. telephony.
+ *
+ * <p>Use the {@link android.app.timezonedetector.TimeZoneDetector} class rather than going through
+ * this Binder interface directly. See {@link android.app.timezonedetector.TimeZoneDetectorService}
+ * for more complete documentation.
+ *
+ *
+ * {@hide}
+ */
+interface ITimeZoneDetectorService {
+ void suggestPhoneTimeZone(in PhoneTimeZoneSuggestion timeZoneSuggestion);
+}
diff --git a/core/java/android/app/timezonedetector/PhoneTimeZoneSuggestion.aidl b/core/java/android/app/timezonedetector/PhoneTimeZoneSuggestion.aidl
new file mode 100644
index 000000000000..3ad903bb5949
--- /dev/null
+++ b/core/java/android/app/timezonedetector/PhoneTimeZoneSuggestion.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.timezonedetector;
+
+parcelable PhoneTimeZoneSuggestion;
diff --git a/core/java/android/app/timezonedetector/PhoneTimeZoneSuggestion.java b/core/java/android/app/timezonedetector/PhoneTimeZoneSuggestion.java
new file mode 100644
index 000000000000..e8162488394c
--- /dev/null
+++ b/core/java/android/app/timezonedetector/PhoneTimeZoneSuggestion.java
@@ -0,0 +1,341 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.timezonedetector;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * A suggested time zone from a Phone-based signal, e.g. from MCC and NITZ information.
+ *
+ * @hide
+ */
+public final class PhoneTimeZoneSuggestion implements Parcelable {
+
+ @NonNull
+ public static final Creator<PhoneTimeZoneSuggestion> CREATOR =
+ new Creator<PhoneTimeZoneSuggestion>() {
+ public PhoneTimeZoneSuggestion createFromParcel(Parcel in) {
+ return PhoneTimeZoneSuggestion.createFromParcel(in);
+ }
+
+ public PhoneTimeZoneSuggestion[] newArray(int size) {
+ return new PhoneTimeZoneSuggestion[size];
+ }
+ };
+
+ /**
+ * Creates an empty time zone suggestion, i.e. one that will cancel previous suggestions with
+ * the same {@code phoneId}.
+ */
+ @NonNull
+ public static PhoneTimeZoneSuggestion createEmptySuggestion(
+ int phoneId, @NonNull String debugInfo) {
+ return new Builder(phoneId).addDebugInfo(debugInfo).build();
+ }
+
+ @IntDef({ MATCH_TYPE_NA, MATCH_TYPE_NETWORK_COUNTRY_ONLY, MATCH_TYPE_NETWORK_COUNTRY_AND_OFFSET,
+ MATCH_TYPE_EMULATOR_ZONE_ID, MATCH_TYPE_TEST_NETWORK_OFFSET_ONLY })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface MatchType {}
+
+ /** Used when match type is not applicable. */
+ public static final int MATCH_TYPE_NA = 0;
+
+ /**
+ * Only the network country is known.
+ */
+ public static final int MATCH_TYPE_NETWORK_COUNTRY_ONLY = 2;
+
+ /**
+ * Both the network county and offset were known.
+ */
+ public static final int MATCH_TYPE_NETWORK_COUNTRY_AND_OFFSET = 3;
+
+ /**
+ * The device is running in an emulator and an NITZ signal was simulated containing an
+ * Android extension with an explicit Olson ID.
+ */
+ public static final int MATCH_TYPE_EMULATOR_ZONE_ID = 4;
+
+ /**
+ * The phone is most likely running in a test network not associated with a country (this is
+ * distinct from the country just not being known yet).
+ * Historically, Android has just picked an arbitrary time zone with the correct offset when
+ * on a test network.
+ */
+ public static final int MATCH_TYPE_TEST_NETWORK_OFFSET_ONLY = 5;
+
+ @IntDef({ QUALITY_NA, QUALITY_SINGLE_ZONE, QUALITY_MULTIPLE_ZONES_WITH_SAME_OFFSET,
+ QUALITY_MULTIPLE_ZONES_WITH_DIFFERENT_OFFSETS })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Quality {}
+
+ /** Used when quality is not applicable. */
+ public static final int QUALITY_NA = 0;
+
+ /** There is only one answer */
+ public static final int QUALITY_SINGLE_ZONE = 1;
+
+ /**
+ * There are multiple answers, but they all shared the same offset / DST state at the time
+ * the suggestion was created. i.e. it might be the wrong zone but the user won't notice
+ * immediately if it is wrong.
+ */
+ public static final int QUALITY_MULTIPLE_ZONES_WITH_SAME_OFFSET = 2;
+
+ /**
+ * There are multiple answers with different offsets. The one given is just one possible.
+ */
+ public static final int QUALITY_MULTIPLE_ZONES_WITH_DIFFERENT_OFFSETS = 3;
+
+ /**
+ * The ID of the phone this suggestion is associated with. For multiple-sim devices this
+ * helps to establish origin so filtering / stickiness can be implemented.
+ */
+ private final int mPhoneId;
+
+ /**
+ * The suggestion. {@code null} means there is no current suggestion and any previous suggestion
+ * should be forgotten.
+ */
+ private final String mZoneId;
+
+ /**
+ * The type of "match" used to establish the time zone.
+ */
+ @MatchType
+ private final int mMatchType;
+
+ /**
+ * A measure of the quality of the time zone suggestion, i.e. how confident one could be in
+ * it.
+ */
+ @Quality
+ private final int mQuality;
+
+ /**
+ * Free-form debug information about how the signal was derived. Used for debug only,
+ * intentionally not used in equals(), etc.
+ */
+ private List<String> mDebugInfo;
+
+ private PhoneTimeZoneSuggestion(Builder builder) {
+ mPhoneId = builder.mPhoneId;
+ mZoneId = builder.mZoneId;
+ mMatchType = builder.mMatchType;
+ mQuality = builder.mQuality;
+ mDebugInfo = builder.mDebugInfo != null ? new ArrayList<>(builder.mDebugInfo) : null;
+ }
+
+ @SuppressWarnings("unchecked")
+ private static PhoneTimeZoneSuggestion createFromParcel(Parcel in) {
+ // Use the Builder so we get validation during build().
+ int phoneId = in.readInt();
+ PhoneTimeZoneSuggestion suggestion = new Builder(phoneId)
+ .setZoneId(in.readString())
+ .setMatchType(in.readInt())
+ .setQuality(in.readInt())
+ .build();
+ List<String> debugInfo = in.readArrayList(PhoneTimeZoneSuggestion.class.getClassLoader());
+ if (debugInfo != null) {
+ suggestion.addDebugInfo(debugInfo);
+ }
+ return suggestion;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeInt(mPhoneId);
+ dest.writeString(mZoneId);
+ dest.writeInt(mMatchType);
+ dest.writeInt(mQuality);
+ dest.writeList(mDebugInfo);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ public int getPhoneId() {
+ return mPhoneId;
+ }
+
+ @Nullable
+ public String getZoneId() {
+ return mZoneId;
+ }
+
+ @MatchType
+ public int getMatchType() {
+ return mMatchType;
+ }
+
+ @Quality
+ public int getQuality() {
+ return mQuality;
+ }
+
+ @NonNull
+ public List<String> getDebugInfo() {
+ return mDebugInfo == null
+ ? Collections.emptyList() : Collections.unmodifiableList(mDebugInfo);
+ }
+
+ /**
+ * Associates information with the instance that can be useful for debugging / logging. The
+ * information is present in {@link #toString()} but is not considered for
+ * {@link #equals(Object)} and {@link #hashCode()}.
+ */
+ public void addDebugInfo(@NonNull String debugInfo) {
+ if (mDebugInfo == null) {
+ mDebugInfo = new ArrayList<>();
+ }
+ mDebugInfo.add(debugInfo);
+ }
+
+ /**
+ * Associates information with the instance that can be useful for debugging / logging. The
+ * information is present in {@link #toString()} but is not considered for
+ * {@link #equals(Object)} and {@link #hashCode()}.
+ */
+ public void addDebugInfo(@NonNull List<String> debugInfo) {
+ if (mDebugInfo == null) {
+ mDebugInfo = new ArrayList<>(debugInfo.size());
+ }
+ mDebugInfo.addAll(debugInfo);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ PhoneTimeZoneSuggestion that = (PhoneTimeZoneSuggestion) o;
+ return mPhoneId == that.mPhoneId
+ && mMatchType == that.mMatchType
+ && mQuality == that.mQuality
+ && Objects.equals(mZoneId, that.mZoneId);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mPhoneId, mZoneId, mMatchType, mQuality);
+ }
+
+ @Override
+ public String toString() {
+ return "PhoneTimeZoneSuggestion{"
+ + "mPhoneId=" + mPhoneId
+ + ", mZoneId='" + mZoneId + '\''
+ + ", mMatchType=" + mMatchType
+ + ", mQuality=" + mQuality
+ + ", mDebugInfo=" + mDebugInfo
+ + '}';
+ }
+
+ /**
+ * Builds {@link PhoneTimeZoneSuggestion} instances.
+ *
+ * @hide
+ */
+ public static class Builder {
+ private final int mPhoneId;
+ private String mZoneId;
+ @MatchType private int mMatchType;
+ @Quality private int mQuality;
+ private List<String> mDebugInfo;
+
+ public Builder(int phoneId) {
+ mPhoneId = phoneId;
+ }
+
+ /** Returns the builder for call chaining. */
+ public Builder setZoneId(String zoneId) {
+ mZoneId = zoneId;
+ return this;
+ }
+
+ /** Returns the builder for call chaining. */
+ public Builder setMatchType(@MatchType int matchType) {
+ mMatchType = matchType;
+ return this;
+ }
+
+ /** Returns the builder for call chaining. */
+ public Builder setQuality(@Quality int quality) {
+ mQuality = quality;
+ return this;
+ }
+
+ /** Returns the builder for call chaining. */
+ public Builder addDebugInfo(@NonNull String debugInfo) {
+ if (mDebugInfo == null) {
+ mDebugInfo = new ArrayList<>();
+ }
+ mDebugInfo.add(debugInfo);
+ return this;
+ }
+
+ /**
+ * Performs basic structural validation of this instance. e.g. Are all the fields populated
+ * that must be? Are the enum ints set to valid values?
+ */
+ void validate() {
+ int quality = mQuality;
+ int matchType = mMatchType;
+ if (mZoneId == null) {
+ if (quality != QUALITY_NA || matchType != MATCH_TYPE_NA) {
+ throw new RuntimeException("Invalid quality or match type for null zone ID."
+ + " quality=" + quality + ", matchType=" + matchType);
+ }
+ } else {
+ boolean qualityValid = (quality == QUALITY_SINGLE_ZONE
+ || quality == QUALITY_MULTIPLE_ZONES_WITH_SAME_OFFSET
+ || quality == QUALITY_MULTIPLE_ZONES_WITH_DIFFERENT_OFFSETS);
+ boolean matchTypeValid = (matchType == MATCH_TYPE_NETWORK_COUNTRY_ONLY
+ || matchType == MATCH_TYPE_NETWORK_COUNTRY_AND_OFFSET
+ || matchType == MATCH_TYPE_EMULATOR_ZONE_ID
+ || matchType == MATCH_TYPE_TEST_NETWORK_OFFSET_ONLY);
+ if (!qualityValid || !matchTypeValid) {
+ throw new RuntimeException("Invalid quality or match type with zone ID."
+ + " quality=" + quality + ", matchType=" + matchType);
+ }
+ }
+ }
+
+ /** Returns the {@link PhoneTimeZoneSuggestion}. */
+ public PhoneTimeZoneSuggestion build() {
+ validate();
+ return new PhoneTimeZoneSuggestion(this);
+ }
+ }
+}
diff --git a/core/java/android/app/timezonedetector/TimeZoneDetector.java b/core/java/android/app/timezonedetector/TimeZoneDetector.java
new file mode 100644
index 000000000000..909cbc2ccdf7
--- /dev/null
+++ b/core/java/android/app/timezonedetector/TimeZoneDetector.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.timezonedetector;
+
+import android.annotation.NonNull;
+import android.annotation.SystemService;
+import android.content.Context;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.ServiceManager.ServiceNotFoundException;
+import android.util.Log;
+
+/**
+ * The interface through which system components can send signals to the TimeZoneDetectorService.
+ * @hide
+ */
+@SystemService(Context.TIME_ZONE_DETECTOR_SERVICE)
+public final class TimeZoneDetector {
+ private static final String TAG = "timezonedetector.TimeZoneDetector";
+ private static final boolean DEBUG = false;
+
+ private final ITimeZoneDetectorService mITimeZoneDetectorService;
+
+ public TimeZoneDetector() throws ServiceNotFoundException {
+ mITimeZoneDetectorService = ITimeZoneDetectorService.Stub.asInterface(
+ ServiceManager.getServiceOrThrow(Context.TIME_ZONE_DETECTOR_SERVICE));
+ }
+
+ /**
+ * Suggests the current time zone to the detector. The detector may ignore the signal if better
+ * signals are available such as those that come from more reliable sources or were
+ * determined more recently.
+ */
+ public void suggestPhoneTimeZone(@NonNull PhoneTimeZoneSuggestion timeZoneSuggestion) {
+ if (DEBUG) {
+ Log.d(TAG, "suggestPhoneTimeZone called: " + timeZoneSuggestion);
+ }
+ try {
+ mITimeZoneDetectorService.suggestPhoneTimeZone(timeZoneSuggestion);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+}
diff --git a/core/java/android/app/usage/IUsageStatsManager.aidl b/core/java/android/app/usage/IUsageStatsManager.aidl
index 83c1d611226d..1211c731e2e1 100644
--- a/core/java/android/app/usage/IUsageStatsManager.aidl
+++ b/core/java/android/app/usage/IUsageStatsManager.aidl
@@ -44,7 +44,6 @@ interface IUsageStatsManager {
void setAppInactive(String packageName, boolean inactive, int userId);
@UnsupportedAppUsage
boolean isAppInactive(String packageName, int userId);
- void whitelistAppTemporarily(String packageName, long duration, int userId);
void onCarrierPrivilegedAppsChanged();
void reportChooserSelection(String packageName, int userId, String contentType,
in String[] annotations, String action);
diff --git a/core/java/android/app/usage/UsageStatsManager.java b/core/java/android/app/usage/UsageStatsManager.java
index 1f13a1e13d13..ab404d212730 100644
--- a/core/java/android/app/usage/UsageStatsManager.java
+++ b/core/java/android/app/usage/UsageStatsManager.java
@@ -29,6 +29,7 @@ import android.app.PendingIntent;
import android.content.Context;
import android.content.pm.ParceledListSlice;
import android.os.Build;
+import android.os.PowerWhitelistManager;
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
@@ -1044,15 +1045,16 @@ public final class UsageStatsManager {
* @param user The user for whom the package should be whitelisted. Passing in a user that is
* not the same as the caller's process will require the INTERACT_ACROSS_USERS permission.
* @see #isAppInactive(String)
+ *
+ * @deprecated Use
+ * {@link android.os.PowerWhitelistManager#whitelistAppTemporarily(String, long)} instead.
*/
@SystemApi
@RequiresPermission(android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST)
+ @Deprecated
public void whitelistAppTemporarily(String packageName, long duration, UserHandle user) {
- try {
- mService.whitelistAppTemporarily(packageName, duration, user.getIdentifier());
- } catch (RemoteException re) {
- throw re.rethrowFromSystemServer();
- }
+ mContext.getSystemService(PowerWhitelistManager.class)
+ .whitelistAppTemporarily(packageName, duration);
}
/**
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 0fdb51359cf9..341b5206ba90 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -2484,6 +2484,48 @@ public abstract class Context {
}
/**
+ * Version of
+ * {@link #sendOrderedBroadcast(Intent, String, BroadcastReceiver, Handler, int, String,
+ * Bundle)} that allows you to specify the App Op to enforce restrictions on which receivers
+ * the broadcast will be sent to as well as supply an optional sending options
+ *
+ * <p>See {@link BroadcastReceiver} for more information on Intent broadcasts.
+ *
+ * @param intent The Intent to broadcast; all receivers matching this
+ * Intent will receive the broadcast.
+ * @param receiverPermission String naming a permissions that
+ * a receiver must hold in order to receive your broadcast.
+ * If null, no permission is required.
+ * @param receiverAppOp The app op associated with the broadcast. If null, no appOp is
+ * required. If both receiverAppOp and receiverPermission are non-null,
+ * a receiver must have both of them to
+ * receive the broadcast
+ * @param options (optional) Additional sending options, generated from a
+ * {@link android.app.BroadcastOptions}.
+ * @param resultReceiver Your own BroadcastReceiver to treat as the final
+ * receiver of the broadcast.
+ * @param scheduler A custom Handler with which to schedule the
+ * resultReceiver callback; if null it will be
+ * scheduled in the Context's main thread.
+ * @param initialCode An initial value for the result code. Often
+ * Activity.RESULT_OK.
+ * @param initialData An initial value for the result data. Often
+ * null.
+ * @param initialExtras An initial value for the result extras. Often
+ * null.
+ *
+ * @see #sendOrderedBroadcast(Intent, String, BroadcastReceiver, Handler, int, String, Bundle)
+ * @see android.app.BroadcastOptions
+ */
+ public void sendOrderedBroadcast(@RequiresPermission @NonNull Intent intent,
+ @Nullable String receiverPermission, @Nullable String receiverAppOp,
+ @Nullable Bundle options, @Nullable BroadcastReceiver resultReceiver,
+ @Nullable Handler scheduler, int initialCode, @Nullable String initialData,
+ @Nullable Bundle initialExtras) {
+ throw new RuntimeException("Not implemented. Must override in a subclass.");
+ }
+
+ /**
* <p>Perform a {@link #sendBroadcast(Intent)} that is "sticky," meaning the
* Intent you are sending stays around after the broadcast is complete,
* so that others can quickly retrieve that data through the return
@@ -3383,7 +3425,9 @@ public abstract class Context {
CROSS_PROFILE_APPS_SERVICE,
//@hide: SYSTEM_UPDATE_SERVICE,
//@hide: TIME_DETECTOR_SERVICE,
+ //@hide: TIME_ZONE_DETECTOR_SERVICE,
PERMISSION_SERVICE,
+ INCREMENTAL_SERVICE,
})
@Retention(RetentionPolicy.SOURCE)
public @interface ServiceName {}
@@ -3864,14 +3908,6 @@ public abstract class Context {
public static final String NETWORK_STACK_SERVICE = "network_stack";
/**
- * Use with {@link android.os.ServiceManager.getService()} to retrieve a
- * {@link android.net.WifiStackClient} IBinder for communicating with the network stack
- * @hide
- * @see android.net.WifiStackClient
- */
- public static final String WIFI_STACK_SERVICE = "wifi_stack";
-
- /**
* Use with {@link #getSystemService(String)} to retrieve a
* {@link android.net.IpSecManager} for encrypting Sockets or Networks with
* IPSec.
@@ -4843,7 +4879,7 @@ public abstract class Context {
/**
* Use with {@link #getSystemService(String)} to retrieve an
- * {@link android.app.timedetector.ITimeDetectorService}.
+ * {@link android.app.timedetector.TimeDetector}.
* @hide
*
* @see #getSystemService(String)
@@ -4851,6 +4887,15 @@ public abstract class Context {
public static final String TIME_DETECTOR_SERVICE = "time_detector";
/**
+ * Use with {@link #getSystemService(String)} to retrieve an
+ * {@link android.app.timezonedetector.TimeZoneDetector}.
+ * @hide
+ *
+ * @see #getSystemService(String)
+ */
+ public static final String TIME_ZONE_DETECTOR_SERVICE = "time_zone_detector";
+
+ /**
* Binder service name for {@link AppBindingService}.
* @hide
*/
@@ -4917,6 +4962,21 @@ public abstract class Context {
public static final String APP_SEARCH_SERVICE = "app_search";
/**
+ * Use with {@link #getSystemService(String)} to retrieve an
+ * {@link android.content.integrity.AppIntegrityManager}.
+ * @hide
+ */
+ @SystemApi
+ public static final String APP_INTEGRITY_SERVICE = "app_integrity";
+
+ /**
+ * Use with {@link #getSystemService(String)} to retrieve an
+ * {@link android.os.incremental.IncrementalManager}.
+ * @hide
+ */
+ public static final String INCREMENTAL_SERVICE = "incremental";
+
+ /**
* 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/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index e44d6ae40356..d6442e28439f 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -590,6 +590,16 @@ public class ContextWrapper extends Context {
}
@Override
+ public void sendOrderedBroadcast(@RequiresPermission @NonNull Intent intent,
+ @Nullable String receiverPermission, @Nullable String receiverAppOp,
+ @Nullable Bundle options, @Nullable BroadcastReceiver resultReceiver,
+ @Nullable Handler scheduler, int initialCode, @Nullable String initialData,
+ @Nullable Bundle initialExtras) {
+ mBase.sendOrderedBroadcast(intent, receiverPermission, receiverAppOp, options,
+ resultReceiver, scheduler, initialCode, initialData, initialExtras);
+ }
+
+ @Override
@Deprecated
public void sendStickyBroadcast(Intent intent) {
mBase.sendStickyBroadcast(intent);
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index ca374f938f1e..40aca0ef2033 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -4417,6 +4417,22 @@ public class Intent implements Parcelable, Cloneable {
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
public static final String ACTION_VIEW_LOCUS = "android.intent.action.VIEW_LOCUS";
+ /**
+ * Broadcast Action: Sent to the integrity component when a package
+ * needs to be verified. The data contains the package URI along with other relevant
+ * information.
+ *
+ * <p class="note">
+ * This is a protected intent that can only be sent by the system.
+ * </p>
+ *
+ * @hide
+ */
+ @SystemApi
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_PACKAGE_NEEDS_INTEGRITY_VERIFICATION =
+ "android.intent.action.PACKAGE_NEEDS_INTEGRITY_VERIFICATION";
+
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
// Standard intent categories (see addCategory()).
diff --git a/services/core/java/com/android/server/integrity/model/AppInstallMetadata.java b/core/java/android/content/integrity/AppInstallMetadata.java
index dfc373bb97dc..c9634758f63f 100644
--- a/services/core/java/com/android/server/integrity/model/AppInstallMetadata.java
+++ b/core/java/android/content/integrity/AppInstallMetadata.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.integrity.model;
+package android.content.integrity;
import static com.android.internal.util.Preconditions.checkArgument;
import static com.android.internal.util.Preconditions.checkNotNull;
diff --git a/core/java/android/content/integrity/AppIntegrityManager.java b/core/java/android/content/integrity/AppIntegrityManager.java
new file mode 100644
index 000000000000..e53ef66020f1
--- /dev/null
+++ b/core/java/android/content/integrity/AppIntegrityManager.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.integrity;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.annotation.SystemService;
+import android.content.Context;
+import android.content.IntentSender;
+import android.content.pm.ParceledListSlice;
+import android.os.RemoteException;
+
+/**
+ * Class for pushing rules used to check the integrity of app installs.
+ *
+ * <p>Note: applications using methods of this class must be a system app and have their package
+ * name whitelisted as an integrity rule provider. Otherwise a {@link SecurityException} will be
+ * thrown.
+ *
+ * @hide
+ */
+@SystemApi
+@SystemService(Context.APP_INTEGRITY_SERVICE)
+public class AppIntegrityManager {
+
+ /** The operation succeeded. */
+ public static final int STATUS_SUCCESS = 0;
+
+ /** The operation failed. */
+ public static final int STATUS_FAILURE = 1;
+
+ /**
+ * Current status of an operation. Will be one of {@link #STATUS_SUCCESS}, {@link
+ * #STATUS_FAILURE}.
+ *
+ * <p>More information about a status may be available through additional extras; see the
+ * individual status documentation for details.
+ *
+ * @see android.content.Intent#getIntExtra(String, int)
+ */
+ public static final String EXTRA_STATUS = "android.content.integrity.extra.STATUS";
+
+ IAppIntegrityManager mManager;
+
+ /** @hide */
+ public AppIntegrityManager(IAppIntegrityManager manager) {
+ mManager = manager;
+ }
+
+ /**
+ * Update the rules to evaluate during install time.
+ *
+ * @param updateRequest request containing the data of the rule set update
+ * @param statusReceiver Called when the state of the session changes. Intents sent to this
+ * receiver contain {@link #EXTRA_STATUS}. Refer to the individual status codes on how to
+ * handle them.
+ */
+ public void updateRuleSet(
+ @NonNull RuleSet updateRequest, @NonNull IntentSender statusReceiver) {
+ try {
+ mManager.updateRuleSet(
+ updateRequest.getVersion(),
+ new ParceledListSlice<>(updateRequest.getRules()),
+ statusReceiver);
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ }
+ }
+
+ /** Get the current version of the rule set. */
+ @NonNull
+ public String getCurrentRuleSetVersion() {
+ try {
+ return mManager.getCurrentRuleSetVersion();
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ }
+ }
+
+ /** Get the name of the package that provided the current rule set. */
+ @NonNull
+ public String getCurrentRuleSetProvider() {
+ try {
+ return mManager.getCurrentRuleSetProvider();
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/integrity/model/AtomicFormula.java b/core/java/android/content/integrity/AtomicFormula.java
index a16f6b9b5970..c8e164f1f232 100644
--- a/services/core/java/com/android/server/integrity/model/AtomicFormula.java
+++ b/core/java/android/content/integrity/AtomicFormula.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.integrity.model;
+package android.content.integrity;
import static com.android.internal.util.Preconditions.checkArgument;
diff --git a/services/core/java/com/android/server/integrity/model/OpenFormula.java b/core/java/android/content/integrity/CompoundFormula.java
index f7ea9208f7fe..53a99534906c 100644
--- a/services/core/java/com/android/server/integrity/model/OpenFormula.java
+++ b/core/java/android/content/integrity/CompoundFormula.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.integrity.model;
+package android.content.integrity;
import static com.android.internal.util.Preconditions.checkArgument;
@@ -35,7 +35,8 @@ import java.util.List;
import java.util.Objects;
/**
- * Represents a complex formula consisting of other simple and complex formulas.
+ * Represents a compound formula formed by joining other simple and complex formulas with boolean
+ * connectors.
*
* <p>Instances of this class are immutable.
*
@@ -43,12 +44,12 @@ import java.util.Objects;
*/
@SystemApi
@VisibleForTesting
-public final class OpenFormula implements Formula, Parcelable {
+public final class CompoundFormula implements Formula, Parcelable {
private static final String TAG = "OpenFormula";
@IntDef(
value = {
- AND, OR, NOT,
+ AND, OR, NOT,
})
@Retention(RetentionPolicy.SOURCE)
public @interface Connector {}
@@ -66,16 +67,16 @@ public final class OpenFormula implements Formula, Parcelable {
private final @NonNull List<Formula> mFormulas;
@NonNull
- public static final Creator<OpenFormula> CREATOR =
- new Creator<OpenFormula>() {
+ public static final Creator<CompoundFormula> CREATOR =
+ new Creator<CompoundFormula>() {
@Override
- public OpenFormula createFromParcel(Parcel in) {
- return new OpenFormula(in);
+ public CompoundFormula createFromParcel(Parcel in) {
+ return new CompoundFormula(in);
}
@Override
- public OpenFormula[] newArray(int size) {
- return new OpenFormula[size];
+ public CompoundFormula[] newArray(int size) {
+ return new CompoundFormula[size];
}
};
@@ -85,15 +86,15 @@ public final class OpenFormula implements Formula, Parcelable {
* @throws IllegalArgumentException if the number of operands is not matching the requirements
* for that operator (at least 2 for {@link #AND} and {@link #OR}, 1 for {@link #NOT}).
*/
- public OpenFormula(@Connector int connector, @NonNull List<Formula> formulas) {
- checkArgument(isValidConnector(connector),
- String.format("Unknown connector: %d", connector));
+ public CompoundFormula(@Connector int connector, @NonNull List<Formula> formulas) {
+ checkArgument(
+ isValidConnector(connector), String.format("Unknown connector: %d", connector));
validateFormulas(connector, formulas);
this.mConnector = connector;
this.mFormulas = Collections.unmodifiableList(formulas);
}
- OpenFormula(Parcel in) {
+ CompoundFormula(Parcel in) {
mConnector = in.readInt();
int length = in.readInt();
checkArgument(length >= 0, "Must have non-negative length. Got " + length);
@@ -132,7 +133,7 @@ public final class OpenFormula implements Formula, Parcelable {
@Override
public int getTag() {
- return Formula.OPEN_FORMULA_TAG;
+ return Formula.COMPOUND_FORMULA_TAG;
}
@Override
@@ -160,7 +161,7 @@ public final class OpenFormula implements Formula, Parcelable {
if (o == null || getClass() != o.getClass()) {
return false;
}
- OpenFormula that = (OpenFormula) o;
+ CompoundFormula that = (CompoundFormula) o;
return mConnector == that.mConnector && mFormulas.equals(that.mFormulas);
}
@@ -217,8 +218,6 @@ public final class OpenFormula implements Formula, Parcelable {
}
private static boolean isValidConnector(int connector) {
- return connector == AND
- || connector == OR
- || connector == NOT;
+ return connector == AND || connector == OR || connector == NOT;
}
}
diff --git a/services/core/java/com/android/server/integrity/model/Formula.java b/core/java/android/content/integrity/Formula.java
index 67698277800f..030ff6b66e1f 100644
--- a/services/core/java/com/android/server/integrity/model/Formula.java
+++ b/core/java/android/content/integrity/Formula.java
@@ -14,18 +14,18 @@
* limitations under the License.
*/
-package com.android.server.integrity.model;
+package android.content.integrity;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.SystemApi;
+import android.content.integrity.AtomicFormula.BooleanAtomicFormula;
+import android.content.integrity.AtomicFormula.IntAtomicFormula;
+import android.content.integrity.AtomicFormula.StringAtomicFormula;
import android.os.Parcel;
import android.os.Parcelable;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.server.integrity.model.AtomicFormula.BooleanAtomicFormula;
-import com.android.server.integrity.model.AtomicFormula.IntAtomicFormula;
-import com.android.server.integrity.model.AtomicFormula.StringAtomicFormula;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -40,7 +40,7 @@ import java.lang.annotation.RetentionPolicy;
public interface Formula {
@IntDef(
value = {
- OPEN_FORMULA_TAG,
+ COMPOUND_FORMULA_TAG,
STRING_ATOMIC_FORMULA_TAG,
INT_ATOMIC_FORMULA_TAG,
BOOLEAN_ATOMIC_FORMULA_TAG
@@ -48,7 +48,7 @@ public interface Formula {
@Retention(RetentionPolicy.SOURCE)
public @interface Tag {}
- int OPEN_FORMULA_TAG = 0;
+ int COMPOUND_FORMULA_TAG = 0;
int STRING_ATOMIC_FORMULA_TAG = 1;
int INT_ATOMIC_FORMULA_TAG = 2;
int BOOLEAN_ATOMIC_FORMULA_TAG = 3;
@@ -87,8 +87,8 @@ public interface Formula {
static Formula readFromParcel(@NonNull Parcel in) {
int tag = in.readInt();
switch (tag) {
- case OPEN_FORMULA_TAG:
- return OpenFormula.CREATOR.createFromParcel(in);
+ case COMPOUND_FORMULA_TAG:
+ return CompoundFormula.CREATOR.createFromParcel(in);
case STRING_ATOMIC_FORMULA_TAG:
return StringAtomicFormula.CREATOR.createFromParcel(in);
case INT_ATOMIC_FORMULA_TAG:
diff --git a/core/java/android/content/integrity/IAppIntegrityManager.aidl b/core/java/android/content/integrity/IAppIntegrityManager.aidl
new file mode 100644
index 000000000000..6b73fd70bb99
--- /dev/null
+++ b/core/java/android/content/integrity/IAppIntegrityManager.aidl
@@ -0,0 +1,28 @@
+/*
+**
+** Copyright 2019, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+package android.content.integrity;
+
+import android.content.integrity.Rule;
+import android.content.IntentSender;
+import android.content.pm.ParceledListSlice;
+
+/** @hide */
+interface IAppIntegrityManager {
+ void updateRuleSet(String version, in ParceledListSlice<Rule> rules, in IntentSender statusReceiver);
+ String getCurrentRuleSetVersion();
+ String getCurrentRuleSetProvider();
+}
diff --git a/core/java/android/content/integrity/Rule.aidl b/core/java/android/content/integrity/Rule.aidl
new file mode 100644
index 000000000000..a6634ee67905
--- /dev/null
+++ b/core/java/android/content/integrity/Rule.aidl
@@ -0,0 +1,19 @@
+/*
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+package android.content.integrity;
+
+parcelable Rule;
diff --git a/services/core/java/com/android/server/integrity/model/Rule.java b/core/java/android/content/integrity/Rule.java
index 3ad876292ab4..914f1479edf3 100644
--- a/services/core/java/com/android/server/integrity/model/Rule.java
+++ b/core/java/android/content/integrity/Rule.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.integrity.model;
+package android.content.integrity;
import static com.android.internal.util.Preconditions.checkArgument;
import static com.android.internal.util.Preconditions.checkNotNull;
diff --git a/core/java/android/content/integrity/RuleSet.java b/core/java/android/content/integrity/RuleSet.java
new file mode 100644
index 000000000000..a78f8c97d553
--- /dev/null
+++ b/core/java/android/content/integrity/RuleSet.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.integrity;
+
+import static com.android.internal.util.Preconditions.checkNotNull;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Immutable data class encapsulating all parameters of a rule set.
+ *
+ * @hide
+ */
+@SystemApi
+public class RuleSet {
+ private final String mVersion;
+ private final List<Rule> mRules;
+
+ private RuleSet(String version, List<Rule> rules) {
+ mVersion = version;
+ mRules = Collections.unmodifiableList(rules);
+ }
+
+ /** @see Builder#setVersion(String). */
+ @NonNull
+ public String getVersion() {
+ return mVersion;
+ }
+
+ /** @see Builder#addRules(List). */
+ @NonNull
+ public List<Rule> getRules() {
+ return mRules;
+ }
+
+ /** Builder class for RuleSetUpdateRequest. */
+ public static class Builder {
+ private String mVersion;
+ private List<Rule> mRules;
+
+ public Builder() {
+ mRules = new ArrayList<>();
+ }
+
+ /**
+ * Set a version string to identify this rule set. This can be retrieved by {@link
+ * AppIntegrityManager#getCurrentRuleSetVersion()}.
+ */
+ @NonNull
+ public Builder setVersion(@NonNull String version) {
+ mVersion = version;
+ return this;
+ }
+
+ /** Add the rules to include. */
+ @NonNull
+ public Builder addRules(@NonNull List<Rule> rules) {
+ mRules.addAll(rules);
+ return this;
+ }
+
+ /**
+ * Builds a {@link RuleSet}.
+ *
+ * @throws IllegalArgumentException if version is null
+ */
+ @NonNull
+ public RuleSet build() {
+ checkNotNull(mVersion);
+ return new RuleSet(mVersion, mRules);
+ }
+ }
+}
diff --git a/core/java/android/content/pm/PermissionInfo.java b/core/java/android/content/pm/PermissionInfo.java
index aa6f58e82bcf..c77c53f387e2 100644
--- a/core/java/android/content/pm/PermissionInfo.java
+++ b/core/java/android/content/pm/PermissionInfo.java
@@ -248,17 +248,6 @@ public class PermissionInfo extends PackageItemInfo implements Parcelable {
@TestApi
public static final int PROTECTION_FLAG_TELEPHONY = 0x400000;
- /**
- * Additional flag for {@link #protectionLevel}, corresponding
- * to the <code>wifi</code> value of
- * {@link android.R.attr#protectionLevel}.
- *
- * @hide
- */
- @SystemApi
- @TestApi
- public static final int PROTECTION_FLAG_WIFI = 0x800000;
-
/** @hide */
@IntDef(flag = true, prefix = { "PROTECTION_FLAG_" }, value = {
PROTECTION_FLAG_PRIVILEGED,
@@ -281,7 +270,6 @@ public class PermissionInfo extends PackageItemInfo implements Parcelable {
PROTECTION_FLAG_INCIDENT_REPORT_APPROVER,
PROTECTION_FLAG_APP_PREDICTOR,
PROTECTION_FLAG_TELEPHONY,
- PROTECTION_FLAG_WIFI,
})
@Retention(RetentionPolicy.SOURCE)
public @interface ProtectionFlags {}
@@ -528,9 +516,6 @@ public class PermissionInfo extends PackageItemInfo implements Parcelable {
if ((level & PermissionInfo.PROTECTION_FLAG_TELEPHONY) != 0) {
protLevel += "|telephony";
}
- if ((level & PermissionInfo.PROTECTION_FLAG_WIFI) != 0) {
- protLevel += "|wifi";
- }
return protLevel;
}
diff --git a/core/java/android/content/pm/UserInfo.java b/core/java/android/content/pm/UserInfo.java
index a83c3da6975e..fff9cf399b67 100644
--- a/core/java/android/content/pm/UserInfo.java
+++ b/core/java/android/content/pm/UserInfo.java
@@ -26,6 +26,8 @@ import android.os.UserHandle;
import android.os.UserManager;
import android.util.DebugUtils;
+import com.android.internal.annotations.VisibleForTesting;
+
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -385,6 +387,13 @@ public class UserInfo implements Parcelable {
}
}
+ // TODO(b/142482943): Get rid of this (after removing it from all tests) if feasible.
+ /**
+ * @deprecated This is dangerous since it doesn't set the mandatory fields. Use a different
+ * constructor instead.
+ */
+ @Deprecated
+ @VisibleForTesting
public UserInfo() {
}
diff --git a/core/java/android/net/IpConfiguration.java b/core/java/android/net/IpConfiguration.java
index 143467b15fe8..dddb64d8cece 100644
--- a/core/java/android/net/IpConfiguration.java
+++ b/core/java/android/net/IpConfiguration.java
@@ -191,18 +191,12 @@ public final class IpConfiguration implements Parcelable {
83 * httpProxy.hashCode();
}
- /**
- * Implement the Parcelable interface
- * @hide
- */
+ /** Implement the Parcelable interface */
public int describeContents() {
return 0;
}
- /**
- * Implement the Parcelable interface
- * @hide
- */
+ /** Implement the Parcelable interface */
public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeString(ipAssignment.name());
dest.writeString(proxySettings.name());
diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java
index 0706e755d133..8e1834113486 100644
--- a/core/java/android/net/LinkProperties.java
+++ b/core/java/android/net/LinkProperties.java
@@ -762,10 +762,7 @@ public final class LinkProperties implements Parcelable {
* Returns the NAT64 prefix in use on this link, if any.
*
* @return the NAT64 prefix or {@code null}.
- * @hide
*/
- @SystemApi
- @TestApi
public @Nullable IpPrefix getNat64Prefix() {
return mNat64Prefix;
}
@@ -777,10 +774,7 @@ public final class LinkProperties implements Parcelable {
* 128-bit IPv6 address) are supported or {@code null} for no prefix.
*
* @param prefix the NAT64 prefix.
- * @hide
*/
- @SystemApi
- @TestApi
public void setNat64Prefix(@Nullable IpPrefix prefix) {
if (prefix != null && prefix.getPrefixLength() != 96) {
throw new IllegalArgumentException("Only 96-bit prefixes are supported: " + prefix);
diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java
index ec3919997603..15ff69e7fd2a 100644
--- a/core/java/android/os/Binder.java
+++ b/core/java/android/os/Binder.java
@@ -505,6 +505,19 @@ public class Binder implements IBinder {
public static final native void restoreCallingWorkSource(long token);
/**
+ * Mark as being built with VINTF-level stability promise. This API should
+ * only ever be invoked by the build system. It means that the interface
+ * represented by this binder is guaranteed to be kept stable for several
+ * years, and the build system also keeps snapshots of these APIs and
+ * invokes the AIDL compiler to make sure that these snapshots are
+ * backwards compatible. Instead of using this API, use an @VintfStability
+ * interface.
+ *
+ * @hide
+ */
+ public final native void markVintfStability();
+
+ /**
* Flush any Binder commands pending in the current thread to the kernel
* driver. This can be
* useful to call before performing an operation that may block for a long
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index 89ccef64d4cd..6eaea99d5c49 100755
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -1084,7 +1084,7 @@ public class Build {
return result == 0;
}
- final String system = SystemProperties.get("ro.build.fingerprint");
+ final String system = SystemProperties.get("ro.system.build.fingerprint");
final String vendor = SystemProperties.get("ro.vendor.build.fingerprint");
final String bootimage = SystemProperties.get("ro.bootimage.build.fingerprint");
final String requiredBootloader = SystemProperties.get("ro.build.expect.bootloader");
@@ -1094,7 +1094,7 @@ public class Build {
TelephonyProperties.baseband_version(), "");
if (TextUtils.isEmpty(system)) {
- Slog.e(TAG, "Required ro.build.fingerprint is empty!");
+ Slog.e(TAG, "Required ro.system.build.fingerprint is empty!");
return false;
}
diff --git a/core/java/android/os/FileObserver.java b/core/java/android/os/FileObserver.java
index 4d9ebc2b5923..5b715c0dcb3c 100644
--- a/core/java/android/os/FileObserver.java
+++ b/core/java/android/os/FileObserver.java
@@ -32,7 +32,7 @@ import java.util.List;
/**
* Monitors files (using <a href="http://en.wikipedia.org/wiki/Inotify">inotify</a>)
- * to fire an event after files are accessed or changed by by any process on
+ * to fire an event after files are accessed or changed by any process on
* the device (including this one). FileObserver is an abstract class;
* subclasses must implement the event handler {@link #onEvent(int, String)}.
*
diff --git a/core/java/android/os/ResultReceiver.aidl b/core/java/android/os/ResultReceiver.aidl
index 28ce6d5f15b0..9fd5bc970496 100644
--- a/core/java/android/os/ResultReceiver.aidl
+++ b/core/java/android/os/ResultReceiver.aidl
@@ -2,19 +2,19 @@
**
** Copyright 2007, The Android Open Source Project
**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
**
-** http://www.apache.org/licenses/LICENSE-2.0
+** http://www.apache.org/licenses/LICENSE-2.0
**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
** limitations under the License.
*/
package android.os;
-parcelable ResultReceiver;
+@JavaOnlyStableParcelable parcelable ResultReceiver;
diff --git a/core/java/android/os/UserHandle.java b/core/java/android/os/UserHandle.java
index 537cb9889805..62e83aa192aa 100644
--- a/core/java/android/os/UserHandle.java
+++ b/core/java/android/os/UserHandle.java
@@ -393,8 +393,13 @@ public final class UserHandle implements Parcelable {
/**
* Generate a text representation of the uid, breaking out its individual
* components -- user, app, isolated, etc.
+ *
+ * @param uid The uid to format
+ * @return A string representing the UID with its individual components broken out
* @hide
*/
+ @SystemApi
+ @NonNull
public static String formatUid(int uid) {
StringBuilder sb = new StringBuilder();
formatUid(sb, uid);
@@ -520,7 +525,7 @@ public final class UserHandle implements Parcelable {
public int hashCode() {
return mHandle;
}
-
+
public int describeContents() {
return 0;
}
@@ -532,10 +537,10 @@ public final class UserHandle implements Parcelable {
/**
* Write a UserHandle to a Parcel, handling null pointers. Must be
* read with {@link #readFromParcel(Parcel)}.
- *
+ *
* @param h The UserHandle to be written.
* @param out The Parcel in which the UserHandle will be placed.
- *
+ *
* @see #readFromParcel(Parcel)
*/
public static void writeToParcel(UserHandle h, Parcel out) {
@@ -545,23 +550,23 @@ public final class UserHandle implements Parcelable {
out.writeInt(USER_NULL);
}
}
-
+
/**
* Read a UserHandle from a Parcel that was previously written
* with {@link #writeToParcel(UserHandle, Parcel)}, returning either
* a null or new object as appropriate.
- *
+ *
* @param in The Parcel from which to read the UserHandle
* @return Returns a new UserHandle matching the previously written
* object, or null if a null had been written.
- *
+ *
* @see #writeToParcel(UserHandle, Parcel)
*/
public static UserHandle readFromParcel(Parcel in) {
int h = in.readInt();
return h != USER_NULL ? new UserHandle(h) : null;
}
-
+
public static final @android.annotation.NonNull Parcelable.Creator<UserHandle> CREATOR
= new Parcelable.Creator<UserHandle>() {
public UserHandle createFromParcel(Parcel in) {
@@ -581,7 +586,7 @@ public final class UserHandle implements Parcelable {
* must not use this with data written by
* {@link #writeToParcel(UserHandle, Parcel)} since it is not possible
* to handle a null UserHandle here.
- *
+ *
* @param in The Parcel containing the previously written UserHandle,
* positioned at the location in the buffer where it was written.
*/
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index ce91c50ca696..74340f0d4710 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -46,6 +46,7 @@ import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
+import android.location.LocationManager;
import android.provider.Settings;
import android.telephony.TelephonyManager;
import android.view.WindowManager.LayoutParams;
@@ -486,13 +487,13 @@ public class UserManager {
*
* <p>This user restriction is different from {@link #DISALLOW_SHARE_LOCATION},
* as the device owner or profile owner can still enable or disable location mode via
- * {@link DevicePolicyManager#setSecureSetting} when this restriction is on.
+ * {@link DevicePolicyManager#setLocationEnabled} when this restriction is on.
*
* <p>The default value is <code>false</code>.
*
* <p>Key for user restrictions.
* <p>Type: Boolean
- * @see android.location.LocationManager#isProviderEnabled(String)
+ * @see LocationManager#isLocationEnabled()
* @see DevicePolicyManager#addUserRestriction(ComponentName, String)
* @see DevicePolicyManager#clearUserRestriction(ComponentName, String)
* @see #getUserRestrictions()
diff --git a/core/java/android/os/connectivity/WifiBatteryStats.java b/core/java/android/os/connectivity/WifiBatteryStats.java
index d10a647cda1a..e9b3837c8853 100644
--- a/core/java/android/os/connectivity/WifiBatteryStats.java
+++ b/core/java/android/os/connectivity/WifiBatteryStats.java
@@ -48,9 +48,9 @@ public final class WifiBatteryStats implements Parcelable {
private long[] mTimeInStateMillis =
new long[BatteryStats.NUM_WIFI_STATES];
private long[] mTimeInSupplicantStateMillis =
- new long[BatteryStats.NUM_WIFI_SIGNAL_STRENGTH_BINS];
- private long[] mTimeInRxSignalStrengthLevelMillis =
new long[BatteryStats.NUM_WIFI_SUPPL_STATES];
+ private long[] mTimeInRxSignalStrengthLevelMillis =
+ new long[BatteryStats.NUM_WIFI_SIGNAL_STRENGTH_BINS];
private long mMonitoredRailChargeConsumedMaMillis = 0;
public static final @NonNull Parcelable.Creator<WifiBatteryStats> CREATOR =
diff --git a/core/java/android/os/incremental/IIncrementalService.aidl b/core/java/android/os/incremental/IIncrementalManager.aidl
index 1c832ca9e6db..d6446d485af5 100644
--- a/core/java/android/os/incremental/IIncrementalService.aidl
+++ b/core/java/android/os/incremental/IIncrementalManager.aidl
@@ -19,7 +19,7 @@ package android.os.incremental;
import android.os.incremental.IncrementalDataLoaderParamsParcel;
/** @hide */
-interface IIncrementalService {
+interface IIncrementalManager {
/**
* A set of flags for the |createMode| parameters when creating a new Incremental storage.
*/
@@ -53,6 +53,12 @@ interface IIncrementalService {
int makeDirectory(int storageId, in @utf8InCpp String pathUnderStorage);
/**
+ * Recursively creates a directory under a storage. The target directory is specified by its relative path under the storage.
+ * All the parent directories of the target directory will be created if they do not exist already.
+ */
+ int makeDirectories(int storageId, in @utf8InCpp String pathUnderStorage);
+
+ /**
* Creates a file under a storage, specifying its name, size and metadata.
*/
int makeFile(int storageId, in @utf8InCpp String pathUnderStorage, long size, in byte[] metadata);
@@ -64,10 +70,12 @@ interface IIncrementalService {
int makeFileFromRange(int storageId, in @utf8InCpp String targetPathUnderStorage, in @utf8InCpp String sourcePathUnderStorage, long start, long end);
/**
- * Creates a hard link between two files in a storage.
- * Both source and destination are specified by relative paths under storage.
+ * Creates a hard link between two files in two storage instances.
+ * Source and dest specified by parent storage IDs and their relative paths under the storage.
+ * The source and dest storage instances should be in the same fs mount.
+ * Note: destStorageId can be the same as sourceStorageId.
*/
- int makeLink(int storageId, in @utf8InCpp String sourcePathUnderStorage, in @utf8InCpp String destPathUnderStorage);
+ int makeLink(int sourceStorageId, in @utf8InCpp String sourcePathUnderStorage, int destStorageId, in @utf8InCpp String destPathUnderStorage);
/**
* Deletes a hard link in a storage, specified by the relative path of the link target under storage.
@@ -85,12 +93,12 @@ interface IIncrementalService {
byte[] getFileMetadata(int storageId, in @utf8InCpp String pathUnderStorage);
/**
- * Returns the list of file paths under a storage.
+ * Starts loading data for a storage.
*/
- @utf8InCpp String[] getFileList(int storageId);
+ boolean startLoading(int storageId);
/**
- * Starts loading data for a storage.
+ * Deletes a storage given its ID. Deletes its bind mounts and unmount it. Stop its data loader.
*/
- boolean startLoading(int storageId);
+ void deleteStorage(int storageId);
}
diff --git a/core/java/android/os/incremental/IncrementalDataLoaderParams.java b/core/java/android/os/incremental/IncrementalDataLoaderParams.java
new file mode 100644
index 000000000000..701f1cc8de02
--- /dev/null
+++ b/core/java/android/os/incremental/IncrementalDataLoaderParams.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os.incremental;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.ParcelFileDescriptor;
+
+import java.util.Arrays;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+ * This class represents the parameters used to configure an Incremental Data Loader.
+ * Hide for now.
+ * @hide
+ */
+public class IncrementalDataLoaderParams {
+ @NonNull private final IncrementalDataLoaderParamsParcel mData;
+
+ public IncrementalDataLoaderParams(@NonNull String url, @NonNull String packageName,
+ @Nullable Map<String, ParcelFileDescriptor> namedFds) {
+ IncrementalDataLoaderParamsParcel data = new IncrementalDataLoaderParamsParcel();
+ data.staticArgs = url;
+ data.packageName = packageName;
+ if (namedFds == null || namedFds.isEmpty()) {
+ data.dynamicArgs = new NamedParcelFileDescriptor[0];
+ } else {
+ data.dynamicArgs = new NamedParcelFileDescriptor[namedFds.size()];
+ int i = 0;
+ for (Map.Entry<String, ParcelFileDescriptor> namedFd : namedFds.entrySet()) {
+ data.dynamicArgs[i] = new NamedParcelFileDescriptor();
+ data.dynamicArgs[i].name = namedFd.getKey();
+ data.dynamicArgs[i].fd = namedFd.getValue();
+ i += 1;
+ }
+ }
+ mData = data;
+ }
+
+ public IncrementalDataLoaderParams(@NonNull IncrementalDataLoaderParamsParcel data) {
+ mData = data;
+ }
+
+ /**
+ * @return static server's URL
+ */
+ public final @NonNull String getStaticArgs() {
+ return mData.staticArgs;
+ }
+
+ /**
+ * @return data loader's package name
+ */
+ public final @NonNull String getPackageName() {
+ return mData.packageName;
+ }
+
+ public final @NonNull IncrementalDataLoaderParamsParcel getData() {
+ return mData;
+ }
+
+ /**
+ * @return data loader's dynamic arguments such as file descriptors
+ */
+ public final @NonNull Map<String, ParcelFileDescriptor> getDynamicArgs() {
+ return Arrays.stream(mData.dynamicArgs).collect(
+ Collectors.toMap(p->p.name, p->p.fd));
+ }
+}
diff --git a/core/java/android/os/incremental/IncrementalDataLoaderParamsParcel.aidl b/core/java/android/os/incremental/IncrementalDataLoaderParamsParcel.aidl
index 50c28f0a4c17..cd988dcace5b 100644
--- a/core/java/android/os/incremental/IncrementalDataLoaderParamsParcel.aidl
+++ b/core/java/android/os/incremental/IncrementalDataLoaderParamsParcel.aidl
@@ -23,7 +23,7 @@ import android.os.incremental.NamedParcelFileDescriptor;
* @hide
*/
parcelable IncrementalDataLoaderParamsParcel {
- @utf8InCpp String staticUri;
@utf8InCpp String packageName;
+ @utf8InCpp String staticArgs;
NamedParcelFileDescriptor[] dynamicArgs;
}
diff --git a/core/java/android/os/incremental/IncrementalManager.java b/core/java/android/os/incremental/IncrementalManager.java
new file mode 100644
index 000000000000..5aabf86e17e6
--- /dev/null
+++ b/core/java/android/os/incremental/IncrementalManager.java
@@ -0,0 +1,327 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os.incremental;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemService;
+import android.content.Context;
+import android.os.RemoteException;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.util.SparseArray;
+
+import com.android.internal.annotations.GuardedBy;
+
+import java.io.File;
+import java.io.IOException;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+/**
+ * Provides operations to open or create an IncrementalStorage, using IIncrementalManager service.
+ * Example Usage:
+ *
+ * <blockquote><pre>
+ * IncrementalManager manager = (IncrementalManager) getSystemService(Context.INCREMENTAL_MANAGER);
+ * IncrementalStorage storage = manager.openStorage("/path/to/incremental/dir");
+ * </pre></blockquote>
+ *
+ * @hide
+ */
+@SystemService(Context.INCREMENTAL_SERVICE)
+public class IncrementalManager {
+ private static final String TAG = "IncrementalManager";
+ private final IIncrementalManager mService;
+ @GuardedBy("mStorages")
+ private final SparseArray<IncrementalStorage> mStorages = new SparseArray<>();
+
+ public static final int CREATE_MODE_TEMPORARY_BIND =
+ IIncrementalManager.CREATE_MODE_TEMPORARY_BIND;
+ public static final int CREATE_MODE_PERMANENT_BIND =
+ IIncrementalManager.CREATE_MODE_PERMANENT_BIND;
+ public static final int CREATE_MODE_CREATE =
+ IIncrementalManager.CREATE_MODE_CREATE;
+ public static final int CREATE_MODE_OPEN_EXISTING =
+ IIncrementalManager.CREATE_MODE_OPEN_EXISTING;
+
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = {"CREATE_MODE_"}, value = {
+ CREATE_MODE_TEMPORARY_BIND,
+ CREATE_MODE_PERMANENT_BIND,
+ CREATE_MODE_CREATE,
+ CREATE_MODE_OPEN_EXISTING,
+ })
+ public @interface CreateMode {
+ }
+
+ public IncrementalManager(@NonNull IIncrementalManager is) {
+ mService = is;
+ }
+
+ /**
+ * Returns a storage object given a storage ID.
+ *
+ * @param storageId The storage ID to identify the storage object.
+ * @return IncrementalStorage object corresponding to storage ID.
+ */
+ @Nullable
+ public IncrementalStorage getStorage(int storageId) {
+ synchronized (mStorages) {
+ return mStorages.get(storageId);
+ }
+ }
+
+ /**
+ * Opens or create an Incremental File System mounted directory and returns an
+ * IncrementalStorage object.
+ *
+ * @param path Absolute path to mount Incremental File System on.
+ * @param params IncrementalDataLoaderParams object to configure data loading.
+ * @param createMode Mode for opening an old Incremental File System mount or
+ * creating a new mount.
+ * @param autoStartDataLoader Set true to immediately start data loader after creating storage.
+ * @return IncrementalStorage object corresponding to the mounted directory.
+ */
+ @Nullable
+ public IncrementalStorage createStorage(@NonNull String path,
+ @NonNull IncrementalDataLoaderParams params, @CreateMode int createMode,
+ boolean autoStartDataLoader) {
+ try {
+ final int id = mService.createStorage(path, params.getData(), createMode);
+ if (id < 0) {
+ return null;
+ }
+ final IncrementalStorage storage = new IncrementalStorage(mService, id);
+ synchronized (mStorages) {
+ mStorages.put(id, storage);
+ }
+ if (autoStartDataLoader) {
+ storage.startLoading();
+ }
+ return storage;
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Opens an existing Incremental File System mounted directory and returns an
+ * IncrementalStorage object.
+ *
+ * @param path Absolute target path that Incremental File System has been mounted on.
+ * @return IncrementalStorage object corresponding to the mounted directory.
+ */
+ @Nullable
+ public IncrementalStorage openStorage(@NonNull String path) {
+ try {
+ final int id = mService.openStorage(path);
+ if (id < 0) {
+ return null;
+ }
+ final IncrementalStorage storage = new IncrementalStorage(mService, id);
+ synchronized (mStorages) {
+ mStorages.put(id, storage);
+ }
+ return storage;
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Opens or creates an IncrementalStorage that is linked to another IncrementalStorage.
+ *
+ * @return IncrementalStorage object corresponding to the linked storage.
+ */
+ @Nullable
+ public IncrementalStorage createStorage(@NonNull String path,
+ @NonNull IncrementalStorage linkedStorage, @CreateMode int createMode) {
+ try {
+ final int id = mService.createLinkedStorage(path, linkedStorage.getId(), createMode);
+ if (id < 0) {
+ return null;
+ }
+ final IncrementalStorage storage = new IncrementalStorage(mService, id);
+ synchronized (mStorages) {
+ mStorages.put(id, storage);
+ }
+ return storage;
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Iterates through path parents to find the base dir of an Incremental Storage.
+ *
+ * @param file Target file to search storage for.
+ * @return Absolute path which is a bind-mount point of Incremental File System.
+ */
+ private Path getStoragePathForFile(File file) {
+ File currentPath = new File(file.getParent());
+ while (currentPath.getParent() != null) {
+ IncrementalStorage storage = openStorage(currentPath.getAbsolutePath());
+ if (storage != null) {
+ return currentPath.toPath();
+ }
+ currentPath = new File(currentPath.getParent());
+ }
+ return null;
+ }
+
+ /**
+ * Renames an Incremental path to a new path. If source path is a file, make a link from the old
+ * Incremental file to the new one. If source path is a dir, unbind old dir from Incremental
+ * Storage and bind the new one.
+ * <ol>
+ * <li> For renaming a dir, dest dir will be created if not exists, and does not need to
+ * be on the same Incremental storage as the source. </li>
+ * <li> For renaming a file, dest file must be on the same Incremental storage as source.
+ * </li>
+ * </ol>
+ *
+ * @param sourcePath Absolute path to the source. Should be the same type as the destPath
+ * (file or dir). Expected to already exist and is an Incremental path.
+ * @param destPath Absolute path to the destination.
+ * @throws IllegalArgumentException when 1) source does not exist,
+ * or 2) source and dest type mismatch (one is file and the other is dir),
+ * or 3) source path is not on Incremental File System,
+ * @throws IOException when 1) cannot find the root path of the Incremental storage of source,
+ * or 2) cannot retrieve the Incremental storage instance of the source,
+ * or 3) renaming a file, but dest is not on the same Incremental Storage,
+ * or 4) renaming a dir, dest dir does not exist but fails to be created.
+ *
+ * TODO(b/136132412): add unit tests
+ */
+ public void rename(@NonNull String sourcePath, @NonNull String destPath) throws IOException {
+ final File source = new File(sourcePath);
+ final File dest = new File(destPath);
+ if (!source.exists()) {
+ throw new IllegalArgumentException("Path not exist: " + sourcePath);
+ }
+ if (dest.exists()) {
+ throw new IllegalArgumentException("Target path already exists: " + destPath);
+ }
+ if (source.isDirectory() && dest.exists() && dest.isFile()) {
+ throw new IllegalArgumentException(
+ "Trying to rename a dir but destination is a file: " + destPath);
+ }
+ if (source.isFile() && dest.exists() && dest.isDirectory()) {
+ throw new IllegalArgumentException(
+ "Trying to rename a file but destination is a dir: " + destPath);
+ }
+ if (!isIncrementalPath(sourcePath)) {
+ throw new IllegalArgumentException("Not an Incremental path: " + sourcePath);
+ }
+
+ Path storagePath = Paths.get(sourcePath);
+ if (source.isFile()) {
+ storagePath = getStoragePathForFile(source);
+ }
+ if (storagePath == null || storagePath.toAbsolutePath() == null) {
+ throw new IOException("Invalid source storage path for: " + sourcePath);
+ }
+ final IncrementalStorage storage = openStorage(storagePath.toAbsolutePath().toString());
+ if (storage == null) {
+ throw new IOException("Failed to retrieve storage from Incremental Service.");
+ }
+ if (source.isFile()) {
+ renameFile(storage, storagePath, source, dest);
+ } else {
+ renameDir(storage, storagePath, source, dest);
+ }
+ }
+
+ private void renameFile(IncrementalStorage storage, Path storagePath,
+ File source, File dest) throws IOException {
+ Path sourcePath = source.toPath();
+ Path destPath = dest.toPath();
+ if (!sourcePath.startsWith(storagePath)) {
+ throw new IOException("Path: " + source.getAbsolutePath() + " is not on storage at: "
+ + storagePath.toString());
+ }
+ if (!destPath.startsWith(storagePath)) {
+ throw new IOException("Path: " + dest.getAbsolutePath() + " is not on storage at: "
+ + storagePath.toString());
+ }
+ final Path sourceRelativePath = storagePath.relativize(sourcePath);
+ final Path destRelativePath = storagePath.relativize(destPath);
+ storage.moveFile(sourceRelativePath.toString(), destRelativePath.toString());
+
+ }
+
+ private void renameDir(IncrementalStorage storage, Path storagePath,
+ File source, File dest) throws IOException {
+ Path destPath = dest.toPath();
+ boolean usedMkdir = false;
+ try {
+ Os.mkdir(dest.getAbsolutePath(), 0755);
+ usedMkdir = true;
+ } catch (ErrnoException e) {
+ // Traditional mkdir fails but maybe we can create it on Incremental File System if
+ // the dest path is on the same Incremental storage as the source.
+ if (destPath.startsWith(storagePath)) {
+ storage.makeDirectories(storagePath.relativize(destPath).toString());
+ } else {
+ throw new IOException("Failed to create directory: " + dest.getAbsolutePath(), e);
+ }
+ }
+ try {
+ storage.moveDir(source.getAbsolutePath(), dest.getAbsolutePath());
+ } catch (Exception ex) {
+ if (usedMkdir) {
+ try {
+ Os.remove(dest.getAbsolutePath());
+ } catch (ErrnoException ignored) {
+ }
+ }
+ throw new IOException(
+ "Failed to move " + source.getAbsolutePath() + " to " + dest.getAbsolutePath());
+ }
+ }
+
+ /**
+ * Closes a storage specified by the absolute path. If the path is not Incremental, do nothing.
+ * Unbinds the target dir and deletes the corresponding storage instance.
+ */
+ public void closeStorage(@NonNull String path) {
+ try {
+ final int id = mService.openStorage(path);
+ if (id < 0) {
+ return;
+ }
+ mService.deleteStorage(id);
+ synchronized (mStorages) {
+ mStorages.remove(id);
+ }
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Checks if path is mounted on Incremental File System.
+ */
+ public static boolean isIncrementalPath(@NonNull String path) {
+ // TODO(b/136132412): implement native method
+ return false;
+ }
+}
diff --git a/core/java/android/os/incremental/IncrementalStorage.java b/core/java/android/os/incremental/IncrementalStorage.java
new file mode 100644
index 000000000000..2bf89ed7f7e8
--- /dev/null
+++ b/core/java/android/os/incremental/IncrementalStorage.java
@@ -0,0 +1,346 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os.incremental;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.RemoteException;
+
+import java.io.File;
+import java.io.IOException;
+
+/**
+ * Provides operations on an Incremental File System directory, using IncrementalService. Example
+ * usage:
+ *
+ * <blockquote><pre>
+ * IncrementalManager manager = (IncrementalManager) getSystemService(Context.INCREMENTAL_MANAGER);
+ * IncrementalStorage storage = manager.openStorage("/path/to/incremental/dir");
+ * storage.makeDirectory("subdir");
+ * </pre></blockquote>
+ *
+ * @hide
+ */
+public final class IncrementalStorage {
+ private static final String TAG = "IncrementalStorage";
+ private final int mId;
+ private final IIncrementalManager mService;
+
+
+ public IncrementalStorage(@NonNull IIncrementalManager is, int id) {
+ mService = is;
+ mId = id;
+ }
+
+ public int getId() {
+ return mId;
+ }
+
+ /**
+ * Temporarily bind-mounts the current storage directory to a target directory. The bind-mount
+ * will NOT be preserved between device reboots.
+ *
+ * @param targetPath Absolute path to the target directory.
+ */
+ public void bind(@NonNull String targetPath) throws IOException {
+ bind("", targetPath);
+ }
+
+ /**
+ * Temporarily bind-mounts a subdir under the current storage directory to a target directory.
+ * The bind-mount will NOT be preserved between device reboots.
+ *
+ * @param sourcePathUnderStorage Source path as a relative path under current storage
+ * directory.
+ * @param targetPath Absolute path to the target directory.
+ */
+ public void bind(@NonNull String sourcePathUnderStorage, @NonNull String targetPath)
+ throws IOException {
+ try {
+ int res = mService.makeBindMount(mId, sourcePathUnderStorage, targetPath,
+ IIncrementalManager.BIND_TEMPORARY);
+ if (res < 0) {
+ throw new IOException("bind() failed with errno " + -res);
+ }
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ }
+
+
+ /**
+ * Permanently bind-mounts the current storage directory to a target directory. The bind-mount
+ * WILL be preserved between device reboots.
+ *
+ * @param targetPath Absolute path to the target directory.
+ */
+ public void bindPermanent(@NonNull String targetPath) throws IOException {
+ bindPermanent("", targetPath);
+ }
+
+ /**
+ * Permanently bind-mounts a subdir under the current storage directory to a target directory.
+ * The bind-mount WILL be preserved between device reboots.
+ *
+ * @param sourcePathUnderStorage Relative path under the current storage directory.
+ * @param targetPath Absolute path to the target directory.
+ */
+ public void bindPermanent(@NonNull String sourcePathUnderStorage, @NonNull String targetPath)
+ throws IOException {
+ try {
+ int res = mService.makeBindMount(mId, sourcePathUnderStorage, targetPath,
+ IIncrementalManager.BIND_PERMANENT);
+ if (res < 0) {
+ throw new IOException("bind() permanent failed with errno " + -res);
+ }
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Unbinds a bind mount.
+ *
+ * @param targetPath Absolute path to the target directory.
+ */
+ public void unBind(@NonNull String targetPath) throws IOException {
+ try {
+ int res = mService.deleteBindMount(mId, targetPath);
+ if (res < 0) {
+ throw new IOException("unbind() failed with errno " + -res);
+ }
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Creates a sub-directory under the current storage directory.
+ *
+ * @param pathUnderStorage Relative path of the sub-directory, e.g., "subdir"
+ */
+ public void makeDirectory(@NonNull String pathUnderStorage) throws IOException {
+ try {
+ int res = mService.makeDirectory(mId, pathUnderStorage);
+ if (res < 0) {
+ throw new IOException("makeDirectory() failed with errno " + -res);
+ }
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Creates a sub-directory under the current storage directory. If its parent dirs do not exist,
+ * create the parent dirs as well.
+ *
+ * @param pathUnderStorage Relative path of the sub-directory, e.g., "subdir/subsubdir"
+ */
+ public void makeDirectories(@NonNull String pathUnderStorage) throws IOException {
+ try {
+ int res = mService.makeDirectories(mId, pathUnderStorage);
+ if (res < 0) {
+ throw new IOException("makeDirectory() failed with errno " + -res);
+ }
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Creates a file under the current storage directory.
+ *
+ * @param pathUnderStorage Relative path of the new file.
+ * @param size Size of the new file in bytes.
+ * @param metadata Metadata bytes.
+ */
+ public void makeFile(@NonNull String pathUnderStorage, long size,
+ @Nullable byte[] metadata) throws IOException {
+ try {
+ int res = mService.makeFile(mId, pathUnderStorage, size, metadata);
+ if (res < 0) {
+ throw new IOException("makeFile() failed with errno " + -res);
+ }
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Creates a file in Incremental storage. The content of the file is mapped from a range inside
+ * a source file in the same storage.
+ *
+ * @param destRelativePath Target relative path under storage.
+ * @param sourceRelativePath Source relative path under storage.
+ * @param rangeStart Starting offset (in bytes) in the source file.
+ * @param rangeEnd Ending offset (in bytes) in the source file.
+ */
+ public void makeFileFromRange(@NonNull String destRelativePath,
+ @NonNull String sourceRelativePath, long rangeStart, long rangeEnd) throws IOException {
+ try {
+ int res = mService.makeFileFromRange(mId, destRelativePath, sourceRelativePath,
+ rangeStart, rangeEnd);
+ if (res < 0) {
+ throw new IOException("makeFileFromRange() failed, errno " + -res);
+ }
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Creates a hard-link between two paths, which can be under different storages but in the same
+ * Incremental File System.
+ *
+ * @param sourcePathUnderStorage The relative path of the source.
+ * @param destStorage The target storage of the link target.
+ * @param destPathUnderStorage The relative path of the target.
+ */
+ public void makeLink(@NonNull String sourcePathUnderStorage, IncrementalStorage destStorage,
+ @NonNull String destPathUnderStorage) throws IOException {
+ try {
+ int res = mService.makeLink(mId, sourcePathUnderStorage, destStorage.getId(),
+ destPathUnderStorage);
+ if (res < 0) {
+ throw new IOException("makeLink() failed with errno " + -res);
+ }
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Deletes a hard-link under the current storage directory.
+ *
+ * @param pathUnderStorage The relative path of the target.
+ */
+ public void unlink(@NonNull String pathUnderStorage) throws IOException {
+ try {
+ int res = mService.unlink(mId, pathUnderStorage);
+ if (res < 0) {
+ throw new IOException("unlink() failed with errno " + -res);
+ }
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Rename an old file name to a new file name under the current storage directory.
+ *
+ * @param sourcePathUnderStorage Old file path as a relative path to the storage directory.
+ * @param destPathUnderStorage New file path as a relative path to the storage directory.
+ */
+ public void moveFile(@NonNull String sourcePathUnderStorage,
+ @NonNull String destPathUnderStorage) throws IOException {
+ try {
+ int res = mService.makeLink(mId, sourcePathUnderStorage, mId, destPathUnderStorage);
+ if (res < 0) {
+ throw new IOException("moveFile() failed at makeLink(), errno " + -res);
+ }
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ try {
+ mService.unlink(mId, sourcePathUnderStorage);
+ } catch (RemoteException ignored) {
+ }
+ }
+
+ /**
+ * Move a directory, which is bind-mounted to a given storage, to a new location. The bind mount
+ * will be persistent between reboots.
+ *
+ * @param sourcePath The old path of the directory as an absolute path.
+ * @param destPath The new path of the directory as an absolute path, expected to already
+ * exist.
+ */
+ public void moveDir(@NonNull String sourcePath, @NonNull String destPath) throws IOException {
+ if (!new File(destPath).exists()) {
+ throw new IOException("moveDir() requires that destination dir already exists.");
+ }
+ try {
+ int res = mService.makeBindMount(mId, "", destPath, IIncrementalManager.BIND_PERMANENT);
+ if (res < 0) {
+ throw new IOException("moveDir() failed at making bind mount, errno " + -res);
+ }
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ try {
+ mService.deleteBindMount(mId, sourcePath);
+ } catch (RemoteException ignored) {
+ }
+ }
+
+ /**
+ * Checks whether a file under the current storage directory is fully loaded.
+ *
+ * @param pathUnderStorage The relative path of the file.
+ * @return True if the file is fully loaded.
+ */
+ public boolean isFileFullyLoaded(@NonNull String pathUnderStorage) {
+ return isFileRangeLoaded(pathUnderStorage, 0, -1);
+ }
+
+ /**
+ * Checks whether a range in a file if loaded.
+ *
+ * @param pathUnderStorage The relative path of the file.
+ * @param start The starting offset of the range.
+ * @param end The ending offset of the range.
+ * @return True if the file is fully loaded.
+ */
+ public boolean isFileRangeLoaded(@NonNull String pathUnderStorage, long start, long end) {
+ try {
+ return mService.isFileRangeLoaded(mId, pathUnderStorage, start, end);
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ return false;
+ }
+ }
+
+ /**
+ * Returns the metadata object of an IncFs File.
+ *
+ * @param pathUnderStorage The relative path of the file.
+ * @return Byte array that contains metadata bytes.
+ */
+ @Nullable
+ public byte[] getFileMetadata(@NonNull String pathUnderStorage) {
+ try {
+ return mService.getFileMetadata(mId, pathUnderStorage);
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ return null;
+ }
+ }
+
+ /**
+ * Informs the data loader service associated with the current storage to start data loader
+ *
+ * @return True if data loader is successfully started.
+ */
+ public boolean startLoading() {
+ try {
+ return mService.startLoading(mId);
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ return false;
+ }
+ }
+}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 0af2c36108df..f627daa74da4 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -89,7 +89,6 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
-import java.util.Locale;
import java.util.Map;
import java.util.Set;
@@ -5715,6 +5714,18 @@ public final class Settings {
"managed_provisioning_dpc_downloaded";
/**
+ * Indicates whether the device is under restricted secure FRP mode.
+ * Secure FRP mode is enabled when the device is under FRP. On solving of FRP challenge,
+ * device is removed from this mode.
+ * <p>
+ * Type: int (0 for false, 1 for true)
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final String SECURE_FRP_MODE = "secure_frp_mode";
+
+ /**
* Indicates whether the current user has completed setup via the setup wizard.
* <p>
* Type: int (0 for false, 1 for true)
@@ -8156,6 +8167,15 @@ public final class Settings {
public static final String NOTIFICATION_BADGING = "notification_badging";
/**
+ * When enabled the system will maintain a rolling history of received notifications. When
+ * disabled the history will be disabled and deleted.
+ *
+ * The value 1 - enable, 0 - disable
+ * @hide
+ */
+ public static final String NOTIFICATION_HISTORY_ENABLED = "notification_history_enabled";
+
+ /**
* Whether notifications are dismissed by a right-to-left swipe (instead of a left-to-right
* swipe).
*
@@ -10625,6 +10645,7 @@ public final class Settings {
/** {@hide} */
public static final String
BLUETOOTH_HEARING_AID_PRIORITY_PREFIX = "bluetooth_hearing_aid_priority_";
+
/**
* Enable/disable radio bug detection
*
@@ -11442,105 +11463,6 @@ public final class Settings {
"adb_allowed_connection_time";
/**
- * Get the key that retrieves a bluetooth headset's priority.
- * @hide
- */
- public static final String getBluetoothHeadsetPriorityKey(String address) {
- return BLUETOOTH_HEADSET_PRIORITY_PREFIX + address.toUpperCase(Locale.ROOT);
- }
-
- /**
- * Get the key that retrieves a bluetooth a2dp sink's priority.
- * @hide
- */
- public static final String getBluetoothA2dpSinkPriorityKey(String address) {
- return BLUETOOTH_A2DP_SINK_PRIORITY_PREFIX + address.toUpperCase(Locale.ROOT);
- }
-
- /**
- * Get the key that retrieves a bluetooth a2dp src's priority.
- * @hide
- */
- public static final String getBluetoothA2dpSrcPriorityKey(String address) {
- return BLUETOOTH_A2DP_SRC_PRIORITY_PREFIX + address.toUpperCase(Locale.ROOT);
- }
-
- /**
- * Get the key that retrieves a bluetooth a2dp device's ability to support optional codecs.
- * @hide
- */
- public static final String getBluetoothA2dpSupportsOptionalCodecsKey(String address) {
- return BLUETOOTH_A2DP_SUPPORTS_OPTIONAL_CODECS_PREFIX +
- address.toUpperCase(Locale.ROOT);
- }
-
- /**
- * Get the key that retrieves whether a bluetooth a2dp device should have optional codecs
- * enabled.
- * @hide
- */
- public static final String getBluetoothA2dpOptionalCodecsEnabledKey(String address) {
- return BLUETOOTH_A2DP_OPTIONAL_CODECS_ENABLED_PREFIX +
- address.toUpperCase(Locale.ROOT);
- }
-
- /**
- * Get the key that retrieves a bluetooth Input Device's priority.
- * @hide
- */
- public static final String getBluetoothHidHostPriorityKey(String address) {
- return BLUETOOTH_INPUT_DEVICE_PRIORITY_PREFIX + address.toUpperCase(Locale.ROOT);
- }
-
- /**
- * Get the key that retrieves a bluetooth pan client priority.
- * @hide
- */
- public static final String getBluetoothPanPriorityKey(String address) {
- return BLUETOOTH_PAN_PRIORITY_PREFIX + address.toUpperCase(Locale.ROOT);
- }
-
- /**
- * Get the key that retrieves a bluetooth hearing aid priority.
- * @hide
- */
- public static final String getBluetoothHearingAidPriorityKey(String address) {
- return BLUETOOTH_HEARING_AID_PRIORITY_PREFIX + address.toUpperCase(Locale.ROOT);
- }
-
- /**
- * Get the key that retrieves a bluetooth map priority.
- * @hide
- */
- public static final String getBluetoothMapPriorityKey(String address) {
- return BLUETOOTH_MAP_PRIORITY_PREFIX + address.toUpperCase(Locale.ROOT);
- }
-
- /**
- * Get the key that retrieves a bluetooth map client priority.
- * @hide
- */
- public static final String getBluetoothMapClientPriorityKey(String address) {
- return BLUETOOTH_MAP_CLIENT_PRIORITY_PREFIX + address.toUpperCase(Locale.ROOT);
- }
-
- /**
- * Get the key that retrieves a bluetooth pbap client priority.
- * @hide
- */
- public static final String getBluetoothPbapClientPriorityKey(String address) {
- return BLUETOOTH_PBAP_CLIENT_PRIORITY_PREFIX + address.toUpperCase(Locale.ROOT);
- }
-
- /**
- * Get the key that retrieves a bluetooth sap priority.
- * @hide
- */
- public static final String getBluetoothSapPriorityKey(String address) {
- return BLUETOOTH_SAP_PRIORITY_PREFIX + address.toUpperCase(Locale.ROOT);
- }
-
- /**
* Scaling factor for normal window animations. Setting to 0 will
* disable window animations.
*/
diff --git a/telephony/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java
index add03160bbe9..add03160bbe9 100644
--- a/telephony/java/android/provider/Telephony.java
+++ b/core/java/android/provider/Telephony.java
diff --git a/core/java/android/service/autofill/SaveInfo.java b/core/java/android/service/autofill/SaveInfo.java
index 48ba4295f3c8..4df43628b5d3 100644
--- a/core/java/android/service/autofill/SaveInfo.java
+++ b/core/java/android/service/autofill/SaveInfo.java
@@ -216,10 +216,21 @@ public final class SaveInfo implements Parcelable {
*/
public static final int NEGATIVE_BUTTON_STYLE_REJECT = 1;
+ /**
+ * Style for the negative button of the save UI to never do the
+ * save operation. This means that the user does not need to save
+ * any data on this activity or application. Once the user tapping
+ * the negative button, the service should never trigger the save
+ * UI again. In addition to this, must consider providing restore
+ * options for the user.
+ */
+ public static final int NEGATIVE_BUTTON_STYLE_NEVER = 2;
+
/** @hide */
@IntDef(prefix = { "NEGATIVE_BUTTON_STYLE_" }, value = {
NEGATIVE_BUTTON_STYLE_CANCEL,
- NEGATIVE_BUTTON_STYLE_REJECT
+ NEGATIVE_BUTTON_STYLE_REJECT,
+ NEGATIVE_BUTTON_STYLE_NEVER
})
@Retention(RetentionPolicy.SOURCE)
@interface NegativeButtonStyle{}
@@ -571,6 +582,7 @@ public final class SaveInfo implements Parcelable {
*
* @see #NEGATIVE_BUTTON_STYLE_CANCEL
* @see #NEGATIVE_BUTTON_STYLE_REJECT
+ * @see #NEGATIVE_BUTTON_STYLE_NEVER
*
* @throws IllegalArgumentException If the style is invalid
*/
@@ -578,11 +590,7 @@ public final class SaveInfo implements Parcelable {
@Nullable IntentSender listener) {
throwIfDestroyed();
Preconditions.checkArgumentInRange(style, NEGATIVE_BUTTON_STYLE_CANCEL,
- NEGATIVE_BUTTON_STYLE_REJECT, "style");
- if (style != NEGATIVE_BUTTON_STYLE_CANCEL
- && style != NEGATIVE_BUTTON_STYLE_REJECT) {
- throw new IllegalArgumentException("Invalid style: " + style);
- }
+ NEGATIVE_BUTTON_STYLE_NEVER, "style");
mNegativeButtonStyle = style;
mNegativeActionListener = listener;
return this;
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index 7e0974033fa7..236e5ae6f952 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -41,6 +41,7 @@ public class FeatureFlagUtils {
public static final String SCREENRECORD_LONG_PRESS = "settings_screenrecord_long_press";
public static final String DYNAMIC_SYSTEM = "settings_dynamic_system";
public static final String SETTINGS_WIFITRACKER2 = "settings_wifitracker2";
+ public static final String SETTINGS_FUSE_FLAG = "settings_fuse";
private static final Map<String, String> DEFAULT_FLAGS;
@@ -48,6 +49,7 @@ public class FeatureFlagUtils {
DEFAULT_FLAGS = new HashMap<>();
DEFAULT_FLAGS.put("settings_audio_switcher", "true");
DEFAULT_FLAGS.put("settings_systemui_theme", "true");
+ DEFAULT_FLAGS.put(SETTINGS_FUSE_FLAG, "false");
DEFAULT_FLAGS.put(DYNAMIC_SYSTEM, "false");
DEFAULT_FLAGS.put(SEAMLESS_TRANSFER, "false");
DEFAULT_FLAGS.put(HEARING_AID_SETTINGS, "false");
diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java
index be4c598da789..1c94e02462d0 100644
--- a/core/java/android/view/MotionEvent.java
+++ b/core/java/android/view/MotionEvent.java
@@ -1440,7 +1440,7 @@ public final class MotionEvent extends InputEvent implements Parcelable {
public static final int TOOL_TYPE_STYLUS = 2;
/**
- * Tool type constant: The tool is a mouse or trackpad.
+ * Tool type constant: The tool is a mouse.
*
* @see #getToolType
*/
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 6458737d326d..1855a2645b7a 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -161,6 +161,8 @@ public final class SurfaceControl implements Parcelable {
private static native boolean nativeSetAllowedDisplayConfigs(IBinder displayToken,
int[] allowedConfigs);
private static native int[] nativeGetAllowedDisplayConfigs(IBinder displayToken);
+ private static native boolean nativeSetDesiredDisplayConfigSpecs(IBinder displayToken,
+ int defaultModeId, float minRefreshRate, float maxRefreshRate);
private static native int[] nativeGetDisplayColorModes(IBinder displayToken);
private static native SurfaceControl.DisplayPrimaries nativeGetDisplayNativePrimaries(
IBinder displayToken);
@@ -1492,6 +1494,19 @@ public final class SurfaceControl implements Parcelable {
/**
* @hide
*/
+ public static boolean setDesiredDisplayConfigSpecs(IBinder displayToken,
+ int defaultModeId, float minRefreshRate, float maxRefreshRate) {
+ if (displayToken == null) {
+ throw new IllegalArgumentException("displayToken must not be null");
+ }
+
+ return nativeSetDesiredDisplayConfigSpecs(displayToken, defaultModeId, minRefreshRate,
+ maxRefreshRate);
+ }
+
+ /**
+ * @hide
+ */
public static int[] getDisplayColorModes(IBinder displayToken) {
if (displayToken == null) {
throw new IllegalArgumentException("displayToken must not be null");
diff --git a/core/java/android/view/WindowlessViewRoot.java b/core/java/android/view/WindowlessViewRoot.java
index addf8e242e3d..68f2bde9c265 100644
--- a/core/java/android/view/WindowlessViewRoot.java
+++ b/core/java/android/view/WindowlessViewRoot.java
@@ -32,6 +32,14 @@ import android.os.IBinder;
public class WindowlessViewRoot {
private ViewRootImpl mViewRoot;
private WindowlessWindowManager mWm;
+
+ /** @hide */
+ public WindowlessViewRoot(@NonNull Context c, @NonNull Display d,
+ @NonNull WindowlessWindowManager wwm) {
+ mWm = wwm;
+ mViewRoot = new ViewRootImpl(c, d, mWm);
+ }
+
public WindowlessViewRoot(@NonNull Context c, @NonNull Display d,
@NonNull SurfaceControl rootSurface,
@Nullable IBinder hostInputToken) {
@@ -55,4 +63,12 @@ public class WindowlessViewRoot {
public void dispose() {
mViewRoot.dispatchDetachedFromWindow();
}
+
+ /**
+ * Tell this viewroot to clean itself up.
+ * @hide
+ */
+ public void die() {
+ mViewRoot.die(false /* immediate */);
+ }
}
diff --git a/core/java/android/view/WindowlessWindowManager.java b/core/java/android/view/WindowlessWindowManager.java
index cf39979ff7f9..2ba09750b001 100644
--- a/core/java/android/view/WindowlessWindowManager.java
+++ b/core/java/android/view/WindowlessWindowManager.java
@@ -34,7 +34,7 @@ import java.util.HashMap;
* By parcelling the root surface, the app can offer another app content for embedding.
* @hide
*/
-class WindowlessWindowManager implements IWindowSession {
+public class WindowlessWindowManager implements IWindowSession {
private final static String TAG = "WindowlessWindowManager";
private class State {
@@ -45,6 +45,7 @@ class WindowlessWindowManager implements IWindowSession {
mParams.copyFrom(p);
}
};
+
/**
* Used to store SurfaceControl we've built for clients to
* reconfigure them if relayout is called.
@@ -67,13 +68,18 @@ class WindowlessWindowManager implements IWindowSession {
private int mForceHeight = -1;
private int mForceWidth = -1;
- WindowlessWindowManager(Configuration c, SurfaceControl rootSurface, IBinder hostInputToken) {
+ public WindowlessWindowManager(Configuration c, SurfaceControl rootSurface,
+ IBinder hostInputToken) {
mRootSurface = rootSurface;
mConfiguration = new Configuration(c);
mRealWm = WindowManagerGlobal.getWindowSession();
mHostInputToken = hostInputToken;
}
+ protected void setConfiguration(Configuration configuration) {
+ mConfiguration.setTo(configuration);
+ }
+
/**
* Utility API.
*/
@@ -125,6 +131,17 @@ class WindowlessWindowManager implements IWindowSession {
@Override
public void remove(android.view.IWindow window) throws RemoteException {
mRealWm.remove(window);
+ State state;
+ synchronized (this) {
+ state = mStateForWindow.remove(window.asBinder());
+ }
+ if (state == null) {
+ throw new IllegalArgumentException(
+ "Invalid window token (never added or removed already)");
+ }
+ try (SurfaceControl.Transaction t = new SurfaceControl.Transaction()) {
+ t.remove(state.mSurfaceControl).apply();
+ }
}
private boolean isOpaque(WindowManager.LayoutParams attrs) {
@@ -165,10 +182,14 @@ class WindowlessWindowManager implements IWindowSession {
int height = surfaceInsets != null ?
attrs.height + surfaceInsets.top + surfaceInsets.bottom : attrs.height;
- t.show(sc)
- .setBufferSize(sc, width, height)
- .setOpaque(sc, isOpaque(attrs))
- .apply();
+ t.setBufferSize(sc, width, height)
+ .setOpaque(sc, isOpaque(attrs));
+ if (viewFlags == View.VISIBLE) {
+ t.show(sc);
+ } else {
+ t.hide(sc);
+ }
+ t.apply();
outSurfaceControl.copyFrom(sc);
outFrame.set(0, 0, attrs.width, attrs.height);
diff --git a/core/java/android/view/accessibility/AccessibilityEvent.java b/core/java/android/view/accessibility/AccessibilityEvent.java
index 32b0f413321a..34654edd00e8 100644
--- a/core/java/android/view/accessibility/AccessibilityEvent.java
+++ b/core/java/android/view/accessibility/AccessibilityEvent.java
@@ -17,6 +17,7 @@
package android.view.accessibility;
import android.annotation.IntDef;
+import android.annotation.NonNull;
import android.annotation.UnsupportedAppUsage;
import android.os.Build;
import android.os.Parcel;
@@ -796,10 +797,32 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par
private ArrayList<AccessibilityRecord> mRecords;
- /*
- * Hide constructor from clients.
+ /**
+ * Creates a new {@link AccessibilityEvent}.
*/
- private AccessibilityEvent() {
+ public AccessibilityEvent() {
+ if (DEBUG_ORIGIN) originStackTrace = Thread.currentThread().getStackTrace();
+ }
+
+
+ /**
+ * Creates a new {@link AccessibilityEvent} with the given <code>eventType</code>.
+ *
+ * @param eventType The event type.
+ */
+ public AccessibilityEvent(int eventType) {
+ mEventType = eventType;
+ if (DEBUG_ORIGIN) originStackTrace = Thread.currentThread().getStackTrace();
+ }
+
+ /**
+ * Copy constructor. Creates a new {@link AccessibilityEvent}, and this instance is initialized
+ * from the given <code>event</code>.
+ *
+ * @param event The other event.
+ */
+ public AccessibilityEvent(@NonNull AccessibilityEvent event) {
+ init(event);
}
/**
@@ -816,6 +839,15 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par
mWindowChangeTypes = event.mWindowChangeTypes;
mEventTime = event.mEventTime;
mPackageName = event.mPackageName;
+ if (event.mRecords != null) {
+ final int recordCount = event.mRecords.size();
+ mRecords = new ArrayList<>(recordCount);
+ for (int i = 0; i < recordCount; i++) {
+ final AccessibilityRecord record = event.mRecords.get(i);
+ final AccessibilityRecord recordClone = new AccessibilityRecord(record);
+ mRecords.add(recordClone);
+ }
+ }
if (DEBUG_ORIGIN) originStackTrace = event.originStackTrace;
}
@@ -1109,6 +1141,9 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par
* Returns a cached instance if such is available or a new one is
* instantiated with its type property set.
*
+ * <p>In most situations object pooling is not beneficial. Create a new instance using the
+ * constructor {@link #AccessibilityEvent(int)} instead.
+ *
* @param eventType The event type.
* @return An instance.
*/
@@ -1123,23 +1158,15 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par
* created. The returned instance is initialized from the given
* <code>event</code>.
*
+ * <p>In most situations object pooling is not beneficial. Create a new instance using the
+ * constructor {@link #AccessibilityEvent(AccessibilityEvent)} instead.
+ *
* @param event The other event.
* @return An instance.
*/
public static AccessibilityEvent obtain(AccessibilityEvent event) {
AccessibilityEvent eventClone = AccessibilityEvent.obtain();
eventClone.init(event);
-
- if (event.mRecords != null) {
- final int recordCount = event.mRecords.size();
- eventClone.mRecords = new ArrayList<AccessibilityRecord>(recordCount);
- for (int i = 0; i < recordCount; i++) {
- final AccessibilityRecord record = event.mRecords.get(i);
- final AccessibilityRecord recordClone = AccessibilityRecord.obtain(record);
- eventClone.mRecords.add(recordClone);
- }
- }
-
return eventClone;
}
@@ -1147,6 +1174,9 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par
* Returns a cached instance if such is available or a new one is
* instantiated.
*
+ * <p>In most situations object pooling is not beneficial. Create a new instance using the
+ * constructor {@link #AccessibilityEvent()} instead.
+ *
* @return An instance.
*/
public static AccessibilityEvent obtain() {
@@ -1162,6 +1192,8 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par
* <b>Note: You must not touch the object after calling this function.</b>
* </p>
*
+ * <p>In most situations object pooling is not beneficial, and recycling is not necessary.
+ *
* @throws IllegalStateException If the event is already recycled.
*/
@Override
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index a38955540927..66bf982894aa 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -775,15 +775,38 @@ public class AccessibilityNodeInfo implements Parcelable {
private TouchDelegateInfo mTouchDelegateInfo;
/**
- * Hide constructor from clients.
+ * Creates a new {@link AccessibilityNodeInfo}.
*/
- private AccessibilityNodeInfo() {
- /* do nothing */
+ public AccessibilityNodeInfo() {
}
- /** @hide */
- AccessibilityNodeInfo(AccessibilityNodeInfo info) {
- init(info);
+ /**
+ * Creates a new {@link AccessibilityNodeInfo} with the given <code>source</code>.
+ *
+ * @param source The source view.
+ */
+ public AccessibilityNodeInfo(@NonNull View source) {
+ setSource(source);
+ }
+
+ /**
+ * Creates a new {@link AccessibilityNodeInfo} with the given <code>source</code>.
+ *
+ * @param root The root of the virtual subtree.
+ * @param virtualDescendantId The id of the virtual descendant.
+ */
+ public AccessibilityNodeInfo(@NonNull View root, int virtualDescendantId) {
+ setSource(root, virtualDescendantId);
+ }
+
+ /**
+ * Copy constructor. Creates a new {@link AccessibilityNodeInfo}, and this new instance is
+ * initialized from the given <code>info</code>.
+ *
+ * @param info The other info.
+ */
+ public AccessibilityNodeInfo(@NonNull AccessibilityNodeInfo info) {
+ init(info, false /* usePoolingInfo */);
}
/**
@@ -911,7 +934,7 @@ public class AccessibilityNodeInfo implements Parcelable {
// when it is obtained. Enforce sealing again before we init to fail when a node has been
// recycled during a refresh to catch such errors earlier.
enforceSealed();
- init(refreshedInfo);
+ init(refreshedInfo, true /* usePoolingInfo */);
refreshedInfo.recycle();
return true;
}
@@ -3299,6 +3322,9 @@ public class AccessibilityNodeInfo implements Parcelable {
* Returns a cached instance if such is available otherwise a new one
* and sets the source.
*
+ * <p>In most situations object pooling is not beneficial. Create a new instance using the
+ * constructor {@link #AccessibilityNodeInfo(View)} instead.
+ *
* @param source The source view.
* @return An instance.
*
@@ -3314,6 +3340,9 @@ public class AccessibilityNodeInfo implements Parcelable {
* Returns a cached instance if such is available otherwise a new one
* and sets the source.
*
+ * <p>In most situations object pooling is not beneficial. Create a new instance using the
+ * constructor {@link #AccessibilityNodeInfo(View, int)} instead.
+ *
* @param root The root of the virtual subtree.
* @param virtualDescendantId The id of the virtual descendant.
* @return An instance.
@@ -3329,6 +3358,9 @@ public class AccessibilityNodeInfo implements Parcelable {
/**
* Returns a cached instance if such is available otherwise a new one.
*
+ * <p>In most situations object pooling is not beneficial. Create a new instance using the
+ * constructor {@link #AccessibilityNodeInfo()} instead.
+ *
* @return An instance.
*/
public static AccessibilityNodeInfo obtain() {
@@ -3344,12 +3376,15 @@ public class AccessibilityNodeInfo implements Parcelable {
* create. The returned instance is initialized from the given
* <code>info</code>.
*
+ * <p>In most situations object pooling is not beneficial. Create a new instance using the
+ * constructor {@link #AccessibilityNodeInfo(AccessibilityNodeInfo)} instead.
+ *
* @param info The other info.
* @return An instance.
*/
public static AccessibilityNodeInfo obtain(AccessibilityNodeInfo info) {
AccessibilityNodeInfo infoClone = AccessibilityNodeInfo.obtain();
- infoClone.init(info);
+ infoClone.init(info, true /* usePoolingInfo */);
return infoClone;
}
@@ -3358,6 +3393,8 @@ public class AccessibilityNodeInfo implements Parcelable {
* <p>
* <strong>Note:</strong> You must not touch the object after calling this function.
*
+ * <p>In most situations object pooling is not beneficial, and recycling is not necessary.
+ *
* @throws IllegalStateException If the info is already recycled.
*/
public void recycle() {
@@ -3647,8 +3684,9 @@ public class AccessibilityNodeInfo implements Parcelable {
* Initializes this instance from another one.
*
* @param other The other instance.
+ * @param usePoolingInfos whether using pooled object internally or not
*/
- private void init(AccessibilityNodeInfo other) {
+ private void init(AccessibilityNodeInfo other, boolean usePoolingInfos) {
mSealed = other.mSealed;
mSourceNodeId = other.mSourceNodeId;
mParentNodeId = other.mParentNodeId;
@@ -3707,6 +3745,18 @@ public class AccessibilityNodeInfo implements Parcelable {
mExtras = other.mExtras != null ? new Bundle(other.mExtras) : null;
+ if (usePoolingInfos) {
+ initPoolingInfos(other);
+ } else {
+ initCopyInfos(other);
+ }
+
+ final TouchDelegateInfo otherInfo = other.mTouchDelegateInfo;
+ mTouchDelegateInfo = (otherInfo != null)
+ ? new TouchDelegateInfo(otherInfo.mTargetMap, true) : null;
+ }
+
+ private void initPoolingInfos(AccessibilityNodeInfo other) {
if (mRangeInfo != null) mRangeInfo.recycle();
mRangeInfo = (other.mRangeInfo != null)
? RangeInfo.obtain(other.mRangeInfo) : null;
@@ -3716,10 +3766,20 @@ public class AccessibilityNodeInfo implements Parcelable {
if (mCollectionItemInfo != null) mCollectionItemInfo.recycle();
mCollectionItemInfo = (other.mCollectionItemInfo != null)
? CollectionItemInfo.obtain(other.mCollectionItemInfo) : null;
+ }
- final TouchDelegateInfo otherInfo = other.mTouchDelegateInfo;
- mTouchDelegateInfo = (otherInfo != null)
- ? new TouchDelegateInfo(otherInfo.mTargetMap, true) : null;
+ private void initCopyInfos(AccessibilityNodeInfo other) {
+ RangeInfo ri = other.mRangeInfo;
+ mRangeInfo = (ri == null) ? null
+ : new RangeInfo(ri.mType, ri.mMin, ri.mMax, ri.mCurrent);
+ CollectionInfo ci = other.mCollectionInfo;
+ mCollectionInfo = (ci == null) ? null
+ : new CollectionInfo(ci.mRowCount, ci.mColumnCount,
+ ci.mHierarchical, ci.mSelectionMode);
+ CollectionItemInfo cii = other.mCollectionItemInfo;
+ mCollectionItemInfo = (cii == null) ? null
+ : new CollectionItemInfo(cii.mRowIndex, cii.mRowSpan, cii.mColumnIndex,
+ cii.mColumnSpan, cii.mHeading, cii.mSelected);
}
/**
@@ -3854,7 +3914,7 @@ public class AccessibilityNodeInfo implements Parcelable {
* Clears the state of this instance.
*/
private void clear() {
- init(DEFAULT);
+ init(DEFAULT, true /* usePoolingInfo */);
}
private static boolean isDefaultStandardAction(AccessibilityAction action) {
@@ -4709,6 +4769,10 @@ public class AccessibilityNodeInfo implements Parcelable {
/**
* Obtains a pooled instance that is a clone of another one.
*
+ * <p>In most situations object pooling is not beneficial. Create a new instance using the
+ * constructor {@link AccessibilityNodeInfo.RangeInfo#AccessibilityNodeInfo.RangeInfo(int,
+ * float, float, float)} instead.
+ *
* @param other The instance to clone.
*
* @hide
@@ -4720,6 +4784,10 @@ public class AccessibilityNodeInfo implements Parcelable {
/**
* Obtains a pooled instance.
*
+ * <p>In most situations object pooling is not beneficial. Create a new instance using the
+ * constructor {@link AccessibilityNodeInfo.RangeInfo#AccessibilityNodeInfo.RangeInfo(int,
+ * float, float, float)} instead.
+ *
* @param type The type of the range.
* @param min The minimum value. Use {@code Float.NEGATIVE_INFINITY} if the range has no
* minimum.
@@ -4750,7 +4818,7 @@ public class AccessibilityNodeInfo implements Parcelable {
* maximum.
* @param current The current value.
*/
- private RangeInfo(int type, float min, float max, float current) {
+ public RangeInfo(int type, float min, float max, float current) {
mType = type;
mMin = min;
mMax = max;
@@ -4799,6 +4867,8 @@ public class AccessibilityNodeInfo implements Parcelable {
/**
* Recycles this instance.
+ *
+ * <p>In most situations object pooling is not beneficial, and recycling is not necessary.
*/
void recycle() {
clear();
@@ -4849,6 +4919,10 @@ public class AccessibilityNodeInfo implements Parcelable {
/**
* Obtains a pooled instance that is a clone of another one.
*
+ * <p>In most situations object pooling is not beneficial. Create a new instance using the
+ * constructor {@link
+ * AccessibilityNodeInfo.CollectionInfo#AccessibilityNodeInfo.CollectionInfo} instead.
+ *
* @param other The instance to clone.
* @hide
*/
@@ -4860,6 +4934,11 @@ public class AccessibilityNodeInfo implements Parcelable {
/**
* Obtains a pooled instance.
*
+ * <p>In most situations object pooling is not beneficial. Create a new instance using the
+ * constructor {@link
+ * AccessibilityNodeInfo.CollectionInfo#AccessibilityNodeInfo.CollectionInfo(int, int,
+ * boolean)} instead.
+ *
* @param rowCount The number of rows, or -1 if count is unknown.
* @param columnCount The number of columns, or -1 if count is unknown.
* @param hierarchical Whether the collection is hierarchical.
@@ -4872,6 +4951,11 @@ public class AccessibilityNodeInfo implements Parcelable {
/**
* Obtains a pooled instance.
*
+ * <p>In most situations object pooling is not beneficial. Create a new instance using the
+ * constructor {@link
+ * AccessibilityNodeInfo.CollectionInfo#AccessibilityNodeInfo.CollectionInfo(int, int,
+ * boolean, int)} instead.
+ *
* @param rowCount The number of rows.
* @param columnCount The number of columns.
* @param hierarchical Whether the collection is hierarchical.
@@ -4902,9 +4986,20 @@ public class AccessibilityNodeInfo implements Parcelable {
* @param rowCount The number of rows.
* @param columnCount The number of columns.
* @param hierarchical Whether the collection is hierarchical.
+ */
+ public CollectionInfo(int rowCount, int columnCount, boolean hierarchical) {
+ this(rowCount, columnCount, hierarchical, SELECTION_MODE_NONE);
+ }
+
+ /**
+ * Creates a new instance.
+ *
+ * @param rowCount The number of rows.
+ * @param columnCount The number of columns.
+ * @param hierarchical Whether the collection is hierarchical.
* @param selectionMode The collection's selection mode.
*/
- private CollectionInfo(int rowCount, int columnCount, boolean hierarchical,
+ public CollectionInfo(int rowCount, int columnCount, boolean hierarchical,
int selectionMode) {
mRowCount = rowCount;
mColumnCount = columnCount;
@@ -4955,6 +5050,8 @@ public class AccessibilityNodeInfo implements Parcelable {
/**
* Recycles this instance.
+ *
+ * <p>In most situations object pooling is not beneficial, and recycling is not necessary.
*/
void recycle() {
clear();
@@ -4991,6 +5088,11 @@ public class AccessibilityNodeInfo implements Parcelable {
/**
* Obtains a pooled instance that is a clone of another one.
*
+ * <p>In most situations object pooling is not beneficial. Create a new instance using the
+ * constructor {@link
+ * AccessibilityNodeInfo.CollectionItemInfo#AccessibilityNodeInfo.CollectionItemInfo}
+ * instead.
+ *
* @param other The instance to clone.
* @hide
*/
@@ -5002,6 +5104,11 @@ public class AccessibilityNodeInfo implements Parcelable {
/**
* Obtains a pooled instance.
*
+ * <p>In most situations object pooling is not beneficial. Create a new instance using the
+ * constructor {@link
+ * AccessibilityNodeInfo.CollectionItemInfo#AccessibilityNodeInfo.CollectionItemInfo(int,
+ * int, int, int, boolean)} instead.
+ *
* @param rowIndex The row index at which the item is located.
* @param rowSpan The number of rows the item spans.
* @param columnIndex The column index at which the item is located.
@@ -5017,6 +5124,11 @@ public class AccessibilityNodeInfo implements Parcelable {
/**
* Obtains a pooled instance.
*
+ * <p>In most situations object pooling is not beneficial. Creates a new instance using the
+ * constructor {@link
+ * AccessibilityNodeInfo.CollectionItemInfo#AccessibilityNodeInfo.CollectionItemInfo(int,
+ * int, int, int, boolean, boolean)} instead.
+ *
* @param rowIndex The row index at which the item is located.
* @param rowSpan The number of rows the item spans.
* @param columnIndex The column index at which the item is located.
@@ -5058,7 +5170,22 @@ public class AccessibilityNodeInfo implements Parcelable {
* @param columnSpan The number of columns the item spans.
* @param heading Whether the item is a heading.
*/
- private CollectionItemInfo(int rowIndex, int rowSpan, int columnIndex, int columnSpan,
+ public CollectionItemInfo(int rowIndex, int rowSpan, int columnIndex, int columnSpan,
+ boolean heading) {
+ this(rowIndex, rowSpan, columnIndex, columnSpan, heading, false);
+ }
+
+ /**
+ * Creates a new instance.
+ *
+ * @param rowIndex The row index at which the item is located.
+ * @param rowSpan The number of rows the item spans.
+ * @param columnIndex The column index at which the item is located.
+ * @param columnSpan The number of columns the item spans.
+ * @param heading Whether the item is a heading.
+ * @param selected Whether the item is selected.
+ */
+ public CollectionItemInfo(int rowIndex, int rowSpan, int columnIndex, int columnSpan,
boolean heading, boolean selected) {
mRowIndex = rowIndex;
mRowSpan = rowSpan;
@@ -5126,6 +5253,8 @@ public class AccessibilityNodeInfo implements Parcelable {
/**
* Recycles this instance.
+ *
+ * <p>In most situations object pooling is not beneficial, and recycling is not necessary.
*/
void recycle() {
clear();
diff --git a/core/java/android/view/accessibility/AccessibilityRecord.java b/core/java/android/view/accessibility/AccessibilityRecord.java
index d7d7e210e5f4..4f6c9ef55220 100644
--- a/core/java/android/view/accessibility/AccessibilityRecord.java
+++ b/core/java/android/view/accessibility/AccessibilityRecord.java
@@ -18,6 +18,7 @@ package android.view.accessibility;
import static com.android.internal.util.CollectionUtils.isEmpty;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UnsupportedAppUsage;
import android.os.Parcelable;
@@ -113,10 +114,20 @@ public class AccessibilityRecord {
int mConnectionId = UNDEFINED;
- /*
- * Hide constructor.
+ /**
+ * Creates a new {@link AccessibilityRecord}.
*/
- AccessibilityRecord() {
+ public AccessibilityRecord() {
+ }
+
+ /**
+ * Copy constructor. Creates a new {@link AccessibilityRecord}, and this instance is initialized
+ * with data from the given <code>record</code>.
+ *
+ * @param record The other record.
+ */
+ public AccessibilityRecord(@NonNull AccessibilityRecord record) {
+ init(record);
}
/**
@@ -790,6 +801,9 @@ public class AccessibilityRecord {
* instantiated. The instance is initialized with data from the
* given record.
*
+ * <p>In most situations object pooling is not beneficial. Create a new instance using the
+ * constructor {@link #AccessibilityRecord(AccessibilityRecord)} instead.
+ *
* @return An instance.
*/
public static AccessibilityRecord obtain(AccessibilityRecord record) {
@@ -802,6 +816,9 @@ public class AccessibilityRecord {
* Returns a cached instance if such is available or a new one is
* instantiated.
*
+ * <p>In most situations object pooling is not beneficial. Create a new instance using the
+ * constructor {@link #AccessibilityRecord()} instead.
+ *
* @return An instance.
*/
public static AccessibilityRecord obtain() {
@@ -823,6 +840,8 @@ public class AccessibilityRecord {
* <p>
* <strong>Note:</strong> You must not touch the object after calling this function.
*
+ * <p>In most situations object pooling is not beneficial, and recycling is not necessary.
+ *
* @throws IllegalStateException If the record is already recycled.
*/
public void recycle() {
diff --git a/core/java/android/view/accessibility/AccessibilityWindowInfo.java b/core/java/android/view/accessibility/AccessibilityWindowInfo.java
index 5fa8a6e0e06b..2cc6e9aebd74 100644
--- a/core/java/android/view/accessibility/AccessibilityWindowInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityWindowInfo.java
@@ -119,12 +119,19 @@ public final class AccessibilityWindowInfo implements Parcelable {
private int mConnectionId = UNDEFINED_WINDOW_ID;
- private AccessibilityWindowInfo() {
- /* do nothing - hide constructor */
+ /**
+ * Creates a new {@link AccessibilityWindowInfo}.
+ */
+ public AccessibilityWindowInfo() {
}
- /** @hide */
- AccessibilityWindowInfo(AccessibilityWindowInfo info) {
+ /**
+ * Copy constructor. Creates a new {@link AccessibilityWindowInfo}, and this new instance is
+ * initialized from given <code>info</code>.
+ *
+ * @param info The other info.
+ */
+ public AccessibilityWindowInfo(@NonNull AccessibilityWindowInfo info) {
init(info);
}
@@ -469,6 +476,9 @@ public final class AccessibilityWindowInfo implements Parcelable {
* Returns a cached instance if such is available or a new one is
* created.
*
+ * <p>In most situations object pooling is not beneficial. Create a new instance using the
+ * constructor {@link #AccessibilityWindowInfo()} instead.
+ *
* @return An instance.
*/
public static AccessibilityWindowInfo obtain() {
@@ -487,6 +497,9 @@ public final class AccessibilityWindowInfo implements Parcelable {
* created. The returned instance is initialized from the given
* <code>info</code>.
*
+ * <p>In most situations object pooling is not beneficial. Create a new instance using the
+ * constructor {@link #AccessibilityWindowInfo(AccessibilityWindowInfo)} instead.
+ *
* @param info The other info.
* @return An instance.
*/
@@ -514,6 +527,8 @@ public final class AccessibilityWindowInfo implements Parcelable {
* <strong>Note:</strong> You must not touch the object after calling this function.
* </p>
*
+ * <p>In most situations object pooling is not beneficial, and recycling is not necessary.
+ *
* @throws IllegalStateException If the info is already recycled.
*/
public void recycle() {
diff --git a/core/java/com/android/internal/app/SuspendedAppActivity.java b/core/java/com/android/internal/app/SuspendedAppActivity.java
index 712774a12cdf..33b2113b0674 100644
--- a/core/java/com/android/internal/app/SuspendedAppActivity.java
+++ b/core/java/com/android/internal/app/SuspendedAppActivity.java
@@ -16,6 +16,8 @@
package com.android.internal.app;
+import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE;
+import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
import static android.content.res.Resources.ID_NULL;
import android.Manifest;
@@ -64,7 +66,8 @@ public class SuspendedAppActivity extends AlertActivity
final Intent moreDetailsIntent = new Intent(Intent.ACTION_SHOW_SUSPENDED_APP_DETAILS)
.setPackage(suspendingPackage);
final String requiredPermission = Manifest.permission.SEND_SHOW_SUSPENDED_APP_DETAILS;
- final ResolveInfo resolvedInfo = mPm.resolveActivityAsUser(moreDetailsIntent, 0, userId);
+ final ResolveInfo resolvedInfo = mPm.resolveActivityAsUser(moreDetailsIntent,
+ MATCH_DIRECT_BOOT_UNAWARE | MATCH_DIRECT_BOOT_AWARE, userId);
if (resolvedInfo != null && resolvedInfo.activityInfo != null
&& requiredPermission.equals(resolvedInfo.activityInfo.permission)) {
moreDetailsIntent.putExtra(Intent.EXTRA_PACKAGE_NAME, suspendedPackage)
diff --git a/core/java/com/android/internal/content/NativeLibraryHelper.java b/core/java/com/android/internal/content/NativeLibraryHelper.java
index fee8345d1660..0847fbdd2291 100644
--- a/core/java/com/android/internal/content/NativeLibraryHelper.java
+++ b/core/java/com/android/internal/content/NativeLibraryHelper.java
@@ -33,7 +33,6 @@ import android.content.pm.PackageParser.PackageLite;
import android.content.pm.PackageParser.PackageParserException;
import android.os.Build;
import android.os.SELinux;
-import android.os.SystemProperties;
import android.system.ErrnoException;
import android.system.Os;
import android.util.Slog;
@@ -444,6 +443,24 @@ public class NativeLibraryHelper {
return sum;
}
+ /**
+ * Configure the native library files managed by Incremental Service. Makes sure Incremental
+ * Service will create native library directories and set up native library binary files in the
+ * same structure as they are in non-incremental installations.
+ *
+ * @param pkg The package to be installed, including all the APK files.
+ * @param handle The pointer to an zip archive.
+ * @param libraryRoot The root directory of the native library files, e.g., lib/
+ * @param abiList The list of ABIs that are supported by the current device.
+ * @param useIsaSubdir Whether or not to set up a sub dir for the ISA.
+ * @return ABI code if installation succeeds or error code if installation fails.
+ */
+ public static int configureNativeBinariesForSupportedAbi(Package pkg, Handle handle,
+ File libraryRoot, String[] abiList, boolean useIsaSubdir) {
+ // TODO(b/136132412): Implement this.
+ return -1;
+ }
+
// We don't care about the other return values for now.
private static final int BITCODE_PRESENT = 1;
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 75a58046faaa..f1e299df0ee4 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -1870,6 +1870,7 @@ public class BatteryStatsImpl extends BatteryStats {
mCount = computeCurrentCountLocked();
mUnpluggedReportedTotalTime = mCurrentReportedTotalTime = 0;
mUnpluggedReportedCount = mCurrentReportedCount = 0;
+ mTrackingReportedValues = false;
}
public void setUpdateVersion(int version) {
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index 865ec27e00c4..9ee79eada626 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -254,18 +254,6 @@ public class ZygoteInit {
InputStream is;
try {
- // If we are profiling the boot image, avoid preloading classes.
- // Can't use device_config since we are the zygote.
- String prop = SystemProperties.get(
- "persist.device_config.runtime_native_boot.profilebootclasspath", "");
- // Might be empty if the property is unset since the default is "".
- if (prop.length() == 0) {
- prop = SystemProperties.get("dalvik.vm.profilebootclasspath", "");
- }
- if ("true".equals(prop)) {
- return;
- }
-
is = new FileInputStream(PRELOADED_CLASSES);
} catch (FileNotFoundException e) {
Log.e(TAG, "Couldn't find " + PRELOADED_CLASSES + ".");
@@ -345,6 +333,22 @@ public class ZygoteInit {
runtime.preloadDexCaches();
Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
+ // If we are profiling the boot image, reset the Jit counters after preloading the
+ // classes. We want to preload for performance, and we can use method counters to
+ // infer what clases are used after calling resetJitCounters, for profile purposes.
+ // Can't use device_config since we are the zygote.
+ String prop = SystemProperties.get(
+ "persist.device_config.runtime_native_boot.profilebootclasspath", "");
+ // Might be empty if the property is unset since the default is "".
+ if (prop.length() == 0) {
+ prop = SystemProperties.get("dalvik.vm.profilebootclasspath", "");
+ }
+ if ("true".equals(prop)) {
+ Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "ResetJitCounters");
+ runtime.resetJitCounters();
+ Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
+ }
+
// Bring back root. We'll need it later if we're in the zygote.
if (droppedPriviliges) {
try {
diff --git a/core/java/com/android/internal/util/BitUtils.java b/core/java/com/android/internal/util/BitUtils.java
index b4bab809cc00..154ea52bf9ba 100644
--- a/core/java/com/android/internal/util/BitUtils.java
+++ b/core/java/com/android/internal/util/BitUtils.java
@@ -68,9 +68,9 @@ public final class BitUtils {
int[] result = new int[size];
int index = 0;
int bitPos = 0;
- while (val > 0) {
+ while (val != 0) {
if ((val & 1) == 1) result[index++] = bitPos;
- val = val >> 1;
+ val = val >>> 1;
bitPos++;
}
return result;
@@ -79,7 +79,7 @@ public final class BitUtils {
public static long packBits(int[] bits) {
long packed = 0;
for (int b : bits) {
- packed |= (1 << b);
+ packed |= (1L << b);
}
return packed;
}
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index 51f8fcc264dc..148b0a2799b4 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -110,6 +110,7 @@ cc_library_shared {
"android_view_InputEventReceiver.cpp",
"android_view_InputEventSender.cpp",
"android_view_InputQueue.cpp",
+ "android_view_FrameMetricsObserver.cpp",
"android_view_KeyCharacterMap.cpp",
"android_view_KeyEvent.cpp",
"android_view_MotionEvent.cpp",
@@ -424,9 +425,9 @@ cc_library_static {
android: {
srcs: [ // sources that depend on android only libraries
"android/graphics/apex/android_canvas.cpp",
+ "android/graphics/apex/renderthread.cpp",
"android/graphics/apex/jni_runtime.cpp",
- "android_view_FrameMetricsObserver.cpp",
"android_view_TextureLayer.cpp",
"android_view_ThreadedRenderer.cpp",
"android/graphics/BitmapRegionDecoder.cpp",
diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp
index 2dec4b399e57..984f93caa937 100755
--- a/core/jni/android/graphics/Bitmap.cpp
+++ b/core/jni/android/graphics/Bitmap.cpp
@@ -12,7 +12,6 @@
#include "SkWebpEncoder.h"
#include "android_os_Parcel.h"
-#include "android_util_Binder.h"
#include "android_nio_utils.h"
#include "CreateJavaOutputStreamAdaptor.h"
#include <hwui/Paint.h>
diff --git a/core/jni/android/graphics/BitmapRegionDecoder.cpp b/core/jni/android/graphics/BitmapRegionDecoder.cpp
index 6ffa72ad8903..f18632dfc403 100644
--- a/core/jni/android/graphics/BitmapRegionDecoder.cpp
+++ b/core/jni/android/graphics/BitmapRegionDecoder.cpp
@@ -25,18 +25,13 @@
#include "SkBitmapRegionDecoder.h"
#include "SkCodec.h"
#include "SkData.h"
-#include "SkUtils.h"
-#include "SkPixelRef.h"
#include "SkStream.h"
-#include "android_nio_utils.h"
-#include "android_util_Binder.h"
#include "core_jni_helpers.h"
#include <HardwareBitmapUploader.h>
#include <nativehelper/JNIHelp.h>
#include <androidfw/Asset.h>
-#include <binder/Parcel.h>
#include <jni.h>
#include <sys/stat.h>
diff --git a/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.cpp b/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.cpp
index 7a9fea72a78e..4de6c863638f 100644
--- a/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.cpp
+++ b/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.cpp
@@ -7,6 +7,7 @@
#include "Utils.h"
#include <nativehelper/JNIHelp.h>
+#include <log/log.h>
#include <memory>
static jmethodID gInputStream_readMethodID;
diff --git a/core/jni/android/graphics/Path.cpp b/core/jni/android/graphics/Path.cpp
index d73affc057d1..1b2776525e47 100644
--- a/core/jni/android/graphics/Path.cpp
+++ b/core/jni/android/graphics/Path.cpp
@@ -132,14 +132,14 @@ public:
static void addRect(JNIEnv* env, jclass clazz, jlong objHandle,
jfloat left, jfloat top, jfloat right, jfloat bottom, jint dirHandle) {
SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
- SkPath::Direction dir = static_cast<SkPath::Direction>(dirHandle);
+ SkPathDirection dir = static_cast<SkPathDirection>(dirHandle);
obj->addRect(left, top, right, bottom, dir);
}
static void addOval(JNIEnv* env, jclass clazz, jlong objHandle,
jfloat left, jfloat top, jfloat right, jfloat bottom, jint dirHandle) {
SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
- SkPath::Direction dir = static_cast<SkPath::Direction>(dirHandle);
+ SkPathDirection dir = static_cast<SkPathDirection>(dirHandle);
SkRect oval = SkRect::MakeLTRB(left, top, right, bottom);
obj->addOval(oval, dir);
}
@@ -147,7 +147,7 @@ public:
static void addCircle(JNIEnv* env, jclass clazz, jlong objHandle, jfloat x, jfloat y,
jfloat radius, jint dirHandle) {
SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
- SkPath::Direction dir = static_cast<SkPath::Direction>(dirHandle);
+ SkPathDirection dir = static_cast<SkPathDirection>(dirHandle);
obj->addCircle(x, y, radius, dir);
}
@@ -162,7 +162,7 @@ public:
jfloat right, jfloat bottom, jfloat rx, jfloat ry, jint dirHandle) {
SkRect rect = SkRect::MakeLTRB(left, top, right, bottom);
SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
- SkPath::Direction dir = static_cast<SkPath::Direction>(dirHandle);
+ SkPathDirection dir = static_cast<SkPathDirection>(dirHandle);
obj->addRoundRect(rect, rx, ry, dir);
}
@@ -170,7 +170,7 @@ public:
jfloat right, jfloat bottom, jfloatArray array, jint dirHandle) {
SkRect rect = SkRect::MakeLTRB(left, top, right, bottom);
SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
- SkPath::Direction dir = static_cast<SkPath::Direction>(dirHandle);
+ SkPathDirection dir = static_cast<SkPathDirection>(dirHandle);
AutoJavaFloatArray afa(env, array, 8);
#ifdef SK_SCALAR_IS_FLOAT
const float* src = afa.ptr();
@@ -419,7 +419,7 @@ public:
float errorSquared = acceptableError * acceptableError;
float errorConic = acceptableError / 2; // somewhat arbitrary
- while ((verb = pathIter.next(points, false)) != SkPath::kDone_Verb) {
+ while ((verb = pathIter.next(points)) != SkPath::kDone_Verb) {
createVerbSegments(pathIter, verb, points, segmentPoints, lengths,
errorSquared, errorConic);
}
@@ -555,8 +555,8 @@ static const JNINativeMethod methods[] = {
int register_android_graphics_Path(JNIEnv* env) {
return RegisterMethodsOrDie(env, "android/graphics/Path", methods, NELEM(methods));
- static_assert(0 == SkPath::kCW_Direction, "direction_mismatch");
- static_assert(1 == SkPath::kCCW_Direction, "direction_mismatch");
+ static_assert(0 == (int)SkPathDirection::kCW, "direction_mismatch");
+ static_assert(1 == (int)SkPathDirection::kCCW, "direction_mismatch");
}
}
diff --git a/core/jni/android/graphics/Typeface.cpp b/core/jni/android/graphics/Typeface.cpp
index 9603a10de1f4..4ce56ba7444f 100644
--- a/core/jni/android/graphics/Typeface.cpp
+++ b/core/jni/android/graphics/Typeface.cpp
@@ -22,8 +22,6 @@
#include <nativehelper/ScopedPrimitiveArray.h>
#include <nativehelper/ScopedUtfChars.h>
#include "SkTypeface.h"
-#include <android_runtime/android_util_AssetManager.h>
-#include <androidfw/AssetManager.h>
#include <hwui/Typeface.h>
#include <minikin/FontFamily.h>
#include <minikin/SystemFonts.h>
diff --git a/core/jni/android/graphics/Utils.cpp b/core/jni/android/graphics/Utils.cpp
index 462d052cbf10..17c194d04f84 100644
--- a/core/jni/android/graphics/Utils.cpp
+++ b/core/jni/android/graphics/Utils.cpp
@@ -18,6 +18,8 @@
#include "SkUtils.h"
#include "SkData.h"
+#include <log/log.h>
+
using namespace android;
AssetStreamAdaptor::AssetStreamAdaptor(Asset* asset)
diff --git a/core/jni/android/graphics/Utils.h b/core/jni/android/graphics/Utils.h
index ac291ea77f62..89255177ba2e 100644
--- a/core/jni/android/graphics/Utils.h
+++ b/core/jni/android/graphics/Utils.h
@@ -19,8 +19,6 @@
#include "SkStream.h"
-#include "android_util_Binder.h"
-
#include <jni.h>
#include <androidfw/Asset.h>
diff --git a/core/jni/android/graphics/apex/include/android/graphics/renderthread.h b/core/jni/android/graphics/apex/include/android/graphics/renderthread.h
new file mode 100644
index 000000000000..0a790af731a9
--- /dev/null
+++ b/core/jni/android/graphics/apex/include/android/graphics/renderthread.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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_GRAPHICS_RENDERTHREAD_H
+#define ANDROID_GRAPHICS_RENDERTHREAD_H
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+/**
+ * Dumps a textual representation of the graphics stats for this process.
+ * @param fd The file descriptor that the available graphics stats will be appended to. The
+ * function requires a valid fd, but does not persist or assume ownership of the fd
+ * outside the scope of this function.
+ */
+void ARenderThread_dumpGraphicsMemory(int fd);
+
+__END_DECLS
+
+#endif // ANDROID_GRAPHICS_RENDERTHREAD_H
diff --git a/core/jni/android/graphics/apex/renderthread.cpp b/core/jni/android/graphics/apex/renderthread.cpp
new file mode 100644
index 000000000000..5d26afe7a2ab
--- /dev/null
+++ b/core/jni/android/graphics/apex/renderthread.cpp
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "android/graphics/renderthread.h"
+
+#include <renderthread/RenderProxy.h>
+
+using namespace android;
+
+void ARenderThread_dumpGraphicsMemory(int fd) {
+ uirenderer::renderthread::RenderProxy::dumpGraphicsMemory(fd);
+}
diff --git a/core/jni/android_app_ActivityThread.cpp b/core/jni/android_app_ActivityThread.cpp
index ca8b8de8d3ad..5aa684d51a01 100644
--- a/core/jni/android_app_ActivityThread.cpp
+++ b/core/jni/android_app_ActivityThread.cpp
@@ -17,13 +17,11 @@
#include "jni.h"
#include <nativehelper/JNIHelp.h>
-#include <minikin/Layout.h>
-#include <renderthread/RenderProxy.h>
-
#include "core_jni_helpers.h"
#include <unistd.h>
#include <bionic/malloc.h>
+#include <android/graphics/renderthread.h>
namespace android {
@@ -35,7 +33,7 @@ static void android_app_ActivityThread_purgePendingResources(JNIEnv* env, jobjec
static void
android_app_ActivityThread_dumpGraphics(JNIEnv* env, jobject clazz, jobject javaFileDescriptor) {
int fd = jniGetFDFromFileDescriptor(env, javaFileDescriptor);
- android::uirenderer::renderthread::RenderProxy::dumpGraphicsMemory(fd);
+ ARenderThread_dumpGraphicsMemory(fd);
}
static void android_app_ActivityThread_initZygoteChildHeapProfiling(JNIEnv* env, jobject clazz) {
diff --git a/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp b/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp
index cb7f0ddee1ff..f2a51ad04885 100644
--- a/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp
+++ b/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp
@@ -396,9 +396,8 @@ static sp<ANativeWindow> getNativeWindow(JNIEnv* env, jobject surface) {
}
static sp<ANativeWindow> getSurfaceTextureNativeWindow(JNIEnv* env, jobject thiz) {
- sp<SurfaceTexture> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz));
sp<IGraphicBufferProducer> producer(SurfaceTexture_getProducer(env, thiz));
- sp<Surface> surfaceTextureClient(surfaceTexture != NULL ? new Surface(producer) : NULL);
+ sp<Surface> surfaceTextureClient(producer != NULL ? new Surface(producer) : NULL);
return surfaceTextureClient;
}
diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp
index 22323931e94c..0992bebb5be0 100644
--- a/core/jni/android_util_Binder.cpp
+++ b/core/jni/android_util_Binder.cpp
@@ -30,12 +30,13 @@
#include <unistd.h>
#include <android-base/stringprintf.h>
+#include <binder/BpBinder.h>
#include <binder/IInterface.h>
-#include <binder/IServiceManager.h>
#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
#include <binder/Parcel.h>
-#include <binder/BpBinder.h>
#include <binder/ProcessState.h>
+#include <binder/Stability.h>
#include <cutils/atomic.h>
#include <log/log.h>
#include <utils/KeyedVector.h>
@@ -459,6 +460,9 @@ public:
sp<JavaBBinder> b = mBinder.promote();
if (b == NULL) {
b = new JavaBBinder(env, obj);
+ if (mVintf) {
+ ::android::internal::Stability::markVintf(b.get());
+ }
mBinder = b;
ALOGV("Creating JavaBinder %p (refs %p) for Object %p, weakCount=%" PRId32 "\n",
b.get(), b->getWeakRefs(), obj, b->getWeakRefs()->getWeakCount());
@@ -473,9 +477,18 @@ public:
return mBinder.promote();
}
+ void markVintf() {
+ mVintf = true;
+ }
+
private:
Mutex mLock;
wp<JavaBBinder> mBinder;
+
+ // in the future, we might condense this into int32_t stability, or if there
+ // is too much binder state here, we can think about making JavaBBinder an
+ // sp here (avoid recreating it)
+ bool mVintf = false;
};
// ----------------------------------------------------------------------------
@@ -965,6 +978,12 @@ static void android_os_Binder_restoreCallingWorkSource(jlong token)
IPCThreadState::self()->restoreCallingWorkSource(token);
}
+static void android_os_Binder_markVintfStability(JNIEnv* env, jobject clazz) {
+ JavaBBinderHolder* jbh =
+ (JavaBBinderHolder*) env->GetLongField(clazz, gBinderOffsets.mObject);
+ jbh->markVintf();
+}
+
static void android_os_Binder_flushPendingCommands(JNIEnv* env, jobject clazz)
{
IPCThreadState::self()->flushCommands();
@@ -1041,6 +1060,7 @@ static const JNINativeMethod gBinderMethods[] = {
// @CriticalNative
{ "clearCallingWorkSource", "()J", (void*)android_os_Binder_clearCallingWorkSource },
{ "restoreCallingWorkSource", "(J)V", (void*)android_os_Binder_restoreCallingWorkSource },
+ { "markVintfStability", "()V", (void*)android_os_Binder_markVintfStability},
{ "flushPendingCommands", "()V", (void*)android_os_Binder_flushPendingCommands },
{ "getNativeBBinderHolder", "()J", (void*)android_os_Binder_getNativeBBinderHolder },
{ "getNativeFinalizer", "()J", (void*)android_os_Binder_getNativeFinalizer },
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index 9f2038840c8a..bd202c15682e 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -810,6 +810,16 @@ static jintArray nativeGetAllowedDisplayConfigs(JNIEnv* env, jclass clazz, jobje
return allowedConfigsArray;
}
+static jboolean nativeSetDesiredDisplayConfigSpecs(JNIEnv* env, jclass clazz,
+ jobject tokenObj, jint displayModeId, jfloat minRefreshRate, jfloat maxRefreshRate) {
+ sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
+ if (token == nullptr) return JNI_FALSE;
+
+ size_t result = SurfaceComposerClient::setDesiredDisplayConfigSpecs(
+ token, displayModeId, minRefreshRate, maxRefreshRate);
+ return result == NO_ERROR ? JNI_TRUE : JNI_FALSE;
+}
+
static jint nativeGetActiveConfig(JNIEnv* env, jclass clazz, jobject tokenObj) {
sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
if (token == NULL) return -1;
@@ -1366,6 +1376,8 @@ static const JNINativeMethod sSurfaceControlMethods[] = {
(void*)nativeSetAllowedDisplayConfigs },
{"nativeGetAllowedDisplayConfigs", "(Landroid/os/IBinder;)[I",
(void*)nativeGetAllowedDisplayConfigs },
+ {"nativeSetDesiredDisplayConfigSpecs", "(Landroid/os/IBinder;IFF)Z",
+ (void*)nativeSetDesiredDisplayConfigSpecs },
{"nativeGetDisplayColorModes", "(Landroid/os/IBinder;)[I",
(void*)nativeGetDisplayColorModes},
{"nativeGetDisplayNativePrimaries", "(Landroid/os/IBinder;)Landroid/view/SurfaceControl$DisplayPrimaries;",
diff --git a/core/jni/android_view_TextureLayer.cpp b/core/jni/android_view_TextureLayer.cpp
index 64751517d162..5491a338023c 100644
--- a/core/jni/android_view_TextureLayer.cpp
+++ b/core/jni/android_view_TextureLayer.cpp
@@ -17,7 +17,6 @@
#define LOG_TAG "OpenGLRenderer"
#include "jni.h"
-#include "GraphicsJNI.h"
#include <nativehelper/JNIHelp.h>
#include "core_jni_helpers.h"
@@ -27,12 +26,8 @@
#include <gui/surfacetexture/surface_texture_platform.h>
#include <gui/surfacetexture/SurfaceTexture.h>
#include <hwui/Paint.h>
-
#include <SkMatrix.h>
-
#include <DeferredLayerUpdater.h>
-#include <Rect.h>
-#include <RenderNode.h>
namespace android {
diff --git a/core/proto/android/app/settings_enums.proto b/core/proto/android/app/settings_enums.proto
index 0cfb36b3f4d3..ab97fdd74b46 100644
--- a/core/proto/android/app/settings_enums.proto
+++ b/core/proto/android/app/settings_enums.proto
@@ -693,6 +693,12 @@ enum Action {
// CATEGORY: SETTINGS
// OS: R
ACTION_CONTROLLER_UPDATE_STATE = 1728;
+
+ // Custom tag to evaluate the consuming time from onAttach to
+ // DashboardFragment.updatePreferenceStates.
+ // CATEGORY: SETTINGS
+ // OS: R
+ ACTION_DASHBOARD_VISIBLE_TIME = 1729;
}
/**
@@ -2451,4 +2457,14 @@ enum PageId {
// CATEGORY: SETTINGS
// OS: R
SETTINGS_PLATFORM_COMPAT_DASHBOARD = 1805;
+
+ // OPEN: Settings > Location -> Work profile tab
+ // CATEGORY: SETTINGS
+ // OS: R
+ LOCATION_WORK = 1806;
+
+ // OPEN: Settings > Account -> Work profile tab
+ // CATEGORY: SETTINGS
+ // OS: R
+ ACCOUNT_WORK = 1807;
}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 220fdd2e889d..b83294c4b193 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -48,6 +48,7 @@
<protected-broadcast android:name="android.intent.action.PACKAGE_RESTARTED" />
<protected-broadcast android:name="android.intent.action.PACKAGE_DATA_CLEARED" />
<protected-broadcast android:name="android.intent.action.PACKAGE_FIRST_LAUNCH" />
+ <protected-broadcast android:name="android.intent.action.PACKAGE_NEEDS_INTEGRITY_VERIFICATION" />
<protected-broadcast android:name="android.intent.action.PACKAGE_NEEDS_VERIFICATION" />
<protected-broadcast android:name="android.intent.action.PACKAGE_VERIFIED" />
<protected-broadcast android:name="android.intent.action.PACKAGES_SUSPENDED" />
@@ -108,8 +109,8 @@
<protected-broadcast android:name="android.app.action.ENTER_CAR_MODE" />
<protected-broadcast android:name="android.app.action.EXIT_CAR_MODE" />
- <protected-broadcast android:name="android.app.action.ENTER_CAR_MODE_PRIVILEGED" />
- <protected-broadcast android:name="android.app.action.EXIT_CAR_MODE_PRIVILEGED" />
+ <protected-broadcast android:name="android.app.action.ENTER_CAR_MODE_PRIORITIZED" />
+ <protected-broadcast android:name="android.app.action.EXIT_CAR_MODE_PRIORITIZED" />
<protected-broadcast android:name="android.app.action.ENTER_DESK_MODE" />
<protected-broadcast android:name="android.app.action.EXIT_DESK_MODE" />
<protected-broadcast android:name="android.app.action.NEXT_ALARM_CLOCK_CHANGED" />
@@ -634,6 +635,11 @@
<protected-broadcast android:name="android.intent.action.DEVICE_CUSTOMIZATION_READY" />
+ <!-- NETWORK_SET_TIME / NETWORK_SET_TIMEZONE moved from com.android.phone to system server.
+ They should ultimately be removed. -->
+ <protected-broadcast android:name="android.intent.action.NETWORK_SET_TIME" />
+ <protected-broadcast android:name="android.intent.action.NETWORK_SET_TIMEZONE" />
+
<!-- For tether entitlement recheck-->
<protected-broadcast
android:name="com.android.server.connectivity.tethering.PROVISIONING_RECHECK_ALARM" />
@@ -1667,13 +1673,13 @@
<permission android:name="android.permission.NETWORK_BYPASS_PRIVATE_DNS"
android:protectionLevel="signature" />
- <!-- #SystemApi @hide Allows device mobility state to be set so that Wifi scan interval can be increased
- when the device is stationary in order to save power.
+ <!-- @SystemApi @hide Allows device mobility state to be set so that Wifi scan interval can
+ be increased when the device is stationary in order to save power.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.WIFI_SET_DEVICE_MOBILITY_STATE"
android:protectionLevel="signature|privileged" />
- <!-- #SystemApi @hide Allows privileged system APK to update Wifi usability stats and score.
+ <!-- @SystemApi @hide Allows privileged system APK to update Wifi usability stats and score.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.WIFI_UPDATE_USABILITY_STATS_SCORE"
android:protectionLevel="signature|privileged" />
@@ -2269,7 +2275,7 @@
types of interactions
@hide -->
<permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL"
- android:protectionLevel="signature|installer|telephony|wifi" />
+ android:protectionLevel="signature|installer|telephony" />
<!-- @SystemApi Allows an application to start its own activities, but on a different profile
associated with the user. For example, an application running on the main profile of a user
@@ -2951,7 +2957,7 @@
@hide
-->
<permission android:name="android.permission.INTERNAL_SYSTEM_WINDOW"
- android:protectionLevel="signature|telephony|wifi" />
+ android:protectionLevel="signature|telephony" />
<!-- @SystemApi Allows an application to use
{@link android.view.WindowManager.LayoutsParams#SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS}
@@ -3542,7 +3548,7 @@
<!-- Allows an application to manage the companion devices.
@hide -->
<permission android:name="android.permission.MANAGE_COMPANION_DEVICES"
- android:protectionLevel="signature|wifi" />
+ android:protectionLevel="signature" />
<!-- @SystemApi Allows an application to use SurfaceFlinger's low level features.
<p>Not for use by third-party applications.
@@ -4595,10 +4601,17 @@
<!-- @SystemApi Allows an app to grant a profile owner access to device identifiers.
<p>Not for use by third-party applications.
+ @deprecated
@hide -->
<permission android:name="android.permission.GRANT_PROFILE_OWNER_DEVICE_IDS_ACCESS"
android:protectionLevel="signature" />
+ <!-- Allows an app to mark a profile owner as managing an organization-owned device.
+ <p>Not for use by third-party applications.
+ @hide -->
+ <permission android:name="android.permission.MARK_DEVICE_ORGANIZATION_OWNED"
+ android:protectionLevel="signature" />
+
<!-- Allows financial apps to read filtered sms messages.
Protection level: signature|appop -->
<permission android:name="android.permission.SMS_FINANCIAL_TRANSACTIONS"
diff --git a/core/res/res/layout/shutdown_dialog.xml b/core/res/res/layout/shutdown_dialog.xml
index 2d214b32164b..ec67aa86bcc9 100644
--- a/core/res/res/layout/shutdown_dialog.xml
+++ b/core/res/res/layout/shutdown_dialog.xml
@@ -32,6 +32,19 @@
android:layout_height="32sp"
android:text="@string/shutdown_progress"
android:textDirection="locale"
+ android:textSize="18sp"
+ android:textAppearance="?attr/textAppearanceMedium"
+ android:gravity="center"
+ android:layout_marginBottom="24dp"
+ android:visibility="gone"
+ android:fontFamily="@string/config_headlineFontFamily"/>
+
+ <TextView
+ android:id="@+id/text2"
+ android:layout_width="wrap_content"
+ android:layout_height="32sp"
+ android:text="@string/shutdown_progress"
+ android:textDirection="locale"
android:textSize="24sp"
android:textAppearance="?attr/textAppearanceLarge"
android:gravity="center"
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index db5b2cbeef85..d095690588f5 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -188,6 +188,8 @@
<string name="work_profile_deleted_details" msgid="3773706828364418016">"Die werkprofiel se administrasieprogram ontbreek of is korrup. Gevolglik is jou werkprofiel en verwante data uitgevee. Kontak jou administrateur vir bystand."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Jou werkprofiel is nie meer op hierdie toestel beskikbaar nie"</string>
<string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Te veel wagwoordpogings"</string>
+ <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+ <skip />
<string name="network_logging_notification_title" msgid="554983187553845004">"Toestel word bestuur"</string>
<string name="network_logging_notification_text" msgid="1327373071132562512">"Jou organisasie bestuur hierdie toestel en kan netwerkverkeer monitor. Tik vir besonderhede."</string>
<string name="factory_reset_warning" msgid="6858705527798047809">"Jou toestel sal uitgevee word"</string>
@@ -1116,10 +1118,8 @@
<string name="loading" msgid="3138021523725055037">"Laai tans..."</string>
<string name="capital_on" msgid="2770685323900821829">"AAN"</string>
<string name="capital_off" msgid="7443704171014626777">"AF"</string>
- <!-- no translation found for checked (9179896827054513119) -->
- <skip />
- <!-- no translation found for not_checked (7972320087569023342) -->
- <skip />
+ <string name="checked" msgid="9179896827054513119">"gemerk"</string>
+ <string name="not_checked" msgid="7972320087569023342">"nie gemerk nie"</string>
<string name="whichApplication" msgid="5432266899591255759">"Voltooi handeling met"</string>
<string name="whichApplicationNamed" msgid="6969946041713975681">"Voltooi handeling met gebruik van %1$s"</string>
<string name="whichApplicationLabel" msgid="7852182961472531728">"Voltooi handeling"</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index 4e84c66aabed..75444ea595c2 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -188,6 +188,8 @@
<string name="work_profile_deleted_details" msgid="3773706828364418016">"የሥራ መገለጫ አስተዳዳሪ መተግበሪያው ወይም ይጎድላል ወይም ተበላሽቷል። በዚህ ምክንያት የሥራ መገለጫዎ እና ተዛማጅ ውሂብ ተሰርዘዋል። እርዳታን ለማግኘት አስተዳዳሪዎን ያነጋግሩ።"</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"የሥራ መገለጫዎ ከዚህ በኋላ በዚህ መሣሪያ ላይ አይገኝም"</string>
<string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"በጣም ብዙ የይለፍ ቃል ሙከራዎች"</string>
+ <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+ <skip />
<string name="network_logging_notification_title" msgid="554983187553845004">"መሣሪያው የሚተዳደር ነው"</string>
<string name="network_logging_notification_text" msgid="1327373071132562512">"የእርስዎ ድርጅት ይህን መሣሪያ ያስተዳድራል፣ እና የአውታረ መረብ ትራፊክን ሊከታተል ይችላል። ዝርዝሮችን ለማግኘት መታ ያድርጉ።"</string>
<string name="factory_reset_warning" msgid="6858705527798047809">"የእርስዎ መሣሪያ ይደመሰሳል"</string>
@@ -1116,10 +1118,8 @@
<string name="loading" msgid="3138021523725055037">"በመጫን ላይ…"</string>
<string name="capital_on" msgid="2770685323900821829">"በ"</string>
<string name="capital_off" msgid="7443704171014626777">"ውጪ"</string>
- <!-- no translation found for checked (9179896827054513119) -->
- <skip />
- <!-- no translation found for not_checked (7972320087569023342) -->
- <skip />
+ <string name="checked" msgid="9179896827054513119">"ምልክት ተደርጎበታል"</string>
+ <string name="not_checked" msgid="7972320087569023342">"ምልክት አልተደረገበትም"</string>
<string name="whichApplication" msgid="5432266899591255759">"... በመጠቀም ድርጊቱን አጠናቅ"</string>
<string name="whichApplicationNamed" msgid="6969946041713975681">"%1$sን ተጠቅመው እርምጃ ያጠናቅቁ"</string>
<string name="whichApplicationLabel" msgid="7852182961472531728">"እርምጃውን አጠናቅቅ"</string>
@@ -2004,6 +2004,5 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"የተከፈለ ማያን ቀያይር"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"የማያ ገጽ ቁልፍ"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"ቅጽበታዊ ገጽ እይታ"</string>
- <!-- no translation found for accessibility_freeform_caption (7873194416838321119) -->
- <skip />
+ <string name="accessibility_freeform_caption" msgid="7873194416838321119">"የ<xliff:g id="APP_NAME">%1$s</xliff:g> መተግበሪያ በብቅ-ባይ መስኮት ውስጥ።"</string>
</resources>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index bf9eeb2f78be..9928436b2a01 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -196,6 +196,8 @@
<string name="work_profile_deleted_details" msgid="3773706828364418016">"تطبيق المشرف للملف الشخصي للعمل مفقود أو تالف لذا تم حذف الملف الشخصي للعمل والبيانات ذات الصلة. اتصل بالمشرف للحصول على المساعدة."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"لم يعد ملفك الشخصي للعمل متاحًا على هذا الجهاز"</string>
<string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"تم إجراء محاولات كثيرة جدًا لإدخال كلمة المرور"</string>
+ <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+ <skip />
<string name="network_logging_notification_title" msgid="554983187553845004">"تتم إدارة الجهاز"</string>
<string name="network_logging_notification_text" msgid="1327373071132562512">"تدير مؤسستك هذا الجهاز ويمكنها مراقبة حركة بيانات الشبكة. يمكنك النقر للحصول على تفاصيل."</string>
<string name="factory_reset_warning" msgid="6858705527798047809">"سيتم محو بيانات جهازك."</string>
@@ -1196,10 +1198,8 @@
<string name="loading" msgid="3138021523725055037">"جارٍ التحميل…"</string>
<string name="capital_on" msgid="2770685323900821829">"مفعّلة"</string>
<string name="capital_off" msgid="7443704171014626777">"إيقاف"</string>
- <!-- no translation found for checked (9179896827054513119) -->
- <skip />
- <!-- no translation found for not_checked (7972320087569023342) -->
- <skip />
+ <string name="checked" msgid="9179896827054513119">"تم وضع علامة"</string>
+ <string name="not_checked" msgid="7972320087569023342">"لم يتم وضع علامة"</string>
<string name="whichApplication" msgid="5432266899591255759">"إكمال الإجراء باستخدام"</string>
<string name="whichApplicationNamed" msgid="6969946041713975681">"‏إكمال الإجراء باستخدام %1$s"</string>
<string name="whichApplicationLabel" msgid="7852182961472531728">"إكمال الإجراء"</string>
@@ -2140,6 +2140,5 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"تبديل \"تقسيم الشاشة\""</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"شاشة القفل"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"لقطة شاشة"</string>
- <!-- no translation found for accessibility_freeform_caption (7873194416838321119) -->
- <skip />
+ <string name="accessibility_freeform_caption" msgid="7873194416838321119">"تطبيق <xliff:g id="APP_NAME">%1$s</xliff:g> في نافذة منبثقة"</string>
</resources>
diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml
index 7fa36deb967f..cfd62394fd79 100644
--- a/core/res/res/values-as/strings.xml
+++ b/core/res/res/values-as/strings.xml
@@ -188,6 +188,8 @@
<string name="work_profile_deleted_details" msgid="3773706828364418016">"কৰ্মস্থানৰ প্ৰ\'ফাইলৰ প্ৰশাসক এপ্ নাই বা ব্যৱহাৰযোগ্য হৈ থকা নাই। যাৰ ফলত আপোনাৰ কৰ্মস্থানৰ প্ৰ\'ফাইল আৰু ইয়াৰ লগত জড়িত অন্য ডেটাসমূহ মচা হৈছে। সহায়ৰ বাবে আপোনাৰ প্ৰশাসকৰ সৈতে সম্পর্ক কৰক।"</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"আপোনাৰ কৰ্মস্থানৰ প্ৰ\'ফাইল এই ডিভাইচটোত আৰু উপলব্ধ নহয়"</string>
<string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"বহুতবাৰ ভুলকৈ পাছৱৰ্ড দিয়া হৈছে"</string>
+ <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+ <skip />
<string name="network_logging_notification_title" msgid="554983187553845004">"পৰিচালিত ডিভাইচ"</string>
<string name="network_logging_notification_text" msgid="1327373071132562512">"আপোনাৰ প্ৰতিষ্ঠানটোৱে এই ডিভাইচটো পৰিচালনা কৰে আৰু ই নেটৱৰ্কৰ ট্ৰেফিক পৰ্যবেক্ষণ কৰিব পাৰে। সবিশেষ জানিবলৈ টিপক।"</string>
<string name="factory_reset_warning" msgid="6858705527798047809">"আপোনাৰ ডিভাইচৰ ডেটা মচা হ\'ব"</string>
@@ -1116,10 +1118,8 @@
<string name="loading" msgid="3138021523725055037">"ল\'ড কৰি থকা হৈছে…"</string>
<string name="capital_on" msgid="2770685323900821829">"অন কৰক"</string>
<string name="capital_off" msgid="7443704171014626777">"অফ কৰক"</string>
- <!-- no translation found for checked (9179896827054513119) -->
- <skip />
- <!-- no translation found for not_checked (7972320087569023342) -->
- <skip />
+ <string name="checked" msgid="9179896827054513119">"টিক চিহ্ন দিয়া হৈছে"</string>
+ <string name="not_checked" msgid="7972320087569023342">"টিক চিহ্ন দিয়া হোৱা নাই"</string>
<string name="whichApplication" msgid="5432266899591255759">"এয়া ব্যৱহাৰ কৰি কার্য সম্পূর্ণ কৰক"</string>
<string name="whichApplicationNamed" msgid="6969946041713975681">"%1$s ব্যৱহাৰ কৰি কাৰ্যটো সম্পূৰ্ণ কৰক"</string>
<string name="whichApplicationLabel" msgid="7852182961472531728">"কাৰ্য সম্পূৰ্ণ কৰক"</string>
@@ -2004,6 +2004,5 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"বিভাজিত স্ক্ৰীন ট’গল কৰক"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"লক স্ক্ৰীন"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"স্ক্ৰীণশ্বট"</string>
- <!-- no translation found for accessibility_freeform_caption (7873194416838321119) -->
- <skip />
+ <string name="accessibility_freeform_caption" msgid="7873194416838321119">"পপ আপ ৱিণ্ড’ত <xliff:g id="APP_NAME">%1$s</xliff:g> এপ্‌।"</string>
</resources>
diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml
index 85186faa8cf1..a26d49d79d28 100644
--- a/core/res/res/values-az/strings.xml
+++ b/core/res/res/values-az/strings.xml
@@ -188,6 +188,8 @@
<string name="work_profile_deleted_details" msgid="3773706828364418016">"İş profili admin tətbiqi ya yoxdur, ya da korlanıb. Nəticədə iş profili və onunla bağlı data silinib. Kömək üçün admin ilə əlaqə saxlayın."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"İş profili artıq bu cihazda əlçatan deyil"</string>
<string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Həddindən çox parol cəhdi"</string>
+ <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+ <skip />
<string name="network_logging_notification_title" msgid="554983187553845004">"Cihaz idarə olunur"</string>
<string name="network_logging_notification_text" msgid="1327373071132562512">"Təşkilat bu cihazı idarə edir və şəbəkənin ötürülməsinə nəzarət edə bilər. Detallar üçün klikləyin."</string>
<string name="factory_reset_warning" msgid="6858705527798047809">"Cihazınız təmizlənəcəkdir"</string>
@@ -1116,10 +1118,8 @@
<string name="loading" msgid="3138021523725055037">"Yüklənir…"</string>
<string name="capital_on" msgid="2770685323900821829">"AÇIQ"</string>
<string name="capital_off" msgid="7443704171014626777">"QAPALI"</string>
- <!-- no translation found for checked (9179896827054513119) -->
- <skip />
- <!-- no translation found for not_checked (7972320087569023342) -->
- <skip />
+ <string name="checked" msgid="9179896827054513119">"yoxlanılıb"</string>
+ <string name="not_checked" msgid="7972320087569023342">"yoxlanılmayıb"</string>
<string name="whichApplication" msgid="5432266899591255759">"Əməliyyatı tamamlayın:"</string>
<string name="whichApplicationNamed" msgid="6969946041713975681">"%1$s istifadə edərək əməliyyatı tamamlayın"</string>
<string name="whichApplicationLabel" msgid="7852182961472531728">"Əməliyyatı tamamlayın"</string>
@@ -2004,6 +2004,5 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Bölünmüş Ekrana keçid"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Kilid Ekranı"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Ekran şəkli"</string>
- <!-- no translation found for accessibility_freeform_caption (7873194416838321119) -->
- <skip />
+ <string name="accessibility_freeform_caption" msgid="7873194416838321119">"Açilən pəncərədə <xliff:g id="APP_NAME">%1$s</xliff:g> tətbiqi."</string>
</resources>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index d576e8c7fc8d..6d0ae6bab591 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -190,6 +190,8 @@
<string name="work_profile_deleted_details" msgid="3773706828364418016">"Aplikacija za administratore na profilu za Work nedostaje ili je oštećena. Zbog toga su profil za Work i povezani podaci izbrisani. Obratite se administratoru za pomoć."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Profil za Work više nije dostupan na ovom uređaju"</string>
<string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Previše pokušaja unosa lozinke"</string>
+ <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+ <skip />
<string name="network_logging_notification_title" msgid="554983187553845004">"Uređajem se upravlja"</string>
<string name="network_logging_notification_text" msgid="1327373071132562512">"Organizacija upravlja ovim uređajem i može da nadgleda mrežni saobraćaj. Dodirnite za detalje."</string>
<string name="factory_reset_warning" msgid="6858705527798047809">"Uređaj će biti obrisan"</string>
@@ -1136,10 +1138,8 @@
<string name="loading" msgid="3138021523725055037">"Učitava se…"</string>
<string name="capital_on" msgid="2770685323900821829">"DA"</string>
<string name="capital_off" msgid="7443704171014626777">"NE"</string>
- <!-- no translation found for checked (9179896827054513119) -->
- <skip />
- <!-- no translation found for not_checked (7972320087569023342) -->
- <skip />
+ <string name="checked" msgid="9179896827054513119">"označeno je"</string>
+ <string name="not_checked" msgid="7972320087569023342">"nije označeno"</string>
<string name="whichApplication" msgid="5432266899591255759">"Dovršavanje radnje pomoću"</string>
<string name="whichApplicationNamed" msgid="6969946041713975681">"Završite radnju pomoću aplikacije %1$s"</string>
<string name="whichApplicationLabel" msgid="7852182961472531728">"Završi radnju"</string>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index f2fb72ee485f..390e8b190d92 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -192,6 +192,8 @@
<string name="work_profile_deleted_details" msgid="3773706828364418016">"Праграма адміністратара для працоўнага профілю адсутнічае або пашкоджана. У выніку гэтага ваш працоўны профіль і звязаныя з ім даныя былі выдалены. Звярніцеся па дапамогу да адміністратара."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Ваш працоўны профіль больш не даступны на гэтай прыладзе"</string>
<string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Занадта шмат спроб уводу пароля"</string>
+ <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+ <skip />
<string name="network_logging_notification_title" msgid="554983187553845004">"Прылада знаходзіцца пад кіраваннем"</string>
<string name="network_logging_notification_text" msgid="1327373071132562512">"Ваша арганізацыя кіруе гэтай прыладай і можа сачыць за сеткавым трафікам. Дакраніцеся для атрымання дадатковай інфармацыі."</string>
<string name="factory_reset_warning" msgid="6858705527798047809">"Даныя вашай прылады будуць сцерты"</string>
@@ -1156,10 +1158,8 @@
<string name="loading" msgid="3138021523725055037">"Загрузка..."</string>
<string name="capital_on" msgid="2770685323900821829">"Уключыць"</string>
<string name="capital_off" msgid="7443704171014626777">"Выключана"</string>
- <!-- no translation found for checked (9179896827054513119) -->
- <skip />
- <!-- no translation found for not_checked (7972320087569023342) -->
- <skip />
+ <string name="checked" msgid="9179896827054513119">"пазначана"</string>
+ <string name="not_checked" msgid="7972320087569023342">"не пазначана"</string>
<string name="whichApplication" msgid="5432266899591255759">"Завяршыць дзеянне з дапамогай"</string>
<string name="whichApplicationNamed" msgid="6969946041713975681">"Завяршыць дзеянне з дапамогай %1$s"</string>
<string name="whichApplicationLabel" msgid="7852182961472531728">"Завяршыць дзеянне"</string>
@@ -2072,6 +2072,5 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Пераключальнік падзеленага экрана"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Экран блакіроўкі"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Здымак экрана"</string>
- <!-- no translation found for accessibility_freeform_caption (7873194416838321119) -->
- <skip />
+ <string name="accessibility_freeform_caption" msgid="7873194416838321119">"Праграма \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" ва ўсплывальным акне."</string>
</resources>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index f89b985989df..d47229df5d40 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -188,6 +188,8 @@
<string name="work_profile_deleted_details" msgid="3773706828364418016">"Приложението за администриране на служебния потребителски профил липсва или е повредено. В резултат на това той и свързаните с него данни са изтрити. За съдействие се свържете с администратора си."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Служебният ви потребителски профил вече не е налице на това устройство"</string>
<string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Опитите за паролата са твърде много"</string>
+ <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+ <skip />
<string name="network_logging_notification_title" msgid="554983187553845004">"Устройството се управлява"</string>
<string name="network_logging_notification_text" msgid="1327373071132562512">"Организацията ви управлява това устройство и може да наблюдава мрежовия трафик. Докоснете за подробности."</string>
<string name="factory_reset_warning" msgid="6858705527798047809">"Данните на устройството ви ще бъдат изтрити"</string>
@@ -1116,10 +1118,8 @@
<string name="loading" msgid="3138021523725055037">"Зарежда се..."</string>
<string name="capital_on" msgid="2770685323900821829">"ВКЛ"</string>
<string name="capital_off" msgid="7443704171014626777">"ИЗКЛ"</string>
- <!-- no translation found for checked (9179896827054513119) -->
- <skip />
- <!-- no translation found for not_checked (7972320087569023342) -->
- <skip />
+ <string name="checked" msgid="9179896827054513119">"с отметка"</string>
+ <string name="not_checked" msgid="7972320087569023342">"без отметка"</string>
<string name="whichApplication" msgid="5432266899591255759">"Изпълняване на действието чрез"</string>
<string name="whichApplicationNamed" msgid="6969946041713975681">"Завършване на действието посредством %1$s"</string>
<string name="whichApplicationLabel" msgid="7852182961472531728">"Изпълняване на действието"</string>
@@ -2004,6 +2004,5 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Превключване на разделения екран"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Заключен екран"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Екранна снимка"</string>
- <!-- no translation found for accessibility_freeform_caption (7873194416838321119) -->
- <skip />
+ <string name="accessibility_freeform_caption" msgid="7873194416838321119">"Приложението <xliff:g id="APP_NAME">%1$s</xliff:g> в изскачащ прозорец."</string>
</resources>
diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml
index 2086da70e8f5..a767a71265da 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -188,6 +188,8 @@
<string name="work_profile_deleted_details" msgid="3773706828364418016">"কর্মস্থলের প্রোফাইলের প্রশাসক অ্যাপটি হয় নেই, অথবা সেটি ক্ষতিগ্রস্ত হয়েছে৷ এর ফলে আপনার কর্মস্থলের প্রোফাইল এবং সম্পর্কিত ডেটা মুছে ফেলা হয়েছে৷ সহায়তার জন্য আপনার প্রশাসকের সাথে যোগাযোগ করুন৷"</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"আপনার কর্মস্থলের প্রোফাইলটি আর এই ডিভাইসে নেই"</string>
<string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"বহুবার ভুল পাসওয়ার্ড দিয়েছেন"</string>
+ <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+ <skip />
<string name="network_logging_notification_title" msgid="554983187553845004">"ডিভাইসটি পরিচালনা করা হচ্ছে"</string>
<string name="network_logging_notification_text" msgid="1327373071132562512">"আপনার প্রতিষ্ঠান এই ডিভাইসটি পরিচালনা করে এবং এটির নেটওয়ার্ক ট্রাফিকের উপরে নজর রাখতে পারে। বিশদ বিবরণের জন্য ট্যাপ করুন।,"</string>
<string name="factory_reset_warning" msgid="6858705527798047809">"আপনার ডিভাইসটি মুছে ফেলা হবে"</string>
@@ -1116,10 +1118,8 @@
<string name="loading" msgid="3138021523725055037">"লোড হচ্ছে..."</string>
<string name="capital_on" msgid="2770685323900821829">"চালু"</string>
<string name="capital_off" msgid="7443704171014626777">"বন্ধ আছে"</string>
- <!-- no translation found for checked (9179896827054513119) -->
- <skip />
- <!-- no translation found for not_checked (7972320087569023342) -->
- <skip />
+ <string name="checked" msgid="9179896827054513119">"টিকচিহ্ন দেওয়া আছে"</string>
+ <string name="not_checked" msgid="7972320087569023342">"টিকচিহ্ন দেওয়া নেই"</string>
<string name="whichApplication" msgid="5432266899591255759">"এটি ব্যবহার করে ক্রিয়াকলাপ সম্পূর্ণ করুন"</string>
<string name="whichApplicationNamed" msgid="6969946041713975681">"%1$s ব্যবহার করে ক্রিয়াকলাপ সম্পূর্ণ করুন"</string>
<string name="whichApplicationLabel" msgid="7852182961472531728">"ক্রিয়াকলাপ সম্পূর্ণ করুন"</string>
@@ -2004,6 +2004,5 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"স্প্লিট স্ক্রিন টগল করুন"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"লক স্ক্রিন"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"স্ক্রিনশট"</string>
- <!-- no translation found for accessibility_freeform_caption (7873194416838321119) -->
- <skip />
+ <string name="accessibility_freeform_caption" msgid="7873194416838321119">"পপ-আপ উইন্ডোতে <xliff:g id="APP_NAME">%1$s</xliff:g> অ্যাপ।"</string>
</resources>
diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml
index b30ea42659c9..f1c15001e6ae 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -190,6 +190,8 @@
<string name="work_profile_deleted_details" msgid="3773706828364418016">"Nedostaje aplikacija administratora za radni profil ili je neispravna. Zbog toga su vaš radni profil i povezani podaci izbrisani. Obratite administratoru za pomoć."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Radni profil više nije dostupan na ovom uređaju"</string>
<string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Previše puta ste pokušali otključati uređaj"</string>
+ <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+ <skip />
<string name="network_logging_notification_title" msgid="554983187553845004">"Uređajem se upravlja."</string>
<string name="network_logging_notification_text" msgid="1327373071132562512">"Vaša organizacija upravlja ovim uređajem i može pratiti mrežni saobraćaj. Dodirnite za detalje."</string>
<string name="factory_reset_warning" msgid="6858705527798047809">"Uređaj će biti izbrisan"</string>
@@ -1136,10 +1138,8 @@
<string name="loading" msgid="3138021523725055037">"Učitavanje..."</string>
<string name="capital_on" msgid="2770685323900821829">"Uključeno"</string>
<string name="capital_off" msgid="7443704171014626777">"Isključeno"</string>
- <!-- no translation found for checked (9179896827054513119) -->
- <skip />
- <!-- no translation found for not_checked (7972320087569023342) -->
- <skip />
+ <string name="checked" msgid="9179896827054513119">"označeno"</string>
+ <string name="not_checked" msgid="7972320087569023342">"nije označeno"</string>
<string name="whichApplication" msgid="5432266899591255759">"Izvrši akciju koristeći"</string>
<string name="whichApplicationNamed" msgid="6969946041713975681">"Dovršite akciju koristeći %1$s"</string>
<string name="whichApplicationLabel" msgid="7852182961472531728">"Izvršiti akciju"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 560e49354b42..4b1940518584 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -188,6 +188,8 @@
<string name="work_profile_deleted_details" msgid="3773706828364418016">"Falta l\'aplicació d\'administració del perfil professional o està malmesa. Com a conseqüència, s\'han suprimit el teu perfil professional i les dades relacionades. Contacta amb l\'administrador per obtenir ajuda."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"El teu perfil professional ja no està disponible en aquest dispositiu"</string>
<string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Has intentat introduir la contrasenya massa vegades"</string>
+ <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+ <skip />
<string name="network_logging_notification_title" msgid="554983187553845004">"El dispositiu està gestionat"</string>
<string name="network_logging_notification_text" msgid="1327373071132562512">"La teva organització gestiona aquest dispositiu i és possible que supervisi el trànsit de xarxa. Toca per obtenir més informació."</string>
<string name="factory_reset_warning" msgid="6858705527798047809">"El contingut del dispositiu s\'esborrarà"</string>
@@ -1116,10 +1118,8 @@
<string name="loading" msgid="3138021523725055037">"S\'està carregant…"</string>
<string name="capital_on" msgid="2770685323900821829">"SÍ"</string>
<string name="capital_off" msgid="7443704171014626777">"NO"</string>
- <!-- no translation found for checked (9179896827054513119) -->
- <skip />
- <!-- no translation found for not_checked (7972320087569023342) -->
- <skip />
+ <string name="checked" msgid="9179896827054513119">"seleccionat"</string>
+ <string name="not_checked" msgid="7972320087569023342">"no seleccionat"</string>
<string name="whichApplication" msgid="5432266899591255759">"Completa l\'acció mitjançant"</string>
<string name="whichApplicationNamed" msgid="6969946041713975681">"Completa l\'acció amb %1$s"</string>
<string name="whichApplicationLabel" msgid="7852182961472531728">"Completa l\'acció"</string>
@@ -2004,6 +2004,5 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Commuta Pantalla dividida"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Pantalla de bloqueig"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Captura de pantalla"</string>
- <!-- no translation found for accessibility_freeform_caption (7873194416838321119) -->
- <skip />
+ <string name="accessibility_freeform_caption" msgid="7873194416838321119">"Aplicació <xliff:g id="APP_NAME">%1$s</xliff:g> a la finestra emergent."</string>
</resources>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 9527c150e5ec..22fd4c6464ef 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -192,6 +192,8 @@
<string name="work_profile_deleted_details" msgid="3773706828364418016">"Aplikace pro správu pracovního profilu chybí nebo je poškozena. Váš pracovní profil a související data proto byla smazána. Požádejte o pomoc administrátora."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Váš pracovní profil v tomto zařízení již není k dispozici"</string>
<string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Příliš mnoho pokusů o zadání hesla"</string>
+ <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+ <skip />
<string name="network_logging_notification_title" msgid="554983187553845004">"Zařízení je spravováno"</string>
<string name="network_logging_notification_text" msgid="1327373071132562512">"Toto zařízení je spravováno vaší organizací, která může sledovat síťový provoz. Podrobnosti zobrazíte klepnutím."</string>
<string name="factory_reset_warning" msgid="6858705527798047809">"Zařízení bude vymazáno"</string>
@@ -1156,10 +1158,8 @@
<string name="loading" msgid="3138021523725055037">"Načítání..."</string>
<string name="capital_on" msgid="2770685323900821829">"I"</string>
<string name="capital_off" msgid="7443704171014626777">"O"</string>
- <!-- no translation found for checked (9179896827054513119) -->
- <skip />
- <!-- no translation found for not_checked (7972320087569023342) -->
- <skip />
+ <string name="checked" msgid="9179896827054513119">"vybráno"</string>
+ <string name="not_checked" msgid="7972320087569023342">"nevybráno"</string>
<string name="whichApplication" msgid="5432266899591255759">"Dokončit akci pomocí aplikace"</string>
<string name="whichApplicationNamed" msgid="6969946041713975681">"Dokončit akci pomocí aplikace %1$s"</string>
<string name="whichApplicationLabel" msgid="7852182961472531728">"Dokončit akci"</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 852256e9c79f..4475a1bd3e13 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -188,6 +188,8 @@
<string name="work_profile_deleted_details" msgid="3773706828364418016">"Administrationsappen til arbejdsprofilen mangler eller er beskadiget. Derfor er din arbejdsprofil og dine relaterede data blevet slettet. Kontakt din administrator for at få hjælp."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Din arbejdsprofil er ikke længere tilgængelig på denne enhed"</string>
<string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"For mange mislykkede adgangskodeforsøg"</string>
+ <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+ <skip />
<string name="network_logging_notification_title" msgid="554983187553845004">"Dette er en administreret enhed"</string>
<string name="network_logging_notification_text" msgid="1327373071132562512">"Din organisation administrerer denne enhed og kan overvåge netværkstrafik. Tryk for at se info."</string>
<string name="factory_reset_warning" msgid="6858705527798047809">"Enheden slettes"</string>
@@ -1116,10 +1118,8 @@
<string name="loading" msgid="3138021523725055037">"Indlæser…"</string>
<string name="capital_on" msgid="2770685323900821829">"TIL"</string>
<string name="capital_off" msgid="7443704171014626777">"FRA"</string>
- <!-- no translation found for checked (9179896827054513119) -->
- <skip />
- <!-- no translation found for not_checked (7972320087569023342) -->
- <skip />
+ <string name="checked" msgid="9179896827054513119">"slået til"</string>
+ <string name="not_checked" msgid="7972320087569023342">"slået fra"</string>
<string name="whichApplication" msgid="5432266899591255759">"Brug"</string>
<string name="whichApplicationNamed" msgid="6969946041713975681">"Gennemfør handling ved hjælp af %1$s"</string>
<string name="whichApplicationLabel" msgid="7852182961472531728">"Afslut handling"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 8d86317b8bd2..2489fca648a9 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -188,6 +188,8 @@
<string name="work_profile_deleted_details" msgid="3773706828364418016">"Die Admin-App für das Arbeitsprofil fehlt oder ist beschädigt. Daher wurden dein Arbeitsprofil und alle zugehörigen Daten gelöscht. Bitte wende dich für weitere Hilfe an deinen Administrator."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Dein Arbeitsprofil ist auf diesem Gerät nicht mehr verfügbar"</string>
<string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Zu viele falsche Passworteingaben"</string>
+ <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+ <skip />
<string name="network_logging_notification_title" msgid="554983187553845004">"Dies ist ein verwaltetes Gerät"</string>
<string name="network_logging_notification_text" msgid="1327373071132562512">"Deine Organisation verwaltet dieses Gerät und überprüft unter Umständen den Netzwerkverkehr. Tippe hier, um weitere Informationen zu erhalten."</string>
<string name="factory_reset_warning" msgid="6858705527798047809">"Die Daten auf deinem Gerät werden gelöscht."</string>
@@ -1116,10 +1118,8 @@
<string name="loading" msgid="3138021523725055037">"Wird geladen…"</string>
<string name="capital_on" msgid="2770685323900821829">"AN"</string>
<string name="capital_off" msgid="7443704171014626777">"AUS"</string>
- <!-- no translation found for checked (9179896827054513119) -->
- <skip />
- <!-- no translation found for not_checked (7972320087569023342) -->
- <skip />
+ <string name="checked" msgid="9179896827054513119">"aktiviert"</string>
+ <string name="not_checked" msgid="7972320087569023342">"deaktiviert"</string>
<string name="whichApplication" msgid="5432266899591255759">"Aktion durchführen mit"</string>
<string name="whichApplicationNamed" msgid="6969946041713975681">"Aktion mit %1$s abschließen"</string>
<string name="whichApplicationLabel" msgid="7852182961472531728">"Abschließen"</string>
@@ -1539,7 +1539,7 @@
<string name="launchBrowserDefault" msgid="6328349989932924119">"Browser starten?"</string>
<string name="SetupCallDefault" msgid="5581740063237175247">"Anruf annehmen?"</string>
<string name="activity_resolver_use_always" msgid="5575222334666843269">"Immer"</string>
- <string name="activity_resolver_set_always" msgid="4142825808921411476">"Auf \"Immer öffnen\" festlegen"</string>
+ <string name="activity_resolver_set_always" msgid="4142825808921411476">"Immer damit öffnen"</string>
<string name="activity_resolver_use_once" msgid="948462794469672658">"Nur diesmal"</string>
<string name="activity_resolver_app_settings" msgid="6758823206817748026">"Einstellungen"</string>
<string name="activity_resolver_work_profiles_support" msgid="4071345609235361269">"Das Arbeitsprofil wird von %1$s nicht unterstützt."</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 890a54881dee..6c76a1f3d2ef 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -188,6 +188,8 @@
<string name="work_profile_deleted_details" msgid="3773706828364418016">"Η εφαρμογή διαχείρισης προφίλ εργασίας είτε λείπει είτε είναι κατεστραμμένη. Ως αποτέλεσμα, διαγράφηκε το προφίλ εργασίας και τα σχετικά δεδομένα. Επικοινωνήστε με τον διαχειριστή σας για βοήθεια."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Το προφίλ εργασίας σας δεν είναι πια διαθέσιμο σε αυτήν τη συσκευή"</string>
<string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Πάρα πολλές προσπάθειες εισαγωγής κωδικού πρόσβασης"</string>
+ <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+ <skip />
<string name="network_logging_notification_title" msgid="554983187553845004">"Η συσκευή είναι διαχειριζόμενη"</string>
<string name="network_logging_notification_text" msgid="1327373071132562512">"Ο οργανισμός σας διαχειρίζεται αυτήν τη συσκευή και ενδέχεται να παρακολουθεί την επισκεψιμότητα δικτύου. Πατήστε για λεπτομέρειες."</string>
<string name="factory_reset_warning" msgid="6858705527798047809">"Η συσκευή σας θα διαγραφεί"</string>
@@ -1116,10 +1118,8 @@
<string name="loading" msgid="3138021523725055037">"Φόρτωση…"</string>
<string name="capital_on" msgid="2770685323900821829">"Ενεργό"</string>
<string name="capital_off" msgid="7443704171014626777">"Ανενεργό"</string>
- <!-- no translation found for checked (9179896827054513119) -->
- <skip />
- <!-- no translation found for not_checked (7972320087569023342) -->
- <skip />
+ <string name="checked" msgid="9179896827054513119">"επιλεγμένο"</string>
+ <string name="not_checked" msgid="7972320087569023342">"μη επιλεγμένο"</string>
<string name="whichApplication" msgid="5432266899591255759">"Ολοκλήρωση ενέργειας με τη χρήση"</string>
<string name="whichApplicationNamed" msgid="6969946041713975681">"Ολοκληρωμένη ενέργεια με χρήση %1$s"</string>
<string name="whichApplicationLabel" msgid="7852182961472531728">"Ολοκλήρωση ενέργειας"</string>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index 468b9a3333db..e5f610b4629c 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -188,6 +188,8 @@
<string name="work_profile_deleted_details" msgid="3773706828364418016">"The work profile admin app is either missing or corrupted. As a result, your work profile and related data have been deleted. Contact your admin for assistance."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Your work profile is no longer available on this device"</string>
<string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Too many password attempts"</string>
+ <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+ <skip />
<string name="network_logging_notification_title" msgid="554983187553845004">"Device is managed"</string>
<string name="network_logging_notification_text" msgid="1327373071132562512">"Your organisation manages this device and may monitor network traffic. Tap for details."</string>
<string name="factory_reset_warning" msgid="6858705527798047809">"Your device will be erased"</string>
@@ -1116,10 +1118,8 @@
<string name="loading" msgid="3138021523725055037">"Loading…"</string>
<string name="capital_on" msgid="2770685323900821829">"ON"</string>
<string name="capital_off" msgid="7443704171014626777">"OFF"</string>
- <!-- no translation found for checked (9179896827054513119) -->
- <skip />
- <!-- no translation found for not_checked (7972320087569023342) -->
- <skip />
+ <string name="checked" msgid="9179896827054513119">"ticked"</string>
+ <string name="not_checked" msgid="7972320087569023342">"not ticked"</string>
<string name="whichApplication" msgid="5432266899591255759">"Complete action using"</string>
<string name="whichApplicationNamed" msgid="6969946041713975681">"Complete action using %1$s"</string>
<string name="whichApplicationLabel" msgid="7852182961472531728">"Complete action"</string>
diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml
index 2c715772d0a0..2cff16f93942 100644
--- a/core/res/res/values-en-rCA/strings.xml
+++ b/core/res/res/values-en-rCA/strings.xml
@@ -188,6 +188,8 @@
<string name="work_profile_deleted_details" msgid="3773706828364418016">"The work profile admin app is either missing or corrupted. As a result, your work profile and related data have been deleted. Contact your admin for assistance."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Your work profile is no longer available on this device"</string>
<string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Too many password attempts"</string>
+ <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+ <skip />
<string name="network_logging_notification_title" msgid="554983187553845004">"Device is managed"</string>
<string name="network_logging_notification_text" msgid="1327373071132562512">"Your organisation manages this device and may monitor network traffic. Tap for details."</string>
<string name="factory_reset_warning" msgid="6858705527798047809">"Your device will be erased"</string>
@@ -1116,10 +1118,8 @@
<string name="loading" msgid="3138021523725055037">"Loading…"</string>
<string name="capital_on" msgid="2770685323900821829">"ON"</string>
<string name="capital_off" msgid="7443704171014626777">"OFF"</string>
- <!-- no translation found for checked (9179896827054513119) -->
- <skip />
- <!-- no translation found for not_checked (7972320087569023342) -->
- <skip />
+ <string name="checked" msgid="9179896827054513119">"ticked"</string>
+ <string name="not_checked" msgid="7972320087569023342">"not ticked"</string>
<string name="whichApplication" msgid="5432266899591255759">"Complete action using"</string>
<string name="whichApplicationNamed" msgid="6969946041713975681">"Complete action using %1$s"</string>
<string name="whichApplicationLabel" msgid="7852182961472531728">"Complete action"</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 468b9a3333db..e5f610b4629c 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -188,6 +188,8 @@
<string name="work_profile_deleted_details" msgid="3773706828364418016">"The work profile admin app is either missing or corrupted. As a result, your work profile and related data have been deleted. Contact your admin for assistance."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Your work profile is no longer available on this device"</string>
<string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Too many password attempts"</string>
+ <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+ <skip />
<string name="network_logging_notification_title" msgid="554983187553845004">"Device is managed"</string>
<string name="network_logging_notification_text" msgid="1327373071132562512">"Your organisation manages this device and may monitor network traffic. Tap for details."</string>
<string name="factory_reset_warning" msgid="6858705527798047809">"Your device will be erased"</string>
@@ -1116,10 +1118,8 @@
<string name="loading" msgid="3138021523725055037">"Loading…"</string>
<string name="capital_on" msgid="2770685323900821829">"ON"</string>
<string name="capital_off" msgid="7443704171014626777">"OFF"</string>
- <!-- no translation found for checked (9179896827054513119) -->
- <skip />
- <!-- no translation found for not_checked (7972320087569023342) -->
- <skip />
+ <string name="checked" msgid="9179896827054513119">"ticked"</string>
+ <string name="not_checked" msgid="7972320087569023342">"not ticked"</string>
<string name="whichApplication" msgid="5432266899591255759">"Complete action using"</string>
<string name="whichApplicationNamed" msgid="6969946041713975681">"Complete action using %1$s"</string>
<string name="whichApplicationLabel" msgid="7852182961472531728">"Complete action"</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index 468b9a3333db..e5f610b4629c 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -188,6 +188,8 @@
<string name="work_profile_deleted_details" msgid="3773706828364418016">"The work profile admin app is either missing or corrupted. As a result, your work profile and related data have been deleted. Contact your admin for assistance."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Your work profile is no longer available on this device"</string>
<string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Too many password attempts"</string>
+ <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+ <skip />
<string name="network_logging_notification_title" msgid="554983187553845004">"Device is managed"</string>
<string name="network_logging_notification_text" msgid="1327373071132562512">"Your organisation manages this device and may monitor network traffic. Tap for details."</string>
<string name="factory_reset_warning" msgid="6858705527798047809">"Your device will be erased"</string>
@@ -1116,10 +1118,8 @@
<string name="loading" msgid="3138021523725055037">"Loading…"</string>
<string name="capital_on" msgid="2770685323900821829">"ON"</string>
<string name="capital_off" msgid="7443704171014626777">"OFF"</string>
- <!-- no translation found for checked (9179896827054513119) -->
- <skip />
- <!-- no translation found for not_checked (7972320087569023342) -->
- <skip />
+ <string name="checked" msgid="9179896827054513119">"ticked"</string>
+ <string name="not_checked" msgid="7972320087569023342">"not ticked"</string>
<string name="whichApplication" msgid="5432266899591255759">"Complete action using"</string>
<string name="whichApplicationNamed" msgid="6969946041713975681">"Complete action using %1$s"</string>
<string name="whichApplicationLabel" msgid="7852182961472531728">"Complete action"</string>
diff --git a/core/res/res/values-en-rXC/strings.xml b/core/res/res/values-en-rXC/strings.xml
index 03ed6a5c8de3..6d536e43a26c 100644
--- a/core/res/res/values-en-rXC/strings.xml
+++ b/core/res/res/values-en-rXC/strings.xml
@@ -188,6 +188,8 @@
<string name="work_profile_deleted_details" msgid="3773706828364418016">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‎‎‎‏‎‏‏‏‏‎‏‏‏‎‎‏‏‎‎‏‎‏‏‏‎‏‏‏‎‎‏‏‏‏‎‎‏‎‎‎‎‎‏‎‎‎‏‎‏‏‏‏‏‎‎‎‎‎‎The work profile admin app is either missing or corrupted. As a result, your work profile and related data have been deleted. Contact your admin for assistance.‎‏‎‎‏‎"</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‏‎‎‏‏‎‎‎‎‎‏‏‏‏‎‎‎‏‎‎‏‎‏‏‎‎‏‎‎‏‏‎‏‎‎‏‏‎‎‎‎‎‏‎‎‎‏‏‏‏‎‏‎‎‎‎‎‎‎Your work profile is no longer available on this device‎‏‎‎‏‎"</string>
<string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‏‎‏‏‏‏‏‏‏‎‎‎‎‏‎‏‎‎‎‎‏‏‎‎‎‎‎‏‎‎‏‏‏‎‎‎‎‎‏‎‎‎‎‏‏‏‏‏‏‏‎‎‏‏‏‏‏‏‎Too many password attempts‎‏‎‎‏‎"</string>
+ <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+ <skip />
<string name="network_logging_notification_title" msgid="554983187553845004">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‏‏‏‏‏‎‏‏‎‎‏‏‏‎‏‏‎‎‏‎‎‏‎‎‎‏‎‎‏‏‎‎‎‏‏‎‎‏‏‏‎‏‎‏‏‏‏‏‏‏‏‏‎‎‎‎‏‏‎‎‎Device is managed‎‏‎‎‏‎"</string>
<string name="network_logging_notification_text" msgid="1327373071132562512">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‏‎‎‏‏‎‏‎‏‏‏‏‎‎‎‏‏‎‏‏‎‎‎‏‏‎‏‎‎‎‎‏‎‏‎‏‎‎‎‏‏‎‏‎‎‏‎‏‎‎‎‏‎‏‎‎‎‎‎Your organization manages this device and may monitor network traffic. Tap for details.‎‏‎‎‏‎"</string>
<string name="factory_reset_warning" msgid="6858705527798047809">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‏‏‎‎‏‎‏‏‏‏‎‎‎‎‎‏‎‎‎‏‎‏‎‏‏‎‏‎‏‎‏‎‏‏‎‏‏‎‏‎‎‏‎‎‏‎‎‏‎‎‎‏‎‎‎‎‎‏‎Your device will be erased‎‏‎‎‏‎"</string>
@@ -1116,10 +1118,8 @@
<string name="loading" msgid="3138021523725055037">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‏‏‏‎‎‎‏‏‎‎‎‏‏‏‏‏‎‏‏‏‏‏‎‎‏‏‎‎‏‎‏‎‏‏‎‎‏‎‏‎‎‏‎‏‏‏‎‏‎‎‎‎‏‏‏‏‎‏‎Loading…‎‏‎‎‏‎"</string>
<string name="capital_on" msgid="2770685323900821829">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‏‎‎‏‏‏‎‎‏‏‎‏‏‏‎‎‏‏‏‎‎‏‏‏‏‏‎‏‎‏‎‎‏‏‎‏‏‏‏‏‏‏‎‎‏‎‎‎‎‏‎‏‎‎‎‏‎‏‎ON‎‏‎‎‏‎"</string>
<string name="capital_off" msgid="7443704171014626777">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‏‏‎‏‎‎‏‏‎‏‎‏‎‏‏‎‎‏‏‎‎‎‎‎‎‏‎‏‎‎‏‏‏‎‎‏‏‎‏‎‏‏‏‎‎‏‏‏‎‏‏‏‎‏‏‎‎‏‎OFF‎‏‎‎‏‎"</string>
- <!-- no translation found for checked (9179896827054513119) -->
- <skip />
- <!-- no translation found for not_checked (7972320087569023342) -->
- <skip />
+ <string name="checked" msgid="9179896827054513119">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‎‎‏‎‏‏‎‎‎‏‎‏‏‏‎‎‎‎‏‏‎‏‏‏‎‏‎‏‏‎‏‎‏‎‎‎‏‏‏‎‏‏‎‏‏‏‏‎‏‏‏‏‏‎checked‎‏‎‎‏‎"</string>
+ <string name="not_checked" msgid="7972320087569023342">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‏‎‏‎‏‎‎‎‏‏‎‏‎‏‏‏‏‎‏‏‏‎‎‎‎‏‎‏‏‎‎‏‏‏‎‏‎‎‎‎‏‏‎‏‎‎‎‎‎‏‎‏‏‎‏‏‏‎‎not checked‎‏‎‎‏‎"</string>
<string name="whichApplication" msgid="5432266899591255759">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‏‏‎‏‏‎‎‎‏‏‎‏‎‎‏‎‎‏‏‏‏‏‎‏‏‎‏‎‏‏‏‎‏‏‎‎‏‏‏‏‏‏‏‏‎‏‎‏‏‎‏‏‎‎‏‏‏‏‎Complete action using‎‏‎‎‏‎"</string>
<string name="whichApplicationNamed" msgid="6969946041713975681">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‎‎‏‎‏‏‏‎‏‎‎‎‏‏‏‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‎‎‎‎‎‎‎‎‎‎‎‎‎‏‏‎‎‎‎‏‏‎‎‎‎‎‎‏‎Complete action using %1$s‎‏‎‎‏‎"</string>
<string name="whichApplicationLabel" msgid="7852182961472531728">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‎‎‏‏‏‏‏‎‎‎‏‎‎‎‏‏‏‎‏‏‎‎‏‏‎‏‎‎‎‎‎‎‎‏‏‏‏‏‎‎‎‏‏‏‏‎‏‏‎‏‎‎‎‏‎‎‎‎‎Complete action‎‏‎‎‏‎"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 6d0caff65dbb..3b9c7ad74957 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -188,6 +188,8 @@
<string name="work_profile_deleted_details" msgid="3773706828364418016">"La app de administración de perfil de trabajo no se encuentra o está dañada. Por lo tanto, se borraron tu perfil de trabajo y los datos relacionados. Para obtener asistencia, comunícate con el administrador."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Tu perfil de trabajo ya no está disponible en este dispositivo"</string>
<string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Demasiados intentos para ingresar la contraseña"</string>
+ <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+ <skip />
<string name="network_logging_notification_title" msgid="554983187553845004">"Dispositivo administrado"</string>
<string name="network_logging_notification_text" msgid="1327373071132562512">"Tu organización administra este dispositivo y es posible que controle el tráfico de red. Presiona para obtener más información."</string>
<string name="factory_reset_warning" msgid="6858705527798047809">"Se borrarán los datos del dispositivo"</string>
@@ -1116,10 +1118,8 @@
<string name="loading" msgid="3138021523725055037">"Cargando…"</string>
<string name="capital_on" msgid="2770685323900821829">"Sí"</string>
<string name="capital_off" msgid="7443704171014626777">"No"</string>
- <!-- no translation found for checked (9179896827054513119) -->
- <skip />
- <!-- no translation found for not_checked (7972320087569023342) -->
- <skip />
+ <string name="checked" msgid="9179896827054513119">"activado"</string>
+ <string name="not_checked" msgid="7972320087569023342">"desactivado"</string>
<string name="whichApplication" msgid="5432266899591255759">"Completar la acción mediante"</string>
<string name="whichApplicationNamed" msgid="6969946041713975681">"Completar acción con %1$s"</string>
<string name="whichApplicationLabel" msgid="7852182961472531728">"Completar acción"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index ca5097bf3356..2e749043299a 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -188,6 +188,8 @@
<string name="work_profile_deleted_details" msgid="3773706828364418016">"Falta la aplicación de administración del perfil de trabajo o está dañada. Por ello, se han eliminado tu perfil de trabajo y los datos relacionados. Ponte en contacto con el administrador para obtener ayuda."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Tu perfil de trabajo ya no está disponible en este dispositivo"</string>
<string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Has fallado demasiadas veces al introducir la contraseña"</string>
+ <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+ <skip />
<string name="network_logging_notification_title" msgid="554983187553845004">"El dispositivo está administrado"</string>
<string name="network_logging_notification_text" msgid="1327373071132562512">"Tu organización administra este dispositivo y puede supervisar el tráfico de red. Toca la notificación para obtener más información."</string>
<string name="factory_reset_warning" msgid="6858705527798047809">"Tu dispositivo se borrará"</string>
@@ -1116,10 +1118,8 @@
<string name="loading" msgid="3138021523725055037">"Cargando..."</string>
<string name="capital_on" msgid="2770685323900821829">"ACTIVADO"</string>
<string name="capital_off" msgid="7443704171014626777">"DESACTIVADO"</string>
- <!-- no translation found for checked (9179896827054513119) -->
- <skip />
- <!-- no translation found for not_checked (7972320087569023342) -->
- <skip />
+ <string name="checked" msgid="9179896827054513119">"seleccionado"</string>
+ <string name="not_checked" msgid="7972320087569023342">"no seleccionado"</string>
<string name="whichApplication" msgid="5432266899591255759">"Completar acción utilizando"</string>
<string name="whichApplicationNamed" msgid="6969946041713975681">"Completar acción con %1$s"</string>
<string name="whichApplicationLabel" msgid="7852182961472531728">"Completar acción"</string>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index 6b01527df2c8..85612549de25 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -188,6 +188,8 @@
<string name="work_profile_deleted_details" msgid="3773706828364418016">"Tööprofiili administraatori rakendus puudub või on rikutud. Seetõttu on teie tööprofiil ja seotud andmed kustutatud. Abi saamiseks võtke ühendust administraatoriga."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Teie tööprofiil pole selles seadmes enam saadaval"</string>
<string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Liiga palju paroolikatseid"</string>
+ <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+ <skip />
<string name="network_logging_notification_title" msgid="554983187553845004">"Seade on hallatud"</string>
<string name="network_logging_notification_text" msgid="1327373071132562512">"Teie organisatsioon haldab seda seadet ja võib jälgida võrguliiklust. Puudutage üksikasjade vaatamiseks."</string>
<string name="factory_reset_warning" msgid="6858705527798047809">"Seade kustutatakse"</string>
@@ -1116,10 +1118,8 @@
<string name="loading" msgid="3138021523725055037">"Laadimine ..."</string>
<string name="capital_on" msgid="2770685323900821829">"SEES"</string>
<string name="capital_off" msgid="7443704171014626777">"VÄLJAS"</string>
- <!-- no translation found for checked (9179896827054513119) -->
- <skip />
- <!-- no translation found for not_checked (7972320087569023342) -->
- <skip />
+ <string name="checked" msgid="9179896827054513119">"märgitud"</string>
+ <string name="not_checked" msgid="7972320087569023342">"märkimata"</string>
<string name="whichApplication" msgid="5432266899591255759">"Lõpetage toiming rakendusega"</string>
<string name="whichApplicationNamed" msgid="6969946041713975681">"Toimingu lõpetamine, kasutades rakendust %1$s"</string>
<string name="whichApplicationLabel" msgid="7852182961472531728">"Vii toiming lõpule"</string>
@@ -2004,6 +2004,5 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Vaheta jagatud ekraanikuva"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Lukustuskuva"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Ekraanipilt"</string>
- <!-- no translation found for accessibility_freeform_caption (7873194416838321119) -->
- <skip />
+ <string name="accessibility_freeform_caption" msgid="7873194416838321119">"Rakendus <xliff:g id="APP_NAME">%1$s</xliff:g> on hüpikaknas."</string>
</resources>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index 66672ddf6ab0..263b5ed7e232 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -188,6 +188,8 @@
<string name="work_profile_deleted_details" msgid="3773706828364418016">"Laneko profila administratzeko aplikazioa falta da edo hondatuta dago. Ondorioz, ezabatu egin dira laneko profila bera eta harekin erlazionatutako datuak. Laguntza lortzeko, jarri administratzailearekin harremanetan."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Laneko profila ez dago erabilgarri gailu honetan"</string>
<string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Gehiegitan saiatu zara pasahitza idazten"</string>
+ <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+ <skip />
<string name="network_logging_notification_title" msgid="554983187553845004">"Jabeak kudeatzen du gailua"</string>
<string name="network_logging_notification_text" msgid="1327373071132562512">"Erakundeak kudeatzen du gailua eta baliteke sareko trafikoa gainbegiratzea. Sakatu hau xehetasunak ikusteko."</string>
<string name="factory_reset_warning" msgid="6858705527798047809">"Gailuko datuak ezabatu egingo dira"</string>
@@ -1116,10 +1118,8 @@
<string name="loading" msgid="3138021523725055037">"Kargatzen…"</string>
<string name="capital_on" msgid="2770685323900821829">"AKTIBATUTA"</string>
<string name="capital_off" msgid="7443704171014626777">"DESAKTIBATUTA"</string>
- <!-- no translation found for checked (9179896827054513119) -->
- <skip />
- <!-- no translation found for not_checked (7972320087569023342) -->
- <skip />
+ <string name="checked" msgid="9179896827054513119">"markatuta"</string>
+ <string name="not_checked" msgid="7972320087569023342">"markatu gabe"</string>
<string name="whichApplication" msgid="5432266899591255759">"Gauzatu ekintza hau erabilita:"</string>
<string name="whichApplicationNamed" msgid="6969946041713975681">"Osatu ekintza %1$s erabiliz"</string>
<string name="whichApplicationLabel" msgid="7852182961472531728">"Osatu ekintza"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index c10dba53dd66..997b6aff7835 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -188,6 +188,8 @@
<string name="work_profile_deleted_details" msgid="3773706828364418016">"برنامه سرپرست نمایه کاری یا وجود ندارد یا خراب است. در نتیجه، نمایه کاری شما و داده‌های مرتبط با آن حذف شده است. برای دریافت راهنمایی با سرپرست سیستم تماس بگیرید."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"نمایه کاری شما دیگر در این دستگاه دردسترس نیست"</string>
<string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"تلاش‌های بسیار زیادی برای وارد کردن گذرواژه انجام شده است"</string>
+ <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+ <skip />
<string name="network_logging_notification_title" msgid="554983187553845004">"دستگاه مدیریت می‌شود"</string>
<string name="network_logging_notification_text" msgid="1327373071132562512">"سازمانتان این دستگاه را مدیریت می‌کند و ممکن است ترافیک شبکه را پایش کند. برای اطلاع از جزئیات، ضربه بزنید."</string>
<string name="factory_reset_warning" msgid="6858705527798047809">"دستگاهتان پاک خواهد شد"</string>
@@ -1116,10 +1118,8 @@
<string name="loading" msgid="3138021523725055037">"درحال بارکردن…"</string>
<string name="capital_on" msgid="2770685323900821829">"روشن"</string>
<string name="capital_off" msgid="7443704171014626777">"خاموش"</string>
- <!-- no translation found for checked (9179896827054513119) -->
- <skip />
- <!-- no translation found for not_checked (7972320087569023342) -->
- <skip />
+ <string name="checked" msgid="9179896827054513119">"علامت‌زده‌شده"</string>
+ <string name="not_checked" msgid="7972320087569023342">"بدون علامت"</string>
<string name="whichApplication" msgid="5432266899591255759">"تکمیل عملکرد با استفاده از"</string>
<string name="whichApplicationNamed" msgid="6969946041713975681">"‏تکمیل عملکرد با استفاده از %1$s"</string>
<string name="whichApplicationLabel" msgid="7852182961472531728">"تکمیل عملکرد"</string>
@@ -2004,6 +2004,5 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"تغییر وضعیت صفحهٔ دونیمه"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"صفحه قفل"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"عکس صفحه‌نمایش"</string>
- <!-- no translation found for accessibility_freeform_caption (7873194416838321119) -->
- <skip />
+ <string name="accessibility_freeform_caption" msgid="7873194416838321119">"برنامه <xliff:g id="APP_NAME">%1$s</xliff:g> در پنجره بالاپر."</string>
</resources>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 35addd127aad..86badf6dbf89 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -188,6 +188,8 @@
<string name="work_profile_deleted_details" msgid="3773706828364418016">"Työprofiilin hallintasovellus puuttuu tai se on vioittunut. Tästä syystä työprofiilisi ja siihen liittyvät tiedot on poistettu. Pyydä ohjeita järjestelmänvalvojaltasi."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Työprofiilisi ei ole enää käytettävissä tällä laitteella."</string>
<string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Liikaa salasanayrityksiä"</string>
+ <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+ <skip />
<string name="network_logging_notification_title" msgid="554983187553845004">"Hallinnoitu laite"</string>
<string name="network_logging_notification_text" msgid="1327373071132562512">"Organisaatiosi hallinnoi tätä laitetta ja voi tarkkailla verkkoliikennettä. Katso lisätietoja napauttamalla."</string>
<string name="factory_reset_warning" msgid="6858705527798047809">"Laitteen tiedot poistetaan"</string>
@@ -1116,10 +1118,8 @@
<string name="loading" msgid="3138021523725055037">"Ladataan…"</string>
<string name="capital_on" msgid="2770685323900821829">"PÄÄLLÄ"</string>
<string name="capital_off" msgid="7443704171014626777">"POIS"</string>
- <!-- no translation found for checked (9179896827054513119) -->
- <skip />
- <!-- no translation found for not_checked (7972320087569023342) -->
- <skip />
+ <string name="checked" msgid="9179896827054513119">"valittu"</string>
+ <string name="not_checked" msgid="7972320087569023342">"ei valittu"</string>
<string name="whichApplication" msgid="5432266899591255759">"Tee toiminto käyttäen sovellusta"</string>
<string name="whichApplicationNamed" msgid="6969946041713975681">"Suorita sovelluksella %1$s"</string>
<string name="whichApplicationLabel" msgid="7852182961472531728">"Suorita toiminto"</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 39dd90550956..2b890656d5dc 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -188,6 +188,8 @@
<string name="work_profile_deleted_details" msgid="3773706828364418016">"Le profil professionnel de l\'application d\'administration est manquant ou corrompu. Votre profil professionnel et ses données connexes ont donc été supprimés. Communiquez avec votre administrateur pour obtenir de l\'assistance."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Votre profil professionnel n\'est plus accessible sur cet appareil"</string>
<string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Trop de tentatives d\'entrée du mot de passe"</string>
+ <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+ <skip />
<string name="network_logging_notification_title" msgid="554983187553845004">"L\'appareil est géré"</string>
<string name="network_logging_notification_text" msgid="1327373071132562512">"Votre organisation gère cet appareil et peut surveiller le trafic réseau. Touchez ici pour obtenir plus d\'information."</string>
<string name="factory_reset_warning" msgid="6858705527798047809">"Le contenu de votre appareil sera effacé"</string>
@@ -1116,10 +1118,8 @@
<string name="loading" msgid="3138021523725055037">"Chargement en cours..."</string>
<string name="capital_on" msgid="2770685323900821829">"OUI"</string>
<string name="capital_off" msgid="7443704171014626777">"NON"</string>
- <!-- no translation found for checked (9179896827054513119) -->
- <skip />
- <!-- no translation found for not_checked (7972320087569023342) -->
- <skip />
+ <string name="checked" msgid="9179896827054513119">"coché"</string>
+ <string name="not_checked" msgid="7972320087569023342">"non coché"</string>
<string name="whichApplication" msgid="5432266899591255759">"Continuer avec"</string>
<string name="whichApplicationNamed" msgid="6969946041713975681">"Continuer avec %1$s"</string>
<string name="whichApplicationLabel" msgid="7852182961472531728">"Terminer l\'action"</string>
@@ -2004,6 +2004,5 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Basculer l\'écran partagé"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Écran de verrouillage"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Capture d\'écran"</string>
- <!-- no translation found for accessibility_freeform_caption (7873194416838321119) -->
- <skip />
+ <string name="accessibility_freeform_caption" msgid="7873194416838321119">"Application <xliff:g id="APP_NAME">%1$s</xliff:g> dans une fenêtre contextuelle."</string>
</resources>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index edc050c11cf9..7522b5aa26fb 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -188,6 +188,8 @@
<string name="work_profile_deleted_details" msgid="3773706828364418016">"L\'application d\'administration du profil professionnel est manquante ou endommagée. Par conséquent, votre profil professionnel et toutes les données associées ont été supprimés. Pour obtenir de l\'aide, contactez l\'administrateur."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Votre profil professionnel n\'est plus disponible sur cet appareil"</string>
<string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Trop de tentatives de saisie du mot de passe"</string>
+ <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+ <skip />
<string name="network_logging_notification_title" msgid="554983187553845004">"L\'appareil est géré"</string>
<string name="network_logging_notification_text" msgid="1327373071132562512">"Votre organisation gère cet appareil et peut surveiller le trafic réseau. Appuyez ici pour obtenir plus d\'informations."</string>
<string name="factory_reset_warning" msgid="6858705527798047809">"Les données de votre appareil vont être effacées"</string>
@@ -1066,7 +1068,7 @@
<string name="selectAll" msgid="1532369154488982046">"Tout sélectionner"</string>
<string name="cut" msgid="2561199725874745819">"Couper"</string>
<string name="copy" msgid="5472512047143665218">"Copier"</string>
- <string name="failed_to_copy_to_clipboard" msgid="725919885138539875">"Échec de la copie dans le Presse-papiers"</string>
+ <string name="failed_to_copy_to_clipboard" msgid="725919885138539875">"Échec de la copie dans le presse-papiers"</string>
<string name="paste" msgid="461843306215520225">"Coller"</string>
<string name="paste_as_plain_text" msgid="7664800665823182587">"Coller au format texte brut"</string>
<string name="replace" msgid="7842675434546657444">"Remplacer..."</string>
@@ -1116,10 +1118,8 @@
<string name="loading" msgid="3138021523725055037">"Chargement…"</string>
<string name="capital_on" msgid="2770685323900821829">"OUI"</string>
<string name="capital_off" msgid="7443704171014626777">"NON"</string>
- <!-- no translation found for checked (9179896827054513119) -->
- <skip />
- <!-- no translation found for not_checked (7972320087569023342) -->
- <skip />
+ <string name="checked" msgid="9179896827054513119">"activé"</string>
+ <string name="not_checked" msgid="7972320087569023342">"désactivé"</string>
<string name="whichApplication" msgid="5432266899591255759">"Continuer avec"</string>
<string name="whichApplicationNamed" msgid="6969946041713975681">"Terminer l\'action avec %1$s"</string>
<string name="whichApplicationLabel" msgid="7852182961472531728">"Terminer l\'action"</string>
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index 583cadf3b8d5..4d40e214b1ba 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -188,6 +188,8 @@
<string name="work_profile_deleted_details" msgid="3773706828364418016">"Falta a aplicación de administración do perfil de traballo ou ben está danada. Como resultado, eliminouse o teu perfil de traballo e os datos relacionados. Para obter asistencia, contacta co administrador."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"O teu perfil de traballo xa non está dispoñible neste dispositivo"</string>
<string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Demasiados intentos de introdución do contrasinal"</string>
+ <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+ <skip />
<string name="network_logging_notification_title" msgid="554983187553845004">"O dispositivo está xestionado"</string>
<string name="network_logging_notification_text" msgid="1327373071132562512">"A túa organización xestiona este dispositivo e pode controlar o tráfico de rede. Toca para obter máis detalles."</string>
<string name="factory_reset_warning" msgid="6858705527798047809">"Borrarase o teu dispositivo"</string>
@@ -1116,10 +1118,8 @@
<string name="loading" msgid="3138021523725055037">"Cargando..."</string>
<string name="capital_on" msgid="2770685323900821829">"SI"</string>
<string name="capital_off" msgid="7443704171014626777">"NON"</string>
- <!-- no translation found for checked (9179896827054513119) -->
- <skip />
- <!-- no translation found for not_checked (7972320087569023342) -->
- <skip />
+ <string name="checked" msgid="9179896827054513119">"seleccionado"</string>
+ <string name="not_checked" msgid="7972320087569023342">"non seleccionado"</string>
<string name="whichApplication" msgid="5432266899591255759">"Completar a acción usando"</string>
<string name="whichApplicationNamed" msgid="6969946041713975681">"Completar a acción usando %1$s"</string>
<string name="whichApplicationLabel" msgid="7852182961472531728">"Completar acción"</string>
@@ -2004,6 +2004,5 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Activar/desactivar pantalla dividida"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Pantalla de bloqueo"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Captura de pantalla"</string>
- <!-- no translation found for accessibility_freeform_caption (7873194416838321119) -->
- <skip />
+ <string name="accessibility_freeform_caption" msgid="7873194416838321119">"Aplicación <xliff:g id="APP_NAME">%1$s</xliff:g> nunha ventá emerxente."</string>
</resources>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index de315426c78c..ea3a573d7115 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -188,6 +188,8 @@
<string name="work_profile_deleted_details" msgid="3773706828364418016">"કાર્ય પ્રોફાઇલ વ્યવસ્થાપક ઍપ્લિકેશન ખૂટે છે અથવા તો દૂષિત છે. પરિણામે, તમારી કાર્યાલયની પ્રોફાઇલ અને તે સંબંધિત ડેટા કાઢી નાખવામાં આવ્યો છે. સહાયતા માટે તમારા વ્યવસ્થાપકનો સંપર્ક કરો."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"આ ઉપકરણ પર તમારી કાર્યાલયની પ્રોફાઇલ હવે ઉપલબ્ધ નથી"</string>
<string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"પાસવર્ડના ઘણા વધુ પ્રયત્નો"</string>
+ <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+ <skip />
<string name="network_logging_notification_title" msgid="554983187553845004">"ઉપકરણ સંચાલિત છે"</string>
<string name="network_logging_notification_text" msgid="1327373071132562512">"તમારી સંસ્થા આ ઉપકરણનું સંચાલન કરે છે અને નેટવર્ક ટ્રાફિફનું નિયમન કરી શકે છે. વિગતો માટે ટૅપ કરો."</string>
<string name="factory_reset_warning" msgid="6858705527798047809">"તમારું ઉપકરણ કાઢી નાખવામાં આવશે"</string>
@@ -1116,10 +1118,8 @@
<string name="loading" msgid="3138021523725055037">"લોડ કરી રહ્યું છે…"</string>
<string name="capital_on" msgid="2770685323900821829">"ચાલુ"</string>
<string name="capital_off" msgid="7443704171014626777">"બંધ"</string>
- <!-- no translation found for checked (9179896827054513119) -->
- <skip />
- <!-- no translation found for not_checked (7972320087569023342) -->
- <skip />
+ <string name="checked" msgid="9179896827054513119">"ચેક કર્યું"</string>
+ <string name="not_checked" msgid="7972320087569023342">"ચેક કર્યું નથી"</string>
<string name="whichApplication" msgid="5432266899591255759">"આના ઉપયોગથી ક્રિયા પૂર્ણ કરો"</string>
<string name="whichApplicationNamed" msgid="6969946041713975681">"%1$s ઉપયોગથી ક્રિયા પૂર્ણ કરો"</string>
<string name="whichApplicationLabel" msgid="7852182961472531728">"ક્રિયા પૂર્ણ કરો"</string>
@@ -2004,6 +2004,5 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"સ્ક્રીનને વિભાજિત કરવાની ક્રિયા ટૉગલ કરો"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"લૉક સ્ક્રીન"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"સ્ક્રીનશૉટ"</string>
- <!-- no translation found for accessibility_freeform_caption (7873194416838321119) -->
- <skip />
+ <string name="accessibility_freeform_caption" msgid="7873194416838321119">"પૉપ-અપ વિંડોમાં <xliff:g id="APP_NAME">%1$s</xliff:g> ઍપ."</string>
</resources>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 5a422d8ad3af..e12fa08010b7 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -188,6 +188,8 @@
<string name="work_profile_deleted_details" msgid="3773706828364418016">"वर्क प्रोफ़ाइल व्यवस्थापक ऐप्लिकेशन या तो मौजूद नहीं है या वह खराब हो गया है. परिणामस्वरूप, आपकी वर्क प्रोफ़ाइल और उससे जुड़े डेटा को हटा दिया गया है. सहायता के लिए अपने व्यवस्थापक से संपर्क करें."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"आपकी वर्क प्रोफ़ाइल अब इस डिवाइस पर उपलब्‍ध नहीं है"</string>
<string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"कई बार गलत पासवर्ड डाला गया"</string>
+ <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+ <skip />
<string name="network_logging_notification_title" msgid="554983187553845004">"डिवाइस प्रबंधित है"</string>
<string name="network_logging_notification_text" msgid="1327373071132562512">"आपका संगठन इस डिवाइस का प्रबंधन करता है और वह नेटवर्क ट्रैफ़िक की निगरानी भी कर सकता है. विवरण के लिए टैप करें."</string>
<string name="factory_reset_warning" msgid="6858705527798047809">"आपके डिवाइस को मिटा दिया जाएगा"</string>
@@ -1116,10 +1118,8 @@
<string name="loading" msgid="3138021523725055037">"लोड हो रहे हैं..."</string>
<string name="capital_on" msgid="2770685323900821829">"ऑन"</string>
<string name="capital_off" msgid="7443704171014626777">"बंद"</string>
- <!-- no translation found for checked (9179896827054513119) -->
- <skip />
- <!-- no translation found for not_checked (7972320087569023342) -->
- <skip />
+ <string name="checked" msgid="9179896827054513119">"चालू है"</string>
+ <string name="not_checked" msgid="7972320087569023342">"बंद है"</string>
<string name="whichApplication" msgid="5432266899591255759">"इसका इस्तेमाल करके कार्रवाई को पूरा करें"</string>
<string name="whichApplicationNamed" msgid="6969946041713975681">"%1$s का उपयोग करके कार्रवाई पूरी करें"</string>
<string name="whichApplicationLabel" msgid="7852182961472531728">"कार्रवाई पूरी करें"</string>
@@ -2004,6 +2004,5 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"स्प्लिट स्क्रीन पर टॉगल करें"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"स्क्रीन लॉक करें"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"स्क्रीनशॉट लें"</string>
- <!-- no translation found for accessibility_freeform_caption (7873194416838321119) -->
- <skip />
+ <string name="accessibility_freeform_caption" msgid="7873194416838321119">"पॉप-अप विंडो में <xliff:g id="APP_NAME">%1$s</xliff:g> ऐप्लिकेशन."</string>
</resources>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index ed7234bc49e0..0871d06bceff 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -190,6 +190,8 @@
<string name="work_profile_deleted_details" msgid="3773706828364418016">"Administratorska aplikacija radnog profila nedostaje ili je oštećena. Zbog toga su radni profil i povezani podaci izbrisani. Za pomoć se obratite svom administratoru."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Vaš radni profil više nije dostupan na ovom uređaju"</string>
<string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Previše pokušaja unosa zaporke"</string>
+ <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+ <skip />
<string name="network_logging_notification_title" msgid="554983187553845004">"Uređaj je upravljan"</string>
<string name="network_logging_notification_text" msgid="1327373071132562512">"Vaša organizacija upravlja ovim uređajem i može nadzirati mrežni promet. Dodirnite za pojedinosti."</string>
<string name="factory_reset_warning" msgid="6858705527798047809">"Uređaj će se izbrisati"</string>
@@ -1136,10 +1138,8 @@
<string name="loading" msgid="3138021523725055037">"Učitavanje…"</string>
<string name="capital_on" msgid="2770685323900821829">"Uklj."</string>
<string name="capital_off" msgid="7443704171014626777">"Isklj."</string>
- <!-- no translation found for checked (9179896827054513119) -->
- <skip />
- <!-- no translation found for not_checked (7972320087569023342) -->
- <skip />
+ <string name="checked" msgid="9179896827054513119">"potvrđeno"</string>
+ <string name="not_checked" msgid="7972320087569023342">"nije potvrđeno"</string>
<string name="whichApplication" msgid="5432266899591255759">"Radnju dovrši pomoću stavke"</string>
<string name="whichApplicationNamed" msgid="6969946041713975681">"Dovršavanje radnje pomoću aplikacije %1$s"</string>
<string name="whichApplicationLabel" msgid="7852182961472531728">"Dovrši radnju"</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index aab529824b1a..ce11fc628693 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -188,6 +188,8 @@
<string name="work_profile_deleted_details" msgid="3773706828364418016">"A munkaprofil rendszergazdai alkalmazása hiányzik vagy sérült. A rendszer ezért törölte a munkaprofilt, és az ahhoz kapcsolódó adatokat. Ha segítségre van szüksége, vegye fel a kapcsolatot rendszergazdájával."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Munkaprofilja már nem hozzáférhető ezen az eszközön."</string>
<string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Túl sok jelszómegadási kísérlet"</string>
+ <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+ <skip />
<string name="network_logging_notification_title" msgid="554983187553845004">"Felügyelt eszköz"</string>
<string name="network_logging_notification_text" msgid="1327373071132562512">"Ezt az eszközt szervezete kezeli, és lehetséges, hogy a hálózati forgalmat is figyelik. További részletekért koppintson."</string>
<string name="factory_reset_warning" msgid="6858705527798047809">"A rendszer törölni fogja eszközét"</string>
@@ -1116,10 +1118,8 @@
<string name="loading" msgid="3138021523725055037">"Betöltés..."</string>
<string name="capital_on" msgid="2770685323900821829">"Be"</string>
<string name="capital_off" msgid="7443704171014626777">"Ki"</string>
- <!-- no translation found for checked (9179896827054513119) -->
- <skip />
- <!-- no translation found for not_checked (7972320087569023342) -->
- <skip />
+ <string name="checked" msgid="9179896827054513119">"kiválasztva"</string>
+ <string name="not_checked" msgid="7972320087569023342">"nincs kiválasztva"</string>
<string name="whichApplication" msgid="5432266899591255759">"Művelet végrehajtása a következővel:"</string>
<string name="whichApplicationNamed" msgid="6969946041713975681">"Művelet elvégzése a(z) %1$s segítségével"</string>
<string name="whichApplicationLabel" msgid="7852182961472531728">"Művelet végrehajtása"</string>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index ee461f50a24a..629b225072e0 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -188,6 +188,8 @@
<string name="work_profile_deleted_details" msgid="3773706828364418016">"Աշխատանքային պրոֆիլի ադմինիստրատորի հավելվածը բացակայում է կամ վնասված է: Արդյունքում ձեր աշխատանքային պրոֆիլը և առնչվող տվյալները ջնջվել են: Օգնության համար դիմեք ձեր ադմինիստրատորին:"</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Ձեր աշխատանքային պրոֆիլն այս սարքում այլևս հասանելի չէ"</string>
<string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Գաղտնաբառը մուտքագրելու չափից շատ փորձեր են կատարվել"</string>
+ <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+ <skip />
<string name="network_logging_notification_title" msgid="554983187553845004">"Սարքը կառավարվում է"</string>
<string name="network_logging_notification_text" msgid="1327373071132562512">"Ձեր կազմակերպությունը կառավարում է այս սարքը և կարող է վերահսկել ցանցի թրաֆիկը: Հպեք՝ մանրամասները դիտելու համար:"</string>
<string name="factory_reset_warning" msgid="6858705527798047809">"Ձեր սարքը ջնջվելու է"</string>
@@ -1116,10 +1118,8 @@
<string name="loading" msgid="3138021523725055037">"Բեռնում..."</string>
<string name="capital_on" msgid="2770685323900821829">"I"</string>
<string name="capital_off" msgid="7443704171014626777">"O"</string>
- <!-- no translation found for checked (9179896827054513119) -->
- <skip />
- <!-- no translation found for not_checked (7972320087569023342) -->
- <skip />
+ <string name="checked" msgid="9179896827054513119">"նշված է"</string>
+ <string name="not_checked" msgid="7972320087569023342">"նշված չէ"</string>
<string name="whichApplication" msgid="5432266899591255759">"Ավարտել գործողությունը` օգտագործելով"</string>
<string name="whichApplicationNamed" msgid="6969946041713975681">"Եզրափակել գործողությունը՝ օգտագործելով %1$s"</string>
<string name="whichApplicationLabel" msgid="7852182961472531728">"Ավարտել գործողությունը"</string>
@@ -2004,6 +2004,5 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Միացնել/անջատել էկրանի տրոհումը"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Կողպէկրան"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Սքրինշոթ"</string>
- <!-- no translation found for accessibility_freeform_caption (7873194416838321119) -->
- <skip />
+ <string name="accessibility_freeform_caption" msgid="7873194416838321119">"<xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածը ելնող պատուհանում։"</string>
</resources>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index ece3a6c260cc..f99c1076de17 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -188,6 +188,8 @@
<string name="work_profile_deleted_details" msgid="3773706828364418016">"Aplikasi admin profil kerja tidak ada atau rusak. Akibatnya, profil kerja dan data terkait telah dihapus. Hubungi admin untuk meminta bantuan."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Profil kerja tidak tersedia lagi di perangkat ini"</string>
<string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Terlalu banyak percobaan memasukkan sandi"</string>
+ <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+ <skip />
<string name="network_logging_notification_title" msgid="554983187553845004">"Perangkat ini ada yang mengelola"</string>
<string name="network_logging_notification_text" msgid="1327373071132562512">"Organisasi mengelola perangkat ini dan mungkin memantau traffic jaringan. Ketuk untuk melihat detailnya."</string>
<string name="factory_reset_warning" msgid="6858705527798047809">"Perangkat akan dihapus"</string>
@@ -1116,10 +1118,8 @@
<string name="loading" msgid="3138021523725055037">"Memuat..."</string>
<string name="capital_on" msgid="2770685323900821829">"AKTIF"</string>
<string name="capital_off" msgid="7443704171014626777">"MATI"</string>
- <!-- no translation found for checked (9179896827054513119) -->
- <skip />
- <!-- no translation found for not_checked (7972320087569023342) -->
- <skip />
+ <string name="checked" msgid="9179896827054513119">"dicentang"</string>
+ <string name="not_checked" msgid="7972320087569023342">"tidak dicentang"</string>
<string name="whichApplication" msgid="5432266899591255759">"Tindakan lengkap menggunakan"</string>
<string name="whichApplicationNamed" msgid="6969946041713975681">"Selesaikan tindakan menggunakan %1$s"</string>
<string name="whichApplicationLabel" msgid="7852182961472531728">"Selesaikan tindakan"</string>
diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml
index 3bcdda63a404..0f4d6de4d399 100644
--- a/core/res/res/values-is/strings.xml
+++ b/core/res/res/values-is/strings.xml
@@ -188,6 +188,8 @@
<string name="work_profile_deleted_details" msgid="3773706828364418016">"Stjórnunarforrit vinnusniðsins vantar eða er skemmt. Vinnusniðinu og gögnum því tengdu hefur því verið eytt. Hafðu samband við kerfisstjórann til að fá frekari aðstoð."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Vinnusniðið þitt er ekki lengur í boði á þessu tæki"</string>
<string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Of margar tilraunir til að slá inn aðgangsorð"</string>
+ <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+ <skip />
<string name="network_logging_notification_title" msgid="554983187553845004">"Tækinu er stjórnað"</string>
<string name="network_logging_notification_text" msgid="1327373071132562512">"Fyrirtækið þitt stjórnar þessu tæki og kann að fylgjast með netnotkun. Ýttu hér til að fá upplýsingar."</string>
<string name="factory_reset_warning" msgid="6858705527798047809">"Tækið verður hreinsað"</string>
@@ -1116,10 +1118,8 @@
<string name="loading" msgid="3138021523725055037">"Hleður…"</string>
<string name="capital_on" msgid="2770685323900821829">"KVEIKT"</string>
<string name="capital_off" msgid="7443704171014626777">"SLÖKKT"</string>
- <!-- no translation found for checked (9179896827054513119) -->
- <skip />
- <!-- no translation found for not_checked (7972320087569023342) -->
- <skip />
+ <string name="checked" msgid="9179896827054513119">"valið"</string>
+ <string name="not_checked" msgid="7972320087569023342">"ekki valið"</string>
<string name="whichApplication" msgid="5432266899591255759">"Ljúka aðgerð með"</string>
<string name="whichApplicationNamed" msgid="6969946041713975681">"Ljúka aðgerð með %1$s"</string>
<string name="whichApplicationLabel" msgid="7852182961472531728">"Ljúka aðgerð"</string>
@@ -2004,6 +2004,5 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Breyta skjáskiptingu"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Lásskjár"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Skjámynd"</string>
- <!-- no translation found for accessibility_freeform_caption (7873194416838321119) -->
- <skip />
+ <string name="accessibility_freeform_caption" msgid="7873194416838321119">"Forritið <xliff:g id="APP_NAME">%1$s</xliff:g> í sprettiglugga."</string>
</resources>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 01bb13665aee..f14e8582b374 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -188,6 +188,8 @@
<string name="work_profile_deleted_details" msgid="3773706828364418016">"L\'app di amministrazione dei profili di lavoro manca o è danneggiata. Di conseguenza, il tuo profilo di lavoro e i relativi dati sono stati eliminati. Contatta l\'amministratore per ricevere assistenza."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Il tuo profilo di lavoro non è più disponibile sul dispositivo"</string>
<string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Troppi tentativi di inserimento della password"</string>
+ <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+ <skip />
<string name="network_logging_notification_title" msgid="554983187553845004">"Il dispositivo è gestito"</string>
<string name="network_logging_notification_text" msgid="1327373071132562512">"Questo dispositivo è gestito dalla tua organizzazione, che potrebbe monitorare il traffico di rete. Tocca per i dettagli."</string>
<string name="factory_reset_warning" msgid="6858705527798047809">"Il dispositivo verrà resettato"</string>
@@ -1116,10 +1118,8 @@
<string name="loading" msgid="3138021523725055037">"Caricamento..."</string>
<string name="capital_on" msgid="2770685323900821829">"ON"</string>
<string name="capital_off" msgid="7443704171014626777">"OFF"</string>
- <!-- no translation found for checked (9179896827054513119) -->
- <skip />
- <!-- no translation found for not_checked (7972320087569023342) -->
- <skip />
+ <string name="checked" msgid="9179896827054513119">"selezionato"</string>
+ <string name="not_checked" msgid="7972320087569023342">"deselezionato"</string>
<string name="whichApplication" msgid="5432266899591255759">"Completa l\'azione con"</string>
<string name="whichApplicationNamed" msgid="6969946041713975681">"Completamento azione con %1$s"</string>
<string name="whichApplicationLabel" msgid="7852182961472531728">"Completa azione"</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index ed2e66a03f3b..375d7d110a6b 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -192,6 +192,8 @@
<string name="work_profile_deleted_details" msgid="3773706828364418016">"אפליקציית הניהול של פרופיל העבודה חסרה או פגומה. כתוצאה מכך, פרופיל העבודה שלך נמחק, כולל כל הנתונים הקשורים אליו. לקבלת עזרה, פנה למנהל המערכת."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"פרופיל העבודה שלך אינו זמין עוד במכשיר הזה"</string>
<string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"בוצעו ניסיונות רבים מדי להזנת סיסמה"</string>
+ <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+ <skip />
<string name="network_logging_notification_title" msgid="554983187553845004">"המכשיר מנוהל"</string>
<string name="network_logging_notification_text" msgid="1327373071132562512">"הארגון שלך מנהל מכשיר זה ועשוי לנטר את התנועה ברשת. הקש לקבלת פרטים."</string>
<string name="factory_reset_warning" msgid="6858705527798047809">"תתבצע מחיקה של המכשיר"</string>
@@ -1156,10 +1158,8 @@
<string name="loading" msgid="3138021523725055037">"טוען..."</string>
<string name="capital_on" msgid="2770685323900821829">"מופעל"</string>
<string name="capital_off" msgid="7443704171014626777">"כבוי"</string>
- <!-- no translation found for checked (9179896827054513119) -->
- <skip />
- <!-- no translation found for not_checked (7972320087569023342) -->
- <skip />
+ <string name="checked" msgid="9179896827054513119">"מסומן"</string>
+ <string name="not_checked" msgid="7972320087569023342">"לא מסומן"</string>
<string name="whichApplication" msgid="5432266899591255759">"השלמת פעולה באמצעות"</string>
<string name="whichApplicationNamed" msgid="6969946041713975681">"‏להשלמת הפעולה באמצעות %1$s"</string>
<string name="whichApplicationLabel" msgid="7852182961472531728">"השלם פעולה"</string>
@@ -2072,6 +2072,5 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"החלפת מצב של מסך מפוצל"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"מסך הנעילה"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"צילום מסך"</string>
- <!-- no translation found for accessibility_freeform_caption (7873194416838321119) -->
- <skip />
+ <string name="accessibility_freeform_caption" msgid="7873194416838321119">"האפליקציה <xliff:g id="APP_NAME">%1$s</xliff:g> בחלון קופץ."</string>
</resources>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 7ad1bc2aad1c..eb990ec02f87 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -188,6 +188,8 @@
<string name="work_profile_deleted_details" msgid="3773706828364418016">"仕事用プロファイルの管理アプリがないか、破損しています。そのため仕事用プロファイルと関連データが削除されました。管理者にサポートをご依頼ください。"</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"お使いの仕事用プロファイルはこのデバイスで使用できなくなりました"</string>
<string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"パスワード入力回数が上限を超えました"</string>
+ <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+ <skip />
<string name="network_logging_notification_title" msgid="554983187553845004">"管理対象のデバイス"</string>
<string name="network_logging_notification_text" msgid="1327373071132562512">"このデバイスは組織によって管理され、ネットワーク トラフィックが監視される場合があります。詳しくはタップしてください。"</string>
<string name="factory_reset_warning" msgid="6858705527798047809">"デバイスのデータが消去されます"</string>
@@ -1116,10 +1118,8 @@
<string name="loading" msgid="3138021523725055037">"読み込んでいます..."</string>
<string name="capital_on" msgid="2770685323900821829">"ON"</string>
<string name="capital_off" msgid="7443704171014626777">"OFF"</string>
- <!-- no translation found for checked (9179896827054513119) -->
- <skip />
- <!-- no translation found for not_checked (7972320087569023342) -->
- <skip />
+ <string name="checked" msgid="9179896827054513119">"ON"</string>
+ <string name="not_checked" msgid="7972320087569023342">"OFF"</string>
<string name="whichApplication" msgid="5432266899591255759">"アプリケーションを選択"</string>
<string name="whichApplicationNamed" msgid="6969946041713975681">"%1$sを使用してアクションを完了"</string>
<string name="whichApplicationLabel" msgid="7852182961472531728">"アクションを実行"</string>
@@ -2004,6 +2004,5 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"分割画面の切り替え"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"ロック画面"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"スクリーンショット"</string>
- <!-- no translation found for accessibility_freeform_caption (7873194416838321119) -->
- <skip />
+ <string name="accessibility_freeform_caption" msgid="7873194416838321119">"<xliff:g id="APP_NAME">%1$s</xliff:g> アプリがポップアップ ウィンドウで開きます。"</string>
</resources>
diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml
index 7e4035d8d4b0..d2d1fed80059 100644
--- a/core/res/res/values-ka/strings.xml
+++ b/core/res/res/values-ka/strings.xml
@@ -188,6 +188,8 @@
<string name="work_profile_deleted_details" msgid="3773706828364418016">"სამსახურის პროფილის ადმინისტრატორის აპი მიუწვდომელია ან დაზიანებულია. ამის გამო, თქვენი სამსახურის პროფილი და დაკავშირებული მონაცემები წაიშალა. დახმარებისთვის დაუკავშირდით თქვენს ადმინისტრატორს."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"თქვენი სამსახურის პროფილი აღარ არის ხელმისაწვდომი ამ მოწყობილობაზე"</string>
<string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"დაფიქსირდა პაროლის შეყვანის ზედმეტად ბევრი მცდელობა"</string>
+ <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+ <skip />
<string name="network_logging_notification_title" msgid="554983187553845004">"მოწყობილობა მართულია"</string>
<string name="network_logging_notification_text" msgid="1327373071132562512">"ამ მოწყობილობას თქვენი ორგანიზაცია მართავს და მას ქსელის ტრაფიკის მონიტორინგი შეუძლია. შეეხეთ დამატებითი დეტალებისთვის."</string>
<string name="factory_reset_warning" msgid="6858705527798047809">"თქვენი მოწყობილობა წაიშლება"</string>
@@ -1116,10 +1118,8 @@
<string name="loading" msgid="3138021523725055037">"ჩატვირთვა…"</string>
<string name="capital_on" msgid="2770685323900821829">"ჩართ."</string>
<string name="capital_off" msgid="7443704171014626777">"გამორთ."</string>
- <!-- no translation found for checked (9179896827054513119) -->
- <skip />
- <!-- no translation found for not_checked (7972320087569023342) -->
- <skip />
+ <string name="checked" msgid="9179896827054513119">"მონიშნულია"</string>
+ <string name="not_checked" msgid="7972320087569023342">"არ არის მონიშნული"</string>
<string name="whichApplication" msgid="5432266899591255759">"რა გამოვიყენოთ?"</string>
<string name="whichApplicationNamed" msgid="6969946041713975681">"მოქმედების %1$s-ის გამოყენებით დასრულება"</string>
<string name="whichApplicationLabel" msgid="7852182961472531728">"მოქმედების დასრულება"</string>
@@ -2004,6 +2004,5 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"გაყოფილი ეკრანის გადართვა"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"ჩაკეტილი ეკრანი"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"ეკრანის ანაბეჭდი"</string>
- <!-- no translation found for accessibility_freeform_caption (7873194416838321119) -->
- <skip />
+ <string name="accessibility_freeform_caption" msgid="7873194416838321119">"<xliff:g id="APP_NAME">%1$s</xliff:g> აპი ამომხტარ ფანჯარაში."</string>
</resources>
diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml
index 661f7c1bce07..a1002f719a55 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -188,6 +188,8 @@
<string name="work_profile_deleted_details" msgid="3773706828364418016">"Жұмыс профилінің әкімші қолданбасы жоқ немесе бүлінген. Нәтижесінде жұмыс профиліңіз және қатысты деректер жойылды. Көмек алу үшін әкімшіге хабарласыңыз."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Жұмыс профиліңіз осы құрылғыда енді қолжетімді емес"</string>
<string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Құпия сөз көп рет қате енгізілді"</string>
+ <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+ <skip />
<string name="network_logging_notification_title" msgid="554983187553845004">"Құрылғы басқарылады"</string>
<string name="network_logging_notification_text" msgid="1327373071132562512">"Ұйымыңыз осы құрылғыны басқарады және желі трафигін бақылауы мүмкін. Мәліметтер алу үшін түртіңіз."</string>
<string name="factory_reset_warning" msgid="6858705527798047809">"Құрылғыңыздағы деректер өшіріледі"</string>
@@ -1116,10 +1118,8 @@
<string name="loading" msgid="3138021523725055037">"Жүктелуде…"</string>
<string name="capital_on" msgid="2770685323900821829">"Қосулы"</string>
<string name="capital_off" msgid="7443704171014626777">"Өшірулі"</string>
- <!-- no translation found for checked (9179896827054513119) -->
- <skip />
- <!-- no translation found for not_checked (7972320087569023342) -->
- <skip />
+ <string name="checked" msgid="9179896827054513119">"белгіленген"</string>
+ <string name="not_checked" msgid="7972320087569023342">"белгіленбеген"</string>
<string name="whichApplication" msgid="5432266899591255759">"Әрекетті аяқтау"</string>
<string name="whichApplicationNamed" msgid="6969946041713975681">"Әрекетті %1$s қолданбасын пайдаланып аяқтау"</string>
<string name="whichApplicationLabel" msgid="7852182961472531728">"Әрекетті аяқтау"</string>
@@ -2004,6 +2004,5 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Экранды бөлу мүмкіндігін қосу/өшіру"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Құлып экраны"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Скриншот"</string>
- <!-- no translation found for accessibility_freeform_caption (7873194416838321119) -->
- <skip />
+ <string name="accessibility_freeform_caption" msgid="7873194416838321119">"Қалқымалы терезедегі <xliff:g id="APP_NAME">%1$s</xliff:g> қолданбасы"</string>
</resources>
diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml
index ded29998917b..61a3ec6fb444 100644
--- a/core/res/res/values-km/strings.xml
+++ b/core/res/res/values-km/strings.xml
@@ -188,6 +188,8 @@
<string name="work_profile_deleted_details" msgid="3773706828364418016">"កម្មវិធី​អ្នកគ្រប់គ្រង​កម្រងព័ត៌មាន​ការងារនេះ​អាច​បាត់ ឬ​មាន​បញ្ហា។ ដូច្នេះហើយ​ទើប​កម្រងព័ត៌មាន​ការងារ​របស់អ្នក និង​ទិន្នន័យ​ដែល​ពាក់ព័ន្ធត្រូវ​បានលុប។ សូមទាក់ទង​ទៅអ្នក​គ្រប់គ្រង​របស់អ្នក ដើម្បី​ទទួល​បាន​ជំនួយ។"</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"កម្រងព័ត៌មាន​ការងារ​របស់អ្នក​លែងមាន​នៅលើ​ឧបករណ៍​នេះទៀត​ហើយ"</string>
<string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"ការព្យាយាមបញ្ចូលពាក្យសម្ងាត់ច្រើនដងពេកហើយ"</string>
+ <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+ <skip />
<string name="network_logging_notification_title" msgid="554983187553845004">"ឧបករណ៍ស្ថិតក្រោមការគ្រប់គ្រង"</string>
<string name="network_logging_notification_text" msgid="1327373071132562512">"ស្ថាប័នរបស់អ្នកគ្រប់គ្រងឧបករណ៍នេះ ហើយអាចនឹងតាមដានចរាចរណ៍បណ្តាញ។ ចុចដើម្បីទទួលបានព័ត៌មានលម្អិត។"</string>
<string name="factory_reset_warning" msgid="6858705527798047809">"ឧបករណ៍របស់អ្នកនឹងត្រូវបានលុប"</string>
@@ -1116,10 +1118,8 @@
<string name="loading" msgid="3138021523725055037">"កំពុង​ផ្ទុក..."</string>
<string name="capital_on" msgid="2770685323900821829">"បើក"</string>
<string name="capital_off" msgid="7443704171014626777">"បិទ"</string>
- <!-- no translation found for checked (9179896827054513119) -->
- <skip />
- <!-- no translation found for not_checked (7972320087569023342) -->
- <skip />
+ <string name="checked" msgid="9179896827054513119">"បានធីក​"</string>
+ <string name="not_checked" msgid="7972320087569023342">"មិន​បាន​ធីក​"</string>
<string name="whichApplication" msgid="5432266899591255759">"បញ្ចប់​សកម្មភាព​ដោយ​ប្រើ"</string>
<!-- String.format failed for translation -->
<!-- no translation found for whichApplicationNamed (6969946041713975681) -->
@@ -2006,6 +2006,5 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"បិទ/បើក​មុខងារ​បំបែកអេក្រង់"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"អេក្រង់ចាក់សោ"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"រូបថតអេក្រង់"</string>
- <!-- no translation found for accessibility_freeform_caption (7873194416838321119) -->
- <skip />
+ <string name="accessibility_freeform_caption" msgid="7873194416838321119">"កម្មវិធី <xliff:g id="APP_NAME">%1$s</xliff:g> នៅក្នុងវិនដូ​លោតឡើង។"</string>
</resources>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index 10930af4069c..5524d400027f 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -188,6 +188,8 @@
<string name="work_profile_deleted_details" msgid="3773706828364418016">"ಉದ್ಯೋಗ ಪ್ರೊಫೈಲ್‌ ನಿರ್ವಾಹಕ ಅಪ್ಲಿಕೇಶನ್ ಕಳೆದು ಹೋಗಿದೆ ಅಥವಾ ಹಾಳಾಗಿದೆ. ಇದರ ಪರಿಣಾಮವಾಗಿ ನಿಮ್ಮ ಉದ್ಯೋಗ ಪ್ರೊಫೈಲ್‌ ಮತ್ತು ಅದಕ್ಕೆ ಸಂಬಂಧಿಸಿದ ಡೇಟಾವನ್ನು ಅಳಿಸಲಾಗಿದೆ. ಸಹಾಯಕ್ಕಾಗಿ ನಿಮ್ಮ ನಿರ್ವಾಹಕರನ್ನು ಸಂಪರ್ಕಿಸಿ."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"ನಿಮ್ಮ ಉದ್ಯೋಗ ಪ್ರೊಫೈಲ್‌ ಈ ಸಾಧನದಲ್ಲಿ ಈಗ ಲಭ್ಯವಿಲ್ಲ"</string>
<string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"ಹಲವಾರು ಪಾಸ್‌ವರ್ಡ್ ಪ್ರಯತ್ನಗಳು"</string>
+ <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+ <skip />
<string name="network_logging_notification_title" msgid="554983187553845004">"ಸಾಧನವನ್ನು ನಿರ್ವಹಿಸಲಾಗುತ್ತಿದೆ"</string>
<string name="network_logging_notification_text" msgid="1327373071132562512">"ನಿಮ್ಮ ಸಂಸ್ಥೆಯು ಈ ಸಾಧನವನ್ನು ನಿರ್ವಹಿಸುತ್ತದೆ ಮತ್ತು ಅದು ನೆಟ್‌ವರ್ಕ್ ಟ್ರಾಫಿಕ್ ಮೇಲೆ ಗಮನವಿರಿಸಬಹುದು. ವಿವರಗಳಿಗಾಗಿ ಟ್ಯಾಪ್ ಮಾಡಿ."</string>
<string name="factory_reset_warning" msgid="6858705527798047809">"ನಿಮ್ಮ ಸಾಧನವನ್ನು ಅಳಿಸಲಾಗುತ್ತದೆ"</string>
@@ -1116,10 +1118,8 @@
<string name="loading" msgid="3138021523725055037">"ಲೋಡ್ ಮಾಡಲಾಗುತ್ತಿದೆ..."</string>
<string name="capital_on" msgid="2770685323900821829">"ಆನ್‌ ಮಾಡಿ"</string>
<string name="capital_off" msgid="7443704171014626777">"ಆಫ್ ಮಾಡು"</string>
- <!-- no translation found for checked (9179896827054513119) -->
- <skip />
- <!-- no translation found for not_checked (7972320087569023342) -->
- <skip />
+ <string name="checked" msgid="9179896827054513119">"ಪರಿಶೀಲಿಸಲಾಗಿದೆ"</string>
+ <string name="not_checked" msgid="7972320087569023342">"ಪರಿಶೀಲಿಸಲಾಗಿಲ್ಲ"</string>
<string name="whichApplication" msgid="5432266899591255759">"ಇದನ್ನು ಬಳಸಿಕೊಂಡು ಕ್ರಿಯೆಯನ್ನು ಪೂರ್ಣಗೊಳಿಸಿ"</string>
<string name="whichApplicationNamed" msgid="6969946041713975681">"%1$s ಬಳಸಿಕೊಂಡು ಕ್ರಿಯೆಯನ್ನು ಪೂರ್ಣಗೊಳಿಸಿ"</string>
<string name="whichApplicationLabel" msgid="7852182961472531728">"ಕ್ರಿಯೆಯನ್ನು ಪೂರ್ಣಗೊಳಿಸಿ"</string>
@@ -2004,6 +2004,5 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"ಸ್ಪ್ಲಿಟ್-ಸ್ಕ್ರೀನ್ ಟಾಗಲ್ ಮಾಡಿ"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"ಲಾಕ್ ಸ್ಕ್ರೀನ್"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"ಸ್ಕ್ರೀನ್‌ಶಾಟ್"</string>
- <!-- no translation found for accessibility_freeform_caption (7873194416838321119) -->
- <skip />
+ <string name="accessibility_freeform_caption" msgid="7873194416838321119">"ಪಾಪ್-ಅಪ್ ಸ್ಪೇಸ್ ವಿಂಡೋದಲ್ಲಿ <xliff:g id="APP_NAME">%1$s</xliff:g> ಆ್ಯಪ್."</string>
</resources>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 431af176e0ac..423dbd6749cb 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -188,6 +188,8 @@
<string name="work_profile_deleted_details" msgid="3773706828364418016">"직장 프로필 관리 앱이 없거나 손상되어 직장 프로필 및 관련 데이터가 삭제되었습니다. 도움이 필요한 경우 관리자에게 문의하세요."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"직장 프로필을 이 기기에서 더 이상 사용할 수 없습니다."</string>
<string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"비밀번호 입력을 너무 많이 시도함"</string>
+ <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+ <skip />
<string name="network_logging_notification_title" msgid="554983187553845004">"관리되는 기기"</string>
<string name="network_logging_notification_text" msgid="1327373071132562512">"조직에서 이 기기를 관리하며 네트워크 트래픽을 모니터링할 수도 있습니다. 자세한 내용을 보려면 탭하세요."</string>
<string name="factory_reset_warning" msgid="6858705527798047809">"기기가 삭제됩니다."</string>
@@ -1116,10 +1118,8 @@
<string name="loading" msgid="3138021523725055037">"로드 중.."</string>
<string name="capital_on" msgid="2770685323900821829">"ON"</string>
<string name="capital_off" msgid="7443704171014626777">"OFF"</string>
- <!-- no translation found for checked (9179896827054513119) -->
- <skip />
- <!-- no translation found for not_checked (7972320087569023342) -->
- <skip />
+ <string name="checked" msgid="9179896827054513119">"선택함"</string>
+ <string name="not_checked" msgid="7972320087569023342">"선택 안함"</string>
<string name="whichApplication" msgid="5432266899591255759">"작업을 수행할 때 사용하는 애플리케이션"</string>
<string name="whichApplicationNamed" msgid="6969946041713975681">"%1$s을(를) 사용하여 작업 완료"</string>
<string name="whichApplicationLabel" msgid="7852182961472531728">"작업 완료"</string>
@@ -2004,6 +2004,5 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"화면 분할 모드 전환"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"잠금 화면"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"스크린샷"</string>
- <!-- no translation found for accessibility_freeform_caption (7873194416838321119) -->
- <skip />
+ <string name="accessibility_freeform_caption" msgid="7873194416838321119">"팝업 창의 <xliff:g id="APP_NAME">%1$s</xliff:g> 앱"</string>
</resources>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index c8116cc3ba25..d1d773c03d77 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -188,6 +188,8 @@
<string name="work_profile_deleted_details" msgid="3773706828364418016">"Жумуш профилинин башкаруучу колдонмосу жок же бузулгандыктан, жумуш профилиңиз жана ага байланыштуу дайындар жок кылынды. Жардам алуу үчүн администраторуңузга кайрылыңыз."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Жумуш профилиңиз бул түзмөктөн жок кылынды"</string>
<string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Өтө көп жолу сырсөздү киргизүү аракети жасалды"</string>
+ <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+ <skip />
<string name="network_logging_notification_title" msgid="554983187553845004">"Түзмөктү ишкана башкарат"</string>
<string name="network_logging_notification_text" msgid="1327373071132562512">"Ишканаңыз бул түзмөктү башкарат жана тармак трафигин көзөмөлдөшү мүмкүн. Чоо-жайын көрүү үчүн таптап коюңуз."</string>
<string name="factory_reset_warning" msgid="6858705527798047809">"Түзмөгүңүз тазаланат"</string>
@@ -1116,10 +1118,8 @@
<string name="loading" msgid="3138021523725055037">"Жүктөлүүдө…"</string>
<string name="capital_on" msgid="2770685323900821829">"ЖАНДЫРЫЛГАН"</string>
<string name="capital_off" msgid="7443704171014626777">"ӨЧҮК"</string>
- <!-- no translation found for checked (9179896827054513119) -->
- <skip />
- <!-- no translation found for not_checked (7972320087569023342) -->
- <skip />
+ <string name="checked" msgid="9179896827054513119">"белгиленген"</string>
+ <string name="not_checked" msgid="7972320087569023342">"белгилене элек"</string>
<string name="whichApplication" msgid="5432266899591255759">"Аракет колдонууну бүтүрүү"</string>
<string name="whichApplicationNamed" msgid="6969946041713975681">"%1$s аркылуу аракетти аягына чейин чыгаруу"</string>
<string name="whichApplicationLabel" msgid="7852182961472531728">"Аракетти аягына чыгаруу"</string>
@@ -1307,8 +1307,7 @@
<string name="usb_unsupported_audio_accessory_message" msgid="1300168007129796621">"Тиркелген түзмөк бул телефонго шайкеш келбейт. Көбүрөөк маалымат алуу үчүн таптап коюңуз."</string>
<string name="adb_active_notification_title" msgid="408390247354560331">"Мүчүлүштүктөрдү USB аркылуу оңдоо иштеп жатат"</string>
<string name="adb_active_notification_message" msgid="5617264033476778211">"Өчүрүү үчүн тийип коюңуз"</string>
- <!-- no translation found for adb_active_notification_message (6624498401272780855) -->
- <skip />
+ <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"USB аркылуу мүчүлүштүктөрдү оңдоону өчүрүүнү тандаңыз."</string>
<string name="test_harness_mode_notification_title" msgid="2282785860014142511">"Сыноо программасынын режими иштетилди"</string>
<string name="test_harness_mode_notification_message" msgid="3039123743127958420">"Сыноо программасынын режимин өчүрүү үчүн, баштапкы жөндөөлөргө кайтарыңыз."</string>
<string name="console_running_notification_title" msgid="6087888939261635904">"Сериялык консоль иштетилди"</string>
@@ -2005,6 +2004,5 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Экранды бөлүүнү күйгүзүү же өчүрүү"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Кулпуланган экран"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Скриншот"</string>
- <!-- no translation found for accessibility_freeform_caption (7873194416838321119) -->
- <skip />
+ <string name="accessibility_freeform_caption" msgid="7873194416838321119">"<xliff:g id="APP_NAME">%1$s</xliff:g> колдонмосу Калкыма терезеде көрүндү."</string>
</resources>
diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml
index 9acb031172a1..ded2a4fbf8e2 100644
--- a/core/res/res/values-lo/strings.xml
+++ b/core/res/res/values-lo/strings.xml
@@ -188,6 +188,8 @@
<string name="work_profile_deleted_details" msgid="3773706828364418016">"ບໍ່ມີແອັບຜູ້ເບິ່ງແຍງລະບົບໂປຣໄຟລ໌ບ່ອນເຮັດວຽກ ຫຼື ເສຍຫາຍ. ຜົນກໍຄື, ໂປຣໄຟລ໌ບ່ອນເຮັດວຽກ ແລະ ຂໍ້ມູນທີ່ກ່ຽວຂ້ອງຂອງທ່ານຖືກລຶບອອກແລ້ວ. ໃຫ້ຕິດຕໍ່ຜູ້ເບິ່ງແຍງລະບົບສຳລັບການຊ່ວຍເຫຼືອ."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"ໂປຣໄຟລ໌ບ່ອນເຮັດວຽກຂອງທ່ານບໍ່ສາມາດໃຊ້ໄດ້ໃນອຸປະກອນນີ້ອີກຕໍ່ໄປ"</string>
<string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"ລອງໃສ່ລະຫັດຜ່ານຫຼາຍເທື່ອເກີນໄປ"</string>
+ <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+ <skip />
<string name="network_logging_notification_title" msgid="554983187553845004">"ອຸປະກອນມີການຈັດການ"</string>
<string name="network_logging_notification_text" msgid="1327373071132562512">"ອົງກອນຂອງທ່ານຈັດການອຸປະກອນນີ້ ແລະ ອາດກວດສອບທຣາບຟິກເຄືອຂ່າຍນຳ. ແຕະເພື່ອເບິ່ງລາຍລະອຽດ."</string>
<string name="factory_reset_warning" msgid="6858705527798047809">"ອຸ​ປະ​ກອນ​ຂອງ​ທ່ານ​ຈະ​ຖືກ​ລຶບ"</string>
@@ -1116,10 +1118,8 @@
<string name="loading" msgid="3138021523725055037">"ກຳລັງໂຫລດ..."</string>
<string name="capital_on" msgid="2770685323900821829">"ເປີດ"</string>
<string name="capital_off" msgid="7443704171014626777">"ປິດ"</string>
- <!-- no translation found for checked (9179896827054513119) -->
- <skip />
- <!-- no translation found for not_checked (7972320087569023342) -->
- <skip />
+ <string name="checked" msgid="9179896827054513119">"ໝາຍຖືກແລ້ວ"</string>
+ <string name="not_checked" msgid="7972320087569023342">"ບໍ່ໄດ້ໝາຍຖືກ"</string>
<string name="whichApplication" msgid="5432266899591255759">"ດຳເນີນການໂດຍໃຊ້"</string>
<string name="whichApplicationNamed" msgid="6969946041713975681">"ສຳ​ເລັດ​​​ການ​ດຳ​ເນີນ​ການ​ໂດຍ​ໃຊ້ %1$s"</string>
<string name="whichApplicationLabel" msgid="7852182961472531728">"ສຳເລັດຄຳສັ່ງ"</string>
@@ -2004,6 +2004,5 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"ເປີດ/ປິດການແບ່ງໜ້າຈໍ"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"ໜ້າຈໍລັອກ"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"ຮູບໜ້າຈໍ"</string>
- <!-- no translation found for accessibility_freeform_caption (7873194416838321119) -->
- <skip />
+ <string name="accessibility_freeform_caption" msgid="7873194416838321119">"ແອັບ <xliff:g id="APP_NAME">%1$s</xliff:g> ໃນໜ້າຈໍປັອບອັບ."</string>
</resources>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 30b551e1d406..eac535c7b3c2 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -192,6 +192,8 @@
<string name="work_profile_deleted_details" msgid="3773706828364418016">"Trūksta darbo profilio administratoriaus programos arba ji sugadinta. Todėl darbo profilis ir susiję duomenys buvo ištrinti. Jei reikia pagalbos, susisiekite su administratoriumi."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Darbo profilis nebepasiekiamas šiame įrenginyje"</string>
<string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Per daug slaptažodžio bandymų"</string>
+ <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+ <skip />
<string name="network_logging_notification_title" msgid="554983187553845004">"Įrenginys yra tvarkomas"</string>
<string name="network_logging_notification_text" msgid="1327373071132562512">"Šį įrenginį tvarko organizacija ir gali stebėti tinklo srautą. Palieskite, kad gautumėte daugiau informacijos."</string>
<string name="factory_reset_warning" msgid="6858705527798047809">"Įrenginys bus ištrintas"</string>
@@ -1156,10 +1158,8 @@
<string name="loading" msgid="3138021523725055037">"Įkeliama..."</string>
<string name="capital_on" msgid="2770685323900821829">"ĮJ."</string>
<string name="capital_off" msgid="7443704171014626777">"IŠJ."</string>
- <!-- no translation found for checked (9179896827054513119) -->
- <skip />
- <!-- no translation found for not_checked (7972320087569023342) -->
- <skip />
+ <string name="checked" msgid="9179896827054513119">"pažymėta"</string>
+ <string name="not_checked" msgid="7972320087569023342">"nepažymėta"</string>
<string name="whichApplication" msgid="5432266899591255759">"Užbaigti veiksmą naudojant"</string>
<string name="whichApplicationNamed" msgid="6969946041713975681">"Užbaigti veiksmą naudojant %1$s"</string>
<string name="whichApplicationLabel" msgid="7852182961472531728">"Užbaigti veiksmą"</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index ae1831b76e91..f586212653ad 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -190,6 +190,8 @@
<string name="work_profile_deleted_details" msgid="3773706828364418016">"Trūkst darba profila administratora lietotnes, vai šī lietotne ir bojāta. Šī iemesla dēļ jūsu darba profils un saistītie dati tika dzēsti. Lai saņemtu palīdzību, sazinieties ar administratoru."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Jūsu darba profils šai ierīcē vairs nav pieejams."</string>
<string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Veikts pārāk daudz paroles ievadīšanas mēģinājumu."</string>
+ <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+ <skip />
<string name="network_logging_notification_title" msgid="554983187553845004">"Ierīce tiek pārvaldīta"</string>
<string name="network_logging_notification_text" msgid="1327373071132562512">"Jūsu organizācija pārvalda šo ierīci un var uzraudzīt tīkla datplūsmu. Pieskarieties, lai saņemtu detalizētu informāciju."</string>
<string name="factory_reset_warning" msgid="6858705527798047809">"Jūsu ierīces dati tiks dzēsti"</string>
@@ -1136,10 +1138,8 @@
<string name="loading" msgid="3138021523725055037">"Notiek ielāde..."</string>
<string name="capital_on" msgid="2770685323900821829">"IESLĒGT"</string>
<string name="capital_off" msgid="7443704171014626777">"IZSL."</string>
- <!-- no translation found for checked (9179896827054513119) -->
- <skip />
- <!-- no translation found for not_checked (7972320087569023342) -->
- <skip />
+ <string name="checked" msgid="9179896827054513119">"atzīmēts"</string>
+ <string name="not_checked" msgid="7972320087569023342">"nav atzīmēts"</string>
<string name="whichApplication" msgid="5432266899591255759">"Izvēlieties lietotni"</string>
<string name="whichApplicationNamed" msgid="6969946041713975681">"Pabeigt darbību, izmantojot %1$s"</string>
<string name="whichApplicationLabel" msgid="7852182961472531728">"Pabeigt darbību"</string>
@@ -2038,6 +2038,5 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Pārslēgt ekrāna sadalīšanu"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Bloķēt ekrānu"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Ekrānuzņēmums"</string>
- <!-- no translation found for accessibility_freeform_caption (7873194416838321119) -->
- <skip />
+ <string name="accessibility_freeform_caption" msgid="7873194416838321119">"Lietotne <xliff:g id="APP_NAME">%1$s</xliff:g> uznirstošajā logā."</string>
</resources>
diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml
index 480561ff31f5..0d308a1d9b8d 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -188,6 +188,8 @@
<string name="work_profile_deleted_details" msgid="3773706828364418016">"Апликацијата на администраторот за работниот профил или исчезна или е оштетена. Како резултат на тоа, вашиот работен профил и поврзаните податоци ќе се избришат. За помош, контактирајте со администраторот."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Вашиот работен профил веќе не е достапен на уредов"</string>
<string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Премногу обиди за внесување лозинка"</string>
+ <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+ <skip />
<string name="network_logging_notification_title" msgid="554983187553845004">"Некој управува со уредот"</string>
<string name="network_logging_notification_text" msgid="1327373071132562512">"Вашата организација управува со уредов и можно е да го следи сообраќајот на мрежата. Допрете за детали."</string>
<string name="factory_reset_warning" msgid="6858705527798047809">"Уредот ќе се избрише"</string>
@@ -1116,10 +1118,8 @@
<string name="loading" msgid="3138021523725055037">"Се вчитува..."</string>
<string name="capital_on" msgid="2770685323900821829">"ВКЛУЧЕНО"</string>
<string name="capital_off" msgid="7443704171014626777">"ИСКЛУЧЕНО"</string>
- <!-- no translation found for checked (9179896827054513119) -->
- <skip />
- <!-- no translation found for not_checked (7972320087569023342) -->
- <skip />
+ <string name="checked" msgid="9179896827054513119">"штиклирано"</string>
+ <string name="not_checked" msgid="7972320087569023342">"не е штиклирано"</string>
<string name="whichApplication" msgid="5432266899591255759">"Заврши дејство со"</string>
<string name="whichApplicationNamed" msgid="6969946041713975681">"Остварете го дејството со %1$s"</string>
<string name="whichApplicationLabel" msgid="7852182961472531728">"Заврши го дејството"</string>
diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml
index d3b9123a581f..63a7194c114f 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -188,6 +188,8 @@
<string name="work_profile_deleted_details" msgid="3773706828364418016">"ഔദ്യോഗിക പ്രൊഫൈൽ അഡ്‌മിൻ ആപ്പ് വിട്ടുപോയിരിക്കുന്നു അല്ലെങ്കിൽ കേടായിരിക്കുന്നു. ഫലമായി, നിങ്ങളുടെ ഔദ്യോഗിക പ്രൊഫൈലും ബന്ധപ്പെട്ട വിവരങ്ങളും ഇല്ലാതാക്കിയിരിക്കുന്നു. സഹായത്തിന് അഡ്‌മിനെ ബന്ധപ്പെടുക."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"ഈ ഉപകരണത്തിൽ തുടർന്നങ്ങോട്ട് നിങ്ങളുടെ ഔദ്യോഗിക പ്രൊഫൈൽ ലഭ്യമല്ല"</string>
<string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"വളരെയധികം പാസ്‌വേഡ് ശ്രമങ്ങൾ"</string>
+ <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+ <skip />
<string name="network_logging_notification_title" msgid="554983187553845004">"ഉപകരണം മാനേജുചെയ്യുന്നുണ്ട്"</string>
<string name="network_logging_notification_text" msgid="1327373071132562512">"നിങ്ങളുടെ സ്ഥാപനമാണ് ഈ ഉപകരണം മാനേജുചെയ്യുന്നത്, നെറ്റ്‌വർക്ക് ട്രാഫിക്ക് നിരീക്ഷിക്കുകയും ചെയ്തേക്കാം, വിശദാംശങ്ങൾ അറിയാൻ ടാപ്പുചെയ്യുക."</string>
<string name="factory_reset_warning" msgid="6858705527798047809">"നിങ്ങളുടെ ഉപകരണം മായ്‌ക്കും"</string>
@@ -1116,10 +1118,8 @@
<string name="loading" msgid="3138021523725055037">"ലോഡുചെയ്യുന്നു..."</string>
<string name="capital_on" msgid="2770685323900821829">"ഓൺ"</string>
<string name="capital_off" msgid="7443704171014626777">"ഓഫ്"</string>
- <!-- no translation found for checked (9179896827054513119) -->
- <skip />
- <!-- no translation found for not_checked (7972320087569023342) -->
- <skip />
+ <string name="checked" msgid="9179896827054513119">"പരിശോധിച്ചത്"</string>
+ <string name="not_checked" msgid="7972320087569023342">"പരിശോധിക്കാത്തത്"</string>
<string name="whichApplication" msgid="5432266899591255759">"പൂർണ്ണമായ പ്രവർത്തനം ഉപയോഗിക്കുന്നു"</string>
<string name="whichApplicationNamed" msgid="6969946041713975681">"%1$s ഉപയോഗിച്ച് പ്രവർത്തനം പൂർത്തിയാക്കുക"</string>
<string name="whichApplicationLabel" msgid="7852182961472531728">"പ്രവർത്തനം പൂർത്തിയാക്കുക"</string>
@@ -2004,6 +2004,5 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"സ്‌ക്രീൻ വിഭജന മോഡ് മാറ്റുക"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"ലോക്ക് സ്‌ക്രീൻ"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"സ്ക്രീൻഷോട്ട്"</string>
- <!-- no translation found for accessibility_freeform_caption (7873194416838321119) -->
- <skip />
+ <string name="accessibility_freeform_caption" msgid="7873194416838321119">"പോപ്പ്-അപ്പ് വിൻഡോയിലെ <xliff:g id="APP_NAME">%1$s</xliff:g> ആപ്പ്."</string>
</resources>
diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml
index e8f6a5028de4..b3cf5ce92aea 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -188,6 +188,8 @@
<string name="work_profile_deleted_details" msgid="3773706828364418016">"Ажлын профайлын админ апп байхгүй эсвэл эвдэрсэн байна. Үүний улмаас таны ажлын профайл болон холбогдох мэдээллийг устгасан болно. Тусламж хэрэгтэй бол админтай холбогдоно уу."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Таны ажлын профайл энэ төхөөрөмжид боломжгүй байна"</string>
<string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Нууц үгийг хэт олон удаа буруу оруулсан байна"</string>
+ <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+ <skip />
<string name="network_logging_notification_title" msgid="554983187553845004">"Төхөөрөмжийг удирдсан"</string>
<string name="network_logging_notification_text" msgid="1327373071132562512">"Таны байгууллага энэ төхөөрөмжийг удирдаж, сүлжээний ачааллыг хянадаг. Дэлгэрэнгүй мэдээлэл авах бол товшино уу."</string>
<string name="factory_reset_warning" msgid="6858705527798047809">"Таны төхөөрөмж устах болно."</string>
@@ -1116,10 +1118,8 @@
<string name="loading" msgid="3138021523725055037">"Ачааллаж байна..."</string>
<string name="capital_on" msgid="2770685323900821829">"Идэвхтэй"</string>
<string name="capital_off" msgid="7443704171014626777">"Идэвхгүй"</string>
- <!-- no translation found for checked (9179896827054513119) -->
- <skip />
- <!-- no translation found for not_checked (7972320087569023342) -->
- <skip />
+ <string name="checked" msgid="9179896827054513119">"тэмдэглэсэн"</string>
+ <string name="not_checked" msgid="7972320087569023342">"тэмдэглээгүй"</string>
<string name="whichApplication" msgid="5432266899591255759">"Үйлдлийг дуусгах"</string>
<string name="whichApplicationNamed" msgid="6969946041713975681">"%1$s ашиглан үйлдлийг гүйцээх"</string>
<string name="whichApplicationLabel" msgid="7852182961472531728">"Үйлдлийг дуусгах"</string>
@@ -2004,6 +2004,5 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Дэлгэц хуваахыг унтраах/асаах"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Дэлгэцийг түгжих"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Дэлгэцийн зураг дарах"</string>
- <!-- no translation found for accessibility_freeform_caption (7873194416838321119) -->
- <skip />
+ <string name="accessibility_freeform_caption" msgid="7873194416838321119">"Үзэгдэх цонхонд байгаа <xliff:g id="APP_NAME">%1$s</xliff:g> апп."</string>
</resources>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index 18f091197986..22b1dcc4da9b 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -188,6 +188,8 @@
<string name="work_profile_deleted_details" msgid="3773706828364418016">"कार्य प्रोफाइल प्रशासक अ‍ॅप गहाळ आहे किंवा करप्ट आहे. परिणामी, तुमचे कार्य प्रोफाइल आणि संबंधित डेटा हटवले गेले आहेत. सहाय्यासाठी आपल्या प्रशासकाशी संपर्क साधा."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"तुमचे कार्य प्रोफाइल आता या डिव्हाइसवर उपलब्‍ध नाही"</string>
<string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"बर्‍याचदा पासवर्ड टाकण्‍याचा प्रयत्‍न केला"</string>
+ <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+ <skip />
<string name="network_logging_notification_title" msgid="554983187553845004">"डिव्हाइस व्यवस्थापित केले आहे"</string>
<string name="network_logging_notification_text" msgid="1327373071132562512">"तुमची संस्था हे डिव्हाइस व्यवस्थापित करते आणि नेटवर्क रहदारीचे निरीक्षण करू शकते. तपशीलांसाठी टॅप करा."</string>
<string name="factory_reset_warning" msgid="6858705527798047809">"तुमचे डिव्हाइस मिटविले जाईल"</string>
@@ -1116,10 +1118,8 @@
<string name="loading" msgid="3138021523725055037">"लोड करत आहे..."</string>
<string name="capital_on" msgid="2770685323900821829">"सुरू"</string>
<string name="capital_off" msgid="7443704171014626777">"बंद"</string>
- <!-- no translation found for checked (9179896827054513119) -->
- <skip />
- <!-- no translation found for not_checked (7972320087569023342) -->
- <skip />
+ <string name="checked" msgid="9179896827054513119">"तपासले"</string>
+ <string name="not_checked" msgid="7972320087569023342">"तपासले नाही"</string>
<string name="whichApplication" msgid="5432266899591255759">"याचा वापर करून क्रिया पूर्ण करा"</string>
<string name="whichApplicationNamed" msgid="6969946041713975681">"%1$s वापरून क्रिया पूर्ण करा"</string>
<string name="whichApplicationLabel" msgid="7852182961472531728">"क्रिया पूर्ण झाली"</string>
@@ -2004,6 +2004,5 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"विभाजित स्क्रीन टॉगल करा"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"स्‍क्रीन लॉक करा"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"स्क्रीनशॉट"</string>
- <!-- no translation found for accessibility_freeform_caption (7873194416838321119) -->
- <skip />
+ <string name="accessibility_freeform_caption" msgid="7873194416838321119">"पॉप-अप विंडोमध्ये <xliff:g id="APP_NAME">%1$s</xliff:g> ॲप."</string>
</resources>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index 0a404e7bdea8..88c12b64636a 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -188,6 +188,8 @@
<string name="work_profile_deleted_details" msgid="3773706828364418016">"Apl pentadbir profil kerja tiada atau rosak. Akibatnya, profil kerja anda dan data yang berkaitan telah dipadamkan. Hubungi pentadbir anda untuk mendapatkan bantuan."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Profil kerja anda tidak lagi tersedia pada peranti ini"</string>
<string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Terlalu banyak percubaan kata laluan"</string>
+ <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+ <skip />
<string name="network_logging_notification_title" msgid="554983187553845004">"Peranti ini diurus"</string>
<string name="network_logging_notification_text" msgid="1327373071132562512">"Organisasi anda mengurus peranti ini dan mungkin memantau trafik rangkaian. Ketik untuk mendapatkan butiran."</string>
<string name="factory_reset_warning" msgid="6858705527798047809">"Peranti anda akan dipadam"</string>
@@ -1116,10 +1118,8 @@
<string name="loading" msgid="3138021523725055037">"Memuatkan…"</string>
<string name="capital_on" msgid="2770685323900821829">"HIDUP"</string>
<string name="capital_off" msgid="7443704171014626777">"MATIKAN"</string>
- <!-- no translation found for checked (9179896827054513119) -->
- <skip />
- <!-- no translation found for not_checked (7972320087569023342) -->
- <skip />
+ <string name="checked" msgid="9179896827054513119">"ditandai"</string>
+ <string name="not_checked" msgid="7972320087569023342">"tidak ditandai"</string>
<string name="whichApplication" msgid="5432266899591255759">"Selesaikan tindakan menggunakan"</string>
<string name="whichApplicationNamed" msgid="6969946041713975681">"Selesaikan tindakan menggunakan %1$s"</string>
<string name="whichApplicationLabel" msgid="7852182961472531728">"Selesaikan tindakan"</string>
@@ -2004,6 +2004,5 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Togol Skrin Pisah"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Skrin Kunci"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Tangkapan skrin"</string>
- <!-- no translation found for accessibility_freeform_caption (7873194416838321119) -->
- <skip />
+ <string name="accessibility_freeform_caption" msgid="7873194416838321119">"Apl <xliff:g id="APP_NAME">%1$s</xliff:g> dalam tetingkap Timbul."</string>
</resources>
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index e34190dddc2f..cdf68cd3d53c 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -188,6 +188,8 @@
<string name="work_profile_deleted_details" msgid="3773706828364418016">"အလုပ်ပရိုဖိုင် စီမံခန့်ခွဲရန်အက်ပ် မရှိပါ သို့မဟုတ် ပျက်စီးနေပါသည်။ ထို့ကြောင့် သင်၏ အလုပ်ပရိုဖိုင်နှင့် ဆက်စပ်နေသော ဒေတာများကို ဖျက်လိုက်ပါပြီ။ အကူအညီရယူရန် သင်၏စီမံခန့်ခွဲသူကို ဆက်သွယ်ပါ။"</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"ဤစက်ပစ္စည်းတွင် သင်၏ အလုပ်ပရိုဖိုင်မရှိတော့ပါ"</string>
<string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"စကားဝှက်ထည့်သွင်းရန် ကြိုးစားသည့် အကြိမ်အရေအတွက် အလွန်များသွား၍ ဖြစ်ပါသည်"</string>
+ <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+ <skip />
<string name="network_logging_notification_title" msgid="554983187553845004">"စက်ပစ္စည်းကို စီမံခန့်ခွဲထားပါသည်"</string>
<string name="network_logging_notification_text" msgid="1327373071132562512">"ဤစက်ပစ္စည်းကို သင်၏ အဖွဲ့အစည်းက စီမံပြီး ကွန်ရက်အသွားအလာကို စောင့်ကြည့်နိုင်ပါသည်။ ထပ်မံလေ့လာရန် တို့ပါ။"</string>
<string name="factory_reset_warning" msgid="6858705527798047809">"သင့်ကိရိယာအား ပယ်ဖျက်လိမ့်မည်"</string>
@@ -1116,10 +1118,8 @@
<string name="loading" msgid="3138021523725055037">"တင်နေ…"</string>
<string name="capital_on" msgid="2770685323900821829">"ဖွင့်ရန်"</string>
<string name="capital_off" msgid="7443704171014626777">"ပိတ်"</string>
- <!-- no translation found for checked (9179896827054513119) -->
- <skip />
- <!-- no translation found for not_checked (7972320087569023342) -->
- <skip />
+ <string name="checked" msgid="9179896827054513119">"အမှန်ခြစ်ပြီး"</string>
+ <string name="not_checked" msgid="7972320087569023342">"ခြစ် မထား"</string>
<string name="whichApplication" msgid="5432266899591255759">"အသုံးပြု၍ ဆောင်ရွက်မှုအားပြီးဆုံးစေခြင်း"</string>
<string name="whichApplicationNamed" msgid="6969946041713975681">"%1$s ကို သုံးပြီး လုပ်ဆောင်ချက် ပြီးဆုံးပါစေ"</string>
<string name="whichApplicationLabel" msgid="7852182961472531728">"လုပ်ဆောင်ချက်ကို အပြီးသတ်ပါ"</string>
@@ -2004,6 +2004,5 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"မျက်နှာပြင် ခွဲ၍ပြသခြင်းကို နှိပ်ပါ"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"လော့ခ်မျက်နှာပြင်"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"ဖန်သားပြင်ဓာတ်ပုံ"</string>
- <!-- no translation found for accessibility_freeform_caption (7873194416838321119) -->
- <skip />
+ <string name="accessibility_freeform_caption" msgid="7873194416838321119">"ပေါ့ပ်အပ်ဝင်းဒိုးတွင်ရှိသော <xliff:g id="APP_NAME">%1$s</xliff:g>အက်ပ်။"</string>
</resources>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 69ee0177a1bb..b129c3c01b00 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -188,6 +188,8 @@
<string name="work_profile_deleted_details" msgid="3773706828364418016">"Administratorappen for jobbprofilen mangler eller er skadet. Dette har ført til at jobbprofilen og alle data knyttet til den, har blitt slettet. Ta kontakt med administratoren for å få hjelp."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Jobbprofilen din er ikke lenger tilgjengelig på denne enheten"</string>
<string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"For mange passordforsøk"</string>
+ <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+ <skip />
<string name="network_logging_notification_title" msgid="554983187553845004">"Enheten administreres"</string>
<string name="network_logging_notification_text" msgid="1327373071132562512">"Organisasjonen din kontrollerer denne enheten og kan overvåke nettverkstrafikk. Trykk for å få mer informasjon."</string>
<string name="factory_reset_warning" msgid="6858705527798047809">"Enheten blir slettet"</string>
@@ -1116,10 +1118,8 @@
<string name="loading" msgid="3138021523725055037">"Laster inn …"</string>
<string name="capital_on" msgid="2770685323900821829">"På"</string>
<string name="capital_off" msgid="7443704171014626777">"Av"</string>
- <!-- no translation found for checked (9179896827054513119) -->
- <skip />
- <!-- no translation found for not_checked (7972320087569023342) -->
- <skip />
+ <string name="checked" msgid="9179896827054513119">"avmerket"</string>
+ <string name="not_checked" msgid="7972320087569023342">"ikke avmerket"</string>
<string name="whichApplication" msgid="5432266899591255759">"Fullfør med"</string>
<string name="whichApplicationNamed" msgid="6969946041713975681">"Fullfør handlingen med %1$s"</string>
<string name="whichApplicationLabel" msgid="7852182961472531728">"Fullfør handlingen"</string>
@@ -1539,7 +1539,7 @@
<string name="launchBrowserDefault" msgid="6328349989932924119">"Vil du starte nettleseren?"</string>
<string name="SetupCallDefault" msgid="5581740063237175247">"Vil du besvare anropet?"</string>
<string name="activity_resolver_use_always" msgid="5575222334666843269">"Alltid"</string>
- <string name="activity_resolver_set_always" msgid="4142825808921411476">"Angi som alltid åpen"</string>
+ <string name="activity_resolver_set_always" msgid="4142825808921411476">"Alltid"</string>
<string name="activity_resolver_use_once" msgid="948462794469672658">"Bare én gang"</string>
<string name="activity_resolver_app_settings" msgid="6758823206817748026">"Innstillinger"</string>
<string name="activity_resolver_work_profiles_support" msgid="4071345609235361269">"%1$s støtter ikke arbeidsprofiler"</string>
@@ -2004,6 +2004,5 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Slå delt skjerm av/på"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Låseskjerm"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Skjermdump"</string>
- <!-- no translation found for accessibility_freeform_caption (7873194416838321119) -->
- <skip />
+ <string name="accessibility_freeform_caption" msgid="7873194416838321119">"<xliff:g id="APP_NAME">%1$s</xliff:g>-appen i forgrunnsvindu."</string>
</resources>
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index cabb5c0c49dc..648f47c99871 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -188,6 +188,8 @@
<string name="work_profile_deleted_details" msgid="3773706828364418016">"उक्त कार्य प्रोफाइलको प्रशासकीय अनुप्रयोग छैन वा बिग्रेको छ। त्यसले गर्दा, तपाईंको कार्य प्रोफाइल र सम्बन्धित डेटालाई मेटिएको छ। सहायताका लागि आफ्ना प्रशासकलाई सम्पर्क गर्नुहोस्।"</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"तपाईंको कार्य प्रोफाइल अब उप्रान्त यस यन्त्रमा उपलब्ध छैन"</string>
<string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"पासवर्ड प्रविष्ट गर्ने अत्यधिक गलत प्रयासहरू भए"</string>
+ <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+ <skip />
<string name="network_logging_notification_title" msgid="554983187553845004">"यन्त्र व्यवस्थित गरिएको छ"</string>
<string name="network_logging_notification_text" msgid="1327373071132562512">"तपाईंको संगठनले यस यन्त्रको व्यवस्थापन गर्दछ र नेटवर्क ट्राफिकको अनुगमन गर्न सक्छ। विवरणहरूका लागि ट्याप गर्नुहोस्।"</string>
<string name="factory_reset_warning" msgid="6858705527798047809">"तपाईंको यन्त्र मेटिनेछ"</string>
@@ -1116,10 +1118,8 @@
<string name="loading" msgid="3138021523725055037">"लोड हुँदै..."</string>
<string name="capital_on" msgid="2770685323900821829">"चालु"</string>
<string name="capital_off" msgid="7443704171014626777">"बन्द"</string>
- <!-- no translation found for checked (9179896827054513119) -->
- <skip />
- <!-- no translation found for not_checked (7972320087569023342) -->
- <skip />
+ <string name="checked" msgid="9179896827054513119">"जाँच गरिएको"</string>
+ <string name="not_checked" msgid="7972320087569023342">"जाँच गरिएको छैन"</string>
<string name="whichApplication" msgid="5432266899591255759">"प्रयोग गरेर कारबाही पुरा गर्नुहोस्"</string>
<!-- String.format failed for translation -->
<!-- no translation found for whichApplicationNamed (6969946041713975681) -->
@@ -2010,6 +2010,5 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"विभाजित स्क्रिन टगल गर्नुहोस्"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"लक स्क्रिन"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"स्क्रिनसट"</string>
- <!-- no translation found for accessibility_freeform_caption (7873194416838321119) -->
- <skip />
+ <string name="accessibility_freeform_caption" msgid="7873194416838321119">"पपअप विन्डोमा <xliff:g id="APP_NAME">%1$s</xliff:g> अनुप्रयोग छ।"</string>
</resources>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 28fdfa5c8889..e248ca1ed1d0 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -188,6 +188,8 @@
<string name="work_profile_deleted_details" msgid="3773706828364418016">"De beheer-app van het werkprofiel ontbreekt of is beschadigd. Als gevolg hiervan zijn je werkprofiel en alle gerelateerde gegevens verwijderd. Neem contact op met je beheerder voor hulp."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Je werkprofiel is niet meer beschikbaar op dit apparaat"</string>
<string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Te veel wachtwoordpogingen"</string>
+ <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+ <skip />
<string name="network_logging_notification_title" msgid="554983187553845004">"Apparaat wordt beheerd"</string>
<string name="network_logging_notification_text" msgid="1327373071132562512">"Dit apparaat wordt beheerd door je organisatie. Het netwerkverkeer kan worden bijgehouden. Tik voor meer informatie."</string>
<string name="factory_reset_warning" msgid="6858705527798047809">"Je apparaat wordt gewist"</string>
@@ -1116,10 +1118,8 @@
<string name="loading" msgid="3138021523725055037">"Laden..."</string>
<string name="capital_on" msgid="2770685323900821829">"AAN"</string>
<string name="capital_off" msgid="7443704171014626777">"UIT"</string>
- <!-- no translation found for checked (9179896827054513119) -->
- <skip />
- <!-- no translation found for not_checked (7972320087569023342) -->
- <skip />
+ <string name="checked" msgid="9179896827054513119">"aangevinkt"</string>
+ <string name="not_checked" msgid="7972320087569023342">"niet aangevinkt"</string>
<string name="whichApplication" msgid="5432266899591255759">"Actie voltooien met"</string>
<string name="whichApplicationNamed" msgid="6969946041713975681">"Actie voltooien via %1$s"</string>
<string name="whichApplicationLabel" msgid="7852182961472531728">"Actie voltooien"</string>
diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml
index 23e04b70e06e..7a73cc61633d 100644
--- a/core/res/res/values-or/strings.xml
+++ b/core/res/res/values-or/strings.xml
@@ -188,6 +188,8 @@
<string name="work_profile_deleted_details" msgid="3773706828364418016">"ଆଡମିନ୍‍ ଆପ୍‍ ନାହିଁ କିମ୍ବା ଭୁଲ ଅଛି। ଫଳସ୍ୱରୂପ, ଆପଣଙ୍କ ୱାର୍କ ପ୍ରୋଫାଇଲ୍‍ ଏବଂ ସମ୍ବନ୍ଧୀୟ ଡାଟା ଡିଲିଟ୍ କରାଯାଇଛି। ସହାୟତା ପାଇଁ ଆପଣଙ୍କ ଆଡମିନଙ୍କୁ ଯୋଗାଯୋଗ କରନ୍ତୁ।"</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"ଏହି ଡିଭାଇସରେ ଆପଣଙ୍କ ୱର୍କ ପ୍ରୋଫାଇଲ୍‍ ଆଉ ଉପଲବ୍ଧ ନାହିଁ"</string>
<string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"ବହୁତ ଥର ଭୁଲ ପାସ୍‌ୱର୍ଡ ଲେଖିଛନ୍ତି"</string>
+ <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+ <skip />
<string name="network_logging_notification_title" msgid="554983187553845004">"ଡିଭାଇସକୁ ପରିଚାଳନା କରାଯାଉଛି"</string>
<string name="network_logging_notification_text" msgid="1327373071132562512">"ଆପଣଙ୍କ ସଂସ୍ଥା ଏହି ଡିଭାଇସକୁ ପରିଚାଳନା କରନ୍ତି ଏବଂ ନେଟୱର୍କ ଟ୍ରାଫିକ୍‍ ନୀରିକ୍ଷଣ କରନ୍ତି। ବିବରଣୀ ପାଇଁ ଟାପ୍‍ କରନ୍ତୁ।"</string>
<string name="factory_reset_warning" msgid="6858705527798047809">"ଆପଣଙ୍କ ଡିଭାଇସ୍‍ ବର୍ତ୍ତମାନ ଲିଭାଯିବ"</string>
@@ -1116,10 +1118,8 @@
<string name="loading" msgid="3138021523725055037">"ଲୋଡ୍ କରାଯାଉଛି…"</string>
<string name="capital_on" msgid="2770685323900821829">"ଅନ୍"</string>
<string name="capital_off" msgid="7443704171014626777">"ଅଫ୍"</string>
- <!-- no translation found for checked (9179896827054513119) -->
- <skip />
- <!-- no translation found for not_checked (7972320087569023342) -->
- <skip />
+ <string name="checked" msgid="9179896827054513119">"ଯାଞ୍ଚ ହୋଇଛି"</string>
+ <string name="not_checked" msgid="7972320087569023342">"ଯାଞ୍ଚ ହୋଇନାହିଁ"</string>
<string name="whichApplication" msgid="5432266899591255759">"ବ୍ୟବହାର କରି କାର୍ଯ୍ୟ ସମ୍ପୂର୍ଣ୍ଣ କରନ୍ତୁ"</string>
<string name="whichApplicationNamed" msgid="6969946041713975681">"%1$s ବ୍ୟବହାର କରି କାର୍ଯ୍ୟ ସମ୍ପୂର୍ଣ୍ଣ କରନ୍ତୁ"</string>
<string name="whichApplicationLabel" msgid="7852182961472531728">"କାର୍ଯ୍ୟ ସମ୍ପୂର୍ଣ୍ଣ କରନ୍ତୁ"</string>
@@ -2004,6 +2004,5 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"ଦୁଇଟି ସ୍କ୍ରିନ୍ ମଧ୍ୟରେ ଟୋଗଲ୍ କରନ୍ତୁ"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"ସ୍କ୍ରିନ୍ ଲକ୍ କରନ୍ତୁ"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"ସ୍କ୍ରି‍ନ୍‍ସଟ୍ ନିଅନ୍ତୁ"</string>
- <!-- no translation found for accessibility_freeform_caption (7873194416838321119) -->
- <skip />
+ <string name="accessibility_freeform_caption" msgid="7873194416838321119">"ପପ୍-ଅପ୍ ୱିଣ୍ଡୋରେ <xliff:g id="APP_NAME">%1$s</xliff:g> ଆପ୍"</string>
</resources>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index 891f1f15795a..3a245e383bc5 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -188,6 +188,8 @@
<string name="work_profile_deleted_details" msgid="3773706828364418016">"ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ ਪ੍ਰਸ਼ਾਸਕ ਐਪ ਜਾਂ ਤਾਂ ਗੁੰਮਸ਼ੁਦਾ ਹੈ ਜਾਂ ਖਰਾਬ ਹੈ। ਨਤੀਜੇ ਵਜੋਂ, ਤੁਹਾਡੀ ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ ਅਤੇ ਸਬੰਧਿਤ ਡਾਟਾ ਮਿਟਾਇਆ ਗਿਆ ਹੈ। ਸਹਾਇਤਾ ਲਈ ਆਪਣੇ ਪ੍ਰਸ਼ਾਸਕ ਨਾਲ ਸੰਪਰਕ ਕਰੋ।"</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"ਤੁਹਾਡਾ ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ ਹੁਣ ਇਸ ਡੀਵਾਈਸ \'ਤੇ ਉਪਲਬਧ ਨਹੀਂ ਹੈ"</string>
<string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"ਕਈ ਵਾਰ ਗਲਤ ਪਾਸਵਰਡ ਦਾਖਲ ਕੀਤਾ ਗਿਆ"</string>
+ <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+ <skip />
<string name="network_logging_notification_title" msgid="554983187553845004">"ਡੀਵਾਈਸ ਪ੍ਰਬੰਧਨ ਅਧੀਨ ਹੈ"</string>
<string name="network_logging_notification_text" msgid="1327373071132562512">"ਤੁਹਾਡਾ ਸੰਗਠਨ ਇਸ ਡੀਵਾਈਸ ਦਾ ਪ੍ਰਬੰਧਨ ਕਰਦਾ ਹੈ ਅਤੇ ਨੈੱਟਵਰਕ ਟਰੈਫਿਕ ਦੀ ਨਿਗਰਾਨੀ ਕਰ ਸਕਦਾ ਹੈ। ਵੇਰਵਿਆਂ ਲਈ ਟੈਪ ਕਰੋ।"</string>
<string name="factory_reset_warning" msgid="6858705527798047809">"ਤੁਹਾਡਾ ਡੀਵਾਈਸ ਮਿਟਾਇਆ ਜਾਏਗਾ"</string>
@@ -1116,10 +1118,8 @@
<string name="loading" msgid="3138021523725055037">"ਲੋਡ ਹੋ ਰਿਹਾ ਹੈ..."</string>
<string name="capital_on" msgid="2770685323900821829">"ਚਾਲੂ"</string>
<string name="capital_off" msgid="7443704171014626777">"ਬੰਦ"</string>
- <!-- no translation found for checked (9179896827054513119) -->
- <skip />
- <!-- no translation found for not_checked (7972320087569023342) -->
- <skip />
+ <string name="checked" msgid="9179896827054513119">"ਨਿਸ਼ਾਨਬੱਧ ਕੀਤਾ ਗਿਆ"</string>
+ <string name="not_checked" msgid="7972320087569023342">"ਨਿਸ਼ਾਨਬੱਧ ਨਹੀਂ ਕੀਤਾ ਗਿਆ"</string>
<string name="whichApplication" msgid="5432266899591255759">"ਇਸਨੂੰ ਵਰਤਦੇ ਹੋਏ ਕਾਰਵਾਈ ਪੂਰੀ ਕਰੋ"</string>
<string name="whichApplicationNamed" msgid="6969946041713975681">"%1$s ਵਰਤਦੇ ਹੋਏ ਕਾਰਵਾਈ ਪੂਰੀ ਕਰੋ"</string>
<string name="whichApplicationLabel" msgid="7852182961472531728">"ਕਾਰਵਾਈ ਪੂਰੀ ਕਰੋ"</string>
@@ -2004,6 +2004,5 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"ਸਪਲਿਟ ਸਕ੍ਰੀਨ ਨੂੰ ਟੌਗਲ ਕਰੋ"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"ਲਾਕ ਸਕ੍ਰੀਨ"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"ਸਕ੍ਰੀਨਸ਼ਾਟ"</string>
- <!-- no translation found for accessibility_freeform_caption (7873194416838321119) -->
- <skip />
+ <string name="accessibility_freeform_caption" msgid="7873194416838321119">"ਪੌਪ-ਅੱਪ ਵਿੰਡੋ ਵਿੱਚ <xliff:g id="APP_NAME">%1$s</xliff:g> ਐਪ।"</string>
</resources>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 811c5d883914..7a86bd561546 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -192,6 +192,8 @@
<string name="work_profile_deleted_details" msgid="3773706828364418016">"Brakuje aplikacji administratora profilu do pracy lub jest ona uszkodzona. Dlatego Twój profil służbowy i związane z nim dane zostały usunięte. Skontaktuj się ze swoim administratorem, by uzyskać pomoc."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Twój profil służbowy nie jest już dostępny na tym urządzeniu"</string>
<string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Zbyt wiele prób podania hasła"</string>
+ <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+ <skip />
<string name="network_logging_notification_title" msgid="554983187553845004">"Urządzenie jest zarządzane"</string>
<string name="network_logging_notification_text" msgid="1327373071132562512">"Twoja organizacja zarządza tym urządzeniem i może monitorować ruch w sieci. Kliknij, by dowiedzieć się więcej."</string>
<string name="factory_reset_warning" msgid="6858705527798047809">"Twoje urządzenie zostanie wyczyszczone"</string>
@@ -1156,10 +1158,8 @@
<string name="loading" msgid="3138021523725055037">"Wczytuję…"</string>
<string name="capital_on" msgid="2770685323900821829">"Wł."</string>
<string name="capital_off" msgid="7443704171014626777">"Wył."</string>
- <!-- no translation found for checked (9179896827054513119) -->
- <skip />
- <!-- no translation found for not_checked (7972320087569023342) -->
- <skip />
+ <string name="checked" msgid="9179896827054513119">"wybrano"</string>
+ <string name="not_checked" msgid="7972320087569023342">"nie wybrano"</string>
<string name="whichApplication" msgid="5432266899591255759">"Wykonaj czynność przez..."</string>
<string name="whichApplicationNamed" msgid="6969946041713975681">"Wykonaj czynność w aplikacji %1$s"</string>
<string name="whichApplicationLabel" msgid="7852182961472531728">"Wykonaj działanie"</string>
@@ -2072,6 +2072,5 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Przełącz podzielony ekran"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Ekran blokady"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Zrzut ekranu"</string>
- <!-- no translation found for accessibility_freeform_caption (7873194416838321119) -->
- <skip />
+ <string name="accessibility_freeform_caption" msgid="7873194416838321119">"Aplikacja <xliff:g id="APP_NAME">%1$s</xliff:g> w wyskakującym okienku."</string>
</resources>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index ecd10c32eaeb..3f82a80453f1 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -188,6 +188,8 @@
<string name="work_profile_deleted_details" msgid="3773706828364418016">"O app para administrador do perfil de trabalho não foi encontrado ou está corrompido. Consequentemente, seu perfil de trabalho e os dados relacionados foram excluídos. Entre em contato com seu administrador para receber assistência."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Seu perfil de trabalho não está mais disponível neste dispositivo"</string>
<string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Muitas tentativas de senha"</string>
+ <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+ <skip />
<string name="network_logging_notification_title" msgid="554983187553845004">"O dispositivo é gerenciado"</string>
<string name="network_logging_notification_text" msgid="1327373071132562512">"Sua organização gerencia este dispositivo e pode monitorar o tráfego de rede. Toque para ver detalhes."</string>
<string name="factory_reset_warning" msgid="6858705527798047809">"Seu dispositivo será limpo"</string>
@@ -1116,10 +1118,8 @@
<string name="loading" msgid="3138021523725055037">"Carregando…"</string>
<string name="capital_on" msgid="2770685323900821829">"LIG"</string>
<string name="capital_off" msgid="7443704171014626777">"DESL"</string>
- <!-- no translation found for checked (9179896827054513119) -->
- <skip />
- <!-- no translation found for not_checked (7972320087569023342) -->
- <skip />
+ <string name="checked" msgid="9179896827054513119">"marcado"</string>
+ <string name="not_checked" msgid="7972320087569023342">"não marcado"</string>
<string name="whichApplication" msgid="5432266899591255759">"Complete a ação usando"</string>
<string name="whichApplicationNamed" msgid="6969946041713975681">"Concluir a ação usando %1$s"</string>
<string name="whichApplicationLabel" msgid="7852182961472531728">"Concluir ação"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 0cfbf8cb467e..f67c96fa10ba 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -188,6 +188,8 @@
<string name="work_profile_deleted_details" msgid="3773706828364418016">"A aplicação de administração do perfil de trabalho está em falta ou danificada. Consequentemente, o seu perfil de trabalho e os dados relacionados foram eliminados. Contacte o gestor para obter assistência."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"O seu perfil de trabalho já não está disponível neste dispositivo"</string>
<string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Demasiadas tentativas de introdução da palavra-passe"</string>
+ <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+ <skip />
<string name="network_logging_notification_title" msgid="554983187553845004">"O dispositivo é gerido"</string>
<string name="network_logging_notification_text" msgid="1327373071132562512">"A sua entidade gere este dispositivo e pode monitorizar o tráfego de rede. Toque para obter mais detalhes."</string>
<string name="factory_reset_warning" msgid="6858705527798047809">"O seu dispositivo será apagado"</string>
@@ -1116,10 +1118,8 @@
<string name="loading" msgid="3138021523725055037">"A carregar…"</string>
<string name="capital_on" msgid="2770685323900821829">"Ativado"</string>
<string name="capital_off" msgid="7443704171014626777">"Desativado"</string>
- <!-- no translation found for checked (9179896827054513119) -->
- <skip />
- <!-- no translation found for not_checked (7972320087569023342) -->
- <skip />
+ <string name="checked" msgid="9179896827054513119">"selecionado"</string>
+ <string name="not_checked" msgid="7972320087569023342">"não selecionado"</string>
<string name="whichApplication" msgid="5432266899591255759">"Concluir ação utilizando"</string>
<string name="whichApplicationNamed" msgid="6969946041713975681">"Concluir ação utilizando %1$s"</string>
<string name="whichApplicationLabel" msgid="7852182961472531728">"Concluir ação"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index ecd10c32eaeb..3f82a80453f1 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -188,6 +188,8 @@
<string name="work_profile_deleted_details" msgid="3773706828364418016">"O app para administrador do perfil de trabalho não foi encontrado ou está corrompido. Consequentemente, seu perfil de trabalho e os dados relacionados foram excluídos. Entre em contato com seu administrador para receber assistência."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Seu perfil de trabalho não está mais disponível neste dispositivo"</string>
<string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Muitas tentativas de senha"</string>
+ <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+ <skip />
<string name="network_logging_notification_title" msgid="554983187553845004">"O dispositivo é gerenciado"</string>
<string name="network_logging_notification_text" msgid="1327373071132562512">"Sua organização gerencia este dispositivo e pode monitorar o tráfego de rede. Toque para ver detalhes."</string>
<string name="factory_reset_warning" msgid="6858705527798047809">"Seu dispositivo será limpo"</string>
@@ -1116,10 +1118,8 @@
<string name="loading" msgid="3138021523725055037">"Carregando…"</string>
<string name="capital_on" msgid="2770685323900821829">"LIG"</string>
<string name="capital_off" msgid="7443704171014626777">"DESL"</string>
- <!-- no translation found for checked (9179896827054513119) -->
- <skip />
- <!-- no translation found for not_checked (7972320087569023342) -->
- <skip />
+ <string name="checked" msgid="9179896827054513119">"marcado"</string>
+ <string name="not_checked" msgid="7972320087569023342">"não marcado"</string>
<string name="whichApplication" msgid="5432266899591255759">"Complete a ação usando"</string>
<string name="whichApplicationNamed" msgid="6969946041713975681">"Concluir a ação usando %1$s"</string>
<string name="whichApplicationLabel" msgid="7852182961472531728">"Concluir ação"</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index f50103270133..846b9829fa9c 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -190,6 +190,8 @@
<string name="work_profile_deleted_details" msgid="3773706828364418016">"Aplicația de administrare a profilului de serviciu lipsește sau este deteriorată. Prin urmare, profilul de serviciu și datele asociate au fost șterse. Pentru asistență, contactați administratorul."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Profilul de serviciu nu mai este disponibil pe acest dispozitiv"</string>
<string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Prea multe încercări de introducere a parolei"</string>
+ <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+ <skip />
<string name="network_logging_notification_title" msgid="554983187553845004">"Dispozitivul este gestionat"</string>
<string name="network_logging_notification_text" msgid="1327373071132562512">"Organizația dvs. gestionează acest dispozitiv și poate monitoriza traficul în rețea. Atingeți pentru mai multe detalii."</string>
<string name="factory_reset_warning" msgid="6858705527798047809">"Datele de pe dispozitiv vor fi șterse"</string>
@@ -1136,10 +1138,8 @@
<string name="loading" msgid="3138021523725055037">"Se încarcă…"</string>
<string name="capital_on" msgid="2770685323900821829">"DA"</string>
<string name="capital_off" msgid="7443704171014626777">"NU"</string>
- <!-- no translation found for checked (9179896827054513119) -->
- <skip />
- <!-- no translation found for not_checked (7972320087569023342) -->
- <skip />
+ <string name="checked" msgid="9179896827054513119">"bifat"</string>
+ <string name="not_checked" msgid="7972320087569023342">"nebifat"</string>
<string name="whichApplication" msgid="5432266899591255759">"Finalizare acțiune utilizând"</string>
<string name="whichApplicationNamed" msgid="6969946041713975681">"Finalizați acțiunea utilizând %1$s"</string>
<string name="whichApplicationLabel" msgid="7852182961472531728">"Finalizați acțiunea"</string>
@@ -2038,6 +2038,5 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Activați ecranul împărțit"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Ecran de blocare"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Captură de ecran"</string>
- <!-- no translation found for accessibility_freeform_caption (7873194416838321119) -->
- <skip />
+ <string name="accessibility_freeform_caption" msgid="7873194416838321119">"Aplicația <xliff:g id="APP_NAME">%1$s</xliff:g> în fereastră pop-up."</string>
</resources>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index aefc37342bff..19fde9f45fb5 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -192,6 +192,8 @@
<string name="work_profile_deleted_details" msgid="3773706828364418016">"Приложение для администрирования рабочего профиля отсутствует или повреждено. Из-за этого рабочий профиль и связанные с ним данные были удалены. Если у вас возникли вопросы, обратитесь к администратору."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Ваш рабочий профиль больше не доступен на этом устройстве"</string>
<string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Слишком много попыток ввести пароль."</string>
+ <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+ <skip />
<string name="network_logging_notification_title" msgid="554983187553845004">"Это управляемое устройство"</string>
<string name="network_logging_notification_text" msgid="1327373071132562512">"Ваша организация управляет этим устройством и может отслеживать сетевой трафик. Подробнее…"</string>
<string name="factory_reset_warning" msgid="6858705527798047809">"Все данные с устройства будут удалены"</string>
@@ -1156,10 +1158,8 @@
<string name="loading" msgid="3138021523725055037">"Загрузка…"</string>
<string name="capital_on" msgid="2770685323900821829">"I"</string>
<string name="capital_off" msgid="7443704171014626777">"O"</string>
- <!-- no translation found for checked (9179896827054513119) -->
- <skip />
- <!-- no translation found for not_checked (7972320087569023342) -->
- <skip />
+ <string name="checked" msgid="9179896827054513119">"отмечено"</string>
+ <string name="not_checked" msgid="7972320087569023342">"не отмечено"</string>
<string name="whichApplication" msgid="5432266899591255759">"Что использовать?"</string>
<string name="whichApplicationNamed" msgid="6969946041713975681">"Выполнить с помощью приложения \"%1$s\""</string>
<string name="whichApplicationLabel" msgid="7852182961472531728">"Выполнить действие"</string>
@@ -2072,6 +2072,5 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Включить или выключить разделение экрана"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Заблокированный экран"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Скриншот"</string>
- <!-- no translation found for accessibility_freeform_caption (7873194416838321119) -->
- <skip />
+ <string name="accessibility_freeform_caption" msgid="7873194416838321119">"Приложение \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" в всплывающем окне."</string>
</resources>
diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml
index 67dfbd395e65..676b48f616f7 100644
--- a/core/res/res/values-si/strings.xml
+++ b/core/res/res/values-si/strings.xml
@@ -188,6 +188,8 @@
<string name="work_profile_deleted_details" msgid="3773706828364418016">"කාර්යාල පැතිකඩ පාලක යෙදුම නොමැති හෝ දූෂණය වී ඇත. ප්‍රතිඵලයක් ලෙස ඔබගේ කාර්යාල පැතිකඩ සහ අදාළ දත්ත මකා දමා ඇත. සහය සඳහා ඔබගේ පරිපාලකයා සම්බන්ධ කර ගන්න."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"ඔබේ කාර්යාල පැතිකඩ මෙම උපාංගය මත තවදුරටත් ලබා ගැනීමට නොහැකිය"</string>
<string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"මුරපද උත්සාහ කිරීම් ඉතා වැඩි ගණනකි"</string>
+ <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+ <skip />
<string name="network_logging_notification_title" msgid="554983187553845004">"උපාංගය කළමනාකරණය කෙරේ"</string>
<string name="network_logging_notification_text" msgid="1327373071132562512">"ඔබගේ ආයතනය මෙම උපාංගය කළමනාකරණය කරන අතර එය ජාල තදබදය නිරීක්ෂණය කළ හැක. විස්තර සඳහා තට්ටු කරන්න."</string>
<string name="factory_reset_warning" msgid="6858705527798047809">"ඔබගේ උපාංගය මකා දැමෙනු ඇත"</string>
@@ -1118,10 +1120,8 @@
<string name="loading" msgid="3138021523725055037">"පූරණය වෙමින්..."</string>
<string name="capital_on" msgid="2770685323900821829">"සක්‍රීයයි"</string>
<string name="capital_off" msgid="7443704171014626777">"ක්‍රියාවිරහිතයි"</string>
- <!-- no translation found for checked (9179896827054513119) -->
- <skip />
- <!-- no translation found for not_checked (7972320087569023342) -->
- <skip />
+ <string name="checked" msgid="9179896827054513119">"පරීක්ෂා කර ඇත"</string>
+ <string name="not_checked" msgid="7972320087569023342">"පරීක්ෂා කර නැත"</string>
<string name="whichApplication" msgid="5432266899591255759">"පහත භාවිතයෙන් ක්‍රියාව සම්පූර්ණ කරන්න"</string>
<string name="whichApplicationNamed" msgid="6969946041713975681">"%1$s භාවිතා කරමින් ක්‍රියාව සම්පුර්ණ කරන්න"</string>
<string name="whichApplicationLabel" msgid="7852182961472531728">"ක්‍රියාව සම්පූර්ණ කරන්න"</string>
@@ -2006,6 +2006,5 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"බෙදුම් තිරය ටොගල කරන්න"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"අගුලු තිරය"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"තිර රුව"</string>
- <!-- no translation found for accessibility_freeform_caption (7873194416838321119) -->
- <skip />
+ <string name="accessibility_freeform_caption" msgid="7873194416838321119">"උත්පතන කවුළුව තුළ <xliff:g id="APP_NAME">%1$s</xliff:g> යෙදුම."</string>
</resources>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index c1eec993af8a..cde5466db748 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -192,6 +192,8 @@
<string name="work_profile_deleted_details" msgid="3773706828364418016">"Aplikácia na správu pracovného profilu buď chýba, alebo je poškodená. Z toho dôvodu bol odstránený pracovný profil aj k nemu priradené dáta. Ak potrebujete pomoc, kontaktujte svojho správcu."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Váš pracovný profil už v tomto zariadení nie je k dispozícii"</string>
<string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Príliš veľa pokusov o zadanie hesla"</string>
+ <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+ <skip />
<string name="network_logging_notification_title" msgid="554983187553845004">"Zariadenie je spravované"</string>
<string name="network_logging_notification_text" msgid="1327373071132562512">"Vaša organizácia spravuje toto zariadenie a môže sledovať sieťovú premávku. Klepnutím zobrazíte podrobnosti."</string>
<string name="factory_reset_warning" msgid="6858705527798047809">"Vaše zariadenie bude vymazané"</string>
@@ -1156,10 +1158,8 @@
<string name="loading" msgid="3138021523725055037">"Načítava sa…"</string>
<string name="capital_on" msgid="2770685323900821829">"I"</string>
<string name="capital_off" msgid="7443704171014626777">"O"</string>
- <!-- no translation found for checked (9179896827054513119) -->
- <skip />
- <!-- no translation found for not_checked (7972320087569023342) -->
- <skip />
+ <string name="checked" msgid="9179896827054513119">"začiarknuté"</string>
+ <string name="not_checked" msgid="7972320087569023342">"nezačiarknuté"</string>
<string name="whichApplication" msgid="5432266899591255759">"Dokončiť akciu pomocou aplikácie"</string>
<string name="whichApplicationNamed" msgid="6969946041713975681">"Dokončiť akciu pomocou aplikácie %1$s"</string>
<string name="whichApplicationLabel" msgid="7852182961472531728">"Dokončiť akciu"</string>
@@ -2072,6 +2072,5 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Prepnúť rozdelenú obrazovku"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Uzamknúť obrazovku"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Snímka obrazovky"</string>
- <!-- no translation found for accessibility_freeform_caption (7873194416838321119) -->
- <skip />
+ <string name="accessibility_freeform_caption" msgid="7873194416838321119">"Aplikácia <xliff:g id="APP_NAME">%1$s</xliff:g> vo vyskakovacom okne."</string>
</resources>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index d15d6a96a70a..04940688c8fc 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -192,6 +192,8 @@
<string name="work_profile_deleted_details" msgid="3773706828364418016">"Skrbniška aplikacija delovnega profila manjka ali pa je poškodovana, zaradi česar je bil delovni profil s povezanimi podatki izbrisan. Za pomoč se obrnite na skrbnika."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Vaš delovni profil ni več na voljo v tej napravi"</string>
<string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Preveč poskusov vnosa gesla"</string>
+ <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+ <skip />
<string name="network_logging_notification_title" msgid="554983187553845004">"Naprava je upravljana"</string>
<string name="network_logging_notification_text" msgid="1327373071132562512">"Vaša organizacija upravlja to napravo in lahko nadzira omrežni promet. Dotaknite se za podrobnosti."</string>
<string name="factory_reset_warning" msgid="6858705527798047809">"Podatki v napravi bodo izbrisani"</string>
@@ -1156,10 +1158,8 @@
<string name="loading" msgid="3138021523725055037">"Nalaganje …"</string>
<string name="capital_on" msgid="2770685323900821829">"VKLOPLJENO"</string>
<string name="capital_off" msgid="7443704171014626777">"IZKLOPLJENO"</string>
- <!-- no translation found for checked (9179896827054513119) -->
- <skip />
- <!-- no translation found for not_checked (7972320087569023342) -->
- <skip />
+ <string name="checked" msgid="9179896827054513119">"potrjeno"</string>
+ <string name="not_checked" msgid="7972320087569023342">"ni potrjeno"</string>
<string name="whichApplication" msgid="5432266899591255759">"Dokončanje dejanja z"</string>
<string name="whichApplicationNamed" msgid="6969946041713975681">"Dokončanje dejanja z aplikacijo %1$s"</string>
<string name="whichApplicationLabel" msgid="7852182961472531728">"Izvedba dejanja"</string>
@@ -2072,6 +2072,5 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Preklop razdeljenega zaslona"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Zaklenjen zaslon"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Posnetek zaslona"</string>
- <!-- no translation found for accessibility_freeform_caption (7873194416838321119) -->
- <skip />
+ <string name="accessibility_freeform_caption" msgid="7873194416838321119">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> v pojavnem oknu."</string>
</resources>
diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml
index 6bf818403a6d..20e6ae513ada 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -188,6 +188,8 @@
<string name="work_profile_deleted_details" msgid="3773706828364418016">"Aplikacioni i administratorit të profilit të punës mungon ose është dëmtuar. Si rezultat i kësaj, profili yt i punës dhe të dhënat përkatëse janë fshirë. Kontakto me administratorin për ndihmë."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Profili yt i punës nuk është më i disponueshëm në këtë pajisje"</string>
<string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Shumë përpjekje për fjalëkalimin"</string>
+ <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+ <skip />
<string name="network_logging_notification_title" msgid="554983187553845004">"Pajisja është e menaxhuar"</string>
<string name="network_logging_notification_text" msgid="1327373071132562512">"Organizata jote e menaxhon këtë pajisje dhe mund të monitorojë trafikun e rrjetit. Trokit për detaje."</string>
<string name="factory_reset_warning" msgid="6858705527798047809">"Pajisja do të spastrohet"</string>
@@ -1116,10 +1118,8 @@
<string name="loading" msgid="3138021523725055037">"Po ngarkohet..."</string>
<string name="capital_on" msgid="2770685323900821829">"Aktivizuar"</string>
<string name="capital_off" msgid="7443704171014626777">"Çaktivizuar"</string>
- <!-- no translation found for checked (9179896827054513119) -->
- <skip />
- <!-- no translation found for not_checked (7972320087569023342) -->
- <skip />
+ <string name="checked" msgid="9179896827054513119">"u përzgjodh"</string>
+ <string name="not_checked" msgid="7972320087569023342">"nuk u përzgjodh"</string>
<string name="whichApplication" msgid="5432266899591255759">"Përfundo veprimin duke përdorur"</string>
<string name="whichApplicationNamed" msgid="6969946041713975681">"Përfundo veprimin duke përdorur %1$s"</string>
<string name="whichApplicationLabel" msgid="7852182961472531728">"Përfundo veprimin"</string>
@@ -2004,6 +2004,5 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Kalo tek ekrani i ndarë"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Ekrani i kyçjes"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Pamja e ekranit"</string>
- <!-- no translation found for accessibility_freeform_caption (7873194416838321119) -->
- <skip />
+ <string name="accessibility_freeform_caption" msgid="7873194416838321119">"Aplikacioni <xliff:g id="APP_NAME">%1$s</xliff:g> në dritaren kërcyese."</string>
</resources>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 37410a761a9e..db53b23d9813 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -190,6 +190,8 @@
<string name="work_profile_deleted_details" msgid="3773706828364418016">"Апликација за администраторе на профилу за Work недостаје или је оштећена. Због тога су профил за Work и повезани подаци избрисани. Обратите се администратору за помоћ."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Профил за Work више није доступан на овом уређају"</string>
<string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Превише покушаја уноса лозинке"</string>
+ <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+ <skip />
<string name="network_logging_notification_title" msgid="554983187553845004">"Уређајем се управља"</string>
<string name="network_logging_notification_text" msgid="1327373071132562512">"Организација управља овим уређајем и може да надгледа мрежни саобраћај. Додирните за детаље."</string>
<string name="factory_reset_warning" msgid="6858705527798047809">"Уређај ће бити обрисан"</string>
@@ -1136,10 +1138,8 @@
<string name="loading" msgid="3138021523725055037">"Учитава се…"</string>
<string name="capital_on" msgid="2770685323900821829">"ДА"</string>
<string name="capital_off" msgid="7443704171014626777">"НЕ"</string>
- <!-- no translation found for checked (9179896827054513119) -->
- <skip />
- <!-- no translation found for not_checked (7972320087569023342) -->
- <skip />
+ <string name="checked" msgid="9179896827054513119">"означено је"</string>
+ <string name="not_checked" msgid="7972320087569023342">"није означено"</string>
<string name="whichApplication" msgid="5432266899591255759">"Довршавање радње помоћу"</string>
<string name="whichApplicationNamed" msgid="6969946041713975681">"Завршите радњу помоћу апликације %1$s"</string>
<string name="whichApplicationLabel" msgid="7852182961472531728">"Заврши радњу"</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index a5b657a4dd96..9e99aec5e9b1 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -188,6 +188,8 @@
<string name="work_profile_deleted_details" msgid="3773706828364418016">"Administratörsappen för jobbprofilen saknas eller är skadad. Det innebär att jobbprofilen och all relaterad data har raderats. Kontakta administratören om du vill ha hjälp."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Jobbprofilen är inte längre tillgänglig på enheten"</string>
<string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"För många försök med lösenord"</string>
+ <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+ <skip />
<string name="network_logging_notification_title" msgid="554983187553845004">"Enheten hanteras"</string>
<string name="network_logging_notification_text" msgid="1327373071132562512">"Organisationen hanterar den här enheten och kan övervaka nätverkstrafiken. Tryck om du vill veta mer."</string>
<string name="factory_reset_warning" msgid="6858705527798047809">"Enheten kommer att rensas"</string>
@@ -1116,10 +1118,8 @@
<string name="loading" msgid="3138021523725055037">"Läser in …"</string>
<string name="capital_on" msgid="2770685323900821829">"PÅ"</string>
<string name="capital_off" msgid="7443704171014626777">"AV"</string>
- <!-- no translation found for checked (9179896827054513119) -->
- <skip />
- <!-- no translation found for not_checked (7972320087569023342) -->
- <skip />
+ <string name="checked" msgid="9179896827054513119">"markerad"</string>
+ <string name="not_checked" msgid="7972320087569023342">"inte markerad"</string>
<string name="whichApplication" msgid="5432266899591255759">"Slutför åtgärd genom att använda"</string>
<string name="whichApplicationNamed" msgid="6969946041713975681">"Slutför åtgärden med %1$s"</string>
<string name="whichApplicationLabel" msgid="7852182961472531728">"Slutför åtgärd"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index d587e2584c97..d7b3555bf2af 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -188,6 +188,8 @@
<string name="work_profile_deleted_details" msgid="3773706828364418016">"Programu ya msimamizi wa wasifu wa kazini imepotea au ina hitilafu. Kwa sababu hiyo, wasifu wako wa kazini na data husika imefutwa. Wasiliana na msimamizi wako kwa usaidizi."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Wasifu wako wa kazini haupatikani tena kwenye kifaa hiki"</string>
<string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Umejaribu kuweka nenosiri mara nyingi mno"</string>
+ <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+ <skip />
<string name="network_logging_notification_title" msgid="554983187553845004">"Kifaa kinadhibitiwa"</string>
<string name="network_logging_notification_text" msgid="1327373071132562512">"Shirika lako linadhibiti kifaa hiki na huenda likafuatilia shughuli kwenye mtandao. Gusa ili upate maelezo zaidi."</string>
<string name="factory_reset_warning" msgid="6858705527798047809">"Data iliyomo kwenye kifaa chako itafutwa"</string>
@@ -1116,10 +1118,8 @@
<string name="loading" msgid="3138021523725055037">"Inapakia…"</string>
<string name="capital_on" msgid="2770685323900821829">"Washa"</string>
<string name="capital_off" msgid="7443704171014626777">"ZIMA"</string>
- <!-- no translation found for checked (9179896827054513119) -->
- <skip />
- <!-- no translation found for not_checked (7972320087569023342) -->
- <skip />
+ <string name="checked" msgid="9179896827054513119">"imeteuliwa"</string>
+ <string name="not_checked" msgid="7972320087569023342">"haijateuliwa"</string>
<string name="whichApplication" msgid="5432266899591255759">"Kamilisha kitendo ukitumia"</string>
<string name="whichApplicationNamed" msgid="6969946041713975681">"Kamilisha kitendo ukitumia %1$s"</string>
<string name="whichApplicationLabel" msgid="7852182961472531728">"Kamilisha kitendo"</string>
@@ -2004,6 +2004,5 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Geuza Skrini Iliyogawanywa"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Skrini Iliyofungwa"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Picha ya skrini"</string>
- <!-- no translation found for accessibility_freeform_caption (7873194416838321119) -->
- <skip />
+ <string name="accessibility_freeform_caption" msgid="7873194416838321119">"Programu ya <xliff:g id="APP_NAME">%1$s</xliff:g> katika dirisha Ibukizi."</string>
</resources>
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index 90b8bc80e89a..569977c5013e 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -188,6 +188,8 @@
<string name="work_profile_deleted_details" msgid="3773706828364418016">"பணிக் கணக்கு நிர்வாகி ஆப்ஸ் இல்லை அல்லது அது சிதைந்துள்ளது. இதன் விளைவாக, உங்கள் பணிக் கணக்குமும் அதனுடன் தொடர்புடைய தரவும் நீக்கப்பட்டன. உதவிக்கு, நிர்வாகியைத் தொடர்புகொள்ளவும்."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"இந்தச் சாதனத்தில் இனி பணிக் கணக்கு கிடைக்காது"</string>
<string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"கடவுச்சொல்லை அதிக முறை தவறாக முயற்சித்துவிட்டீர்கள்"</string>
+ <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+ <skip />
<string name="network_logging_notification_title" msgid="554983187553845004">"சாதனம் நிர்வகிக்கப்படுகிறது"</string>
<string name="network_logging_notification_text" msgid="1327373071132562512">"உங்கள் நிறுவனம் இந்தச் சாதனத்தை நிர்வகிக்கும், அத்துடன் அது நெட்வொர்க் ட்ராஃபிக்கைக் கண்காணிக்கலாம். விவரங்களுக்கு, தட்டவும்."</string>
<string name="factory_reset_warning" msgid="6858705527798047809">"சாதனத் தரவு அழிக்கப்படும்"</string>
@@ -1116,10 +1118,8 @@
<string name="loading" msgid="3138021523725055037">"ஏற்றுகிறது..."</string>
<string name="capital_on" msgid="2770685323900821829">"ஆன்"</string>
<string name="capital_off" msgid="7443704171014626777">"ஆஃப்"</string>
- <!-- no translation found for checked (9179896827054513119) -->
- <skip />
- <!-- no translation found for not_checked (7972320087569023342) -->
- <skip />
+ <string name="checked" msgid="9179896827054513119">"இயக்கப்பட்டுள்ளது"</string>
+ <string name="not_checked" msgid="7972320087569023342">"முடக்கப்பட்டுள்ளது"</string>
<string name="whichApplication" msgid="5432266899591255759">"இதைப் பயன்படுத்தி செயலை நிறைவுசெய்"</string>
<string name="whichApplicationNamed" msgid="6969946041713975681">"%1$s ஐப் பயன்படுத்தி செயலை முடிக்கவும்"</string>
<string name="whichApplicationLabel" msgid="7852182961472531728">"செயலை முடி"</string>
@@ -2004,6 +2004,5 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"திரைப் பிரிப்பை நிலைமாற்று"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"பூட்டுத் திரை"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"ஸ்கிரீன்ஷாட்"</string>
- <!-- no translation found for accessibility_freeform_caption (7873194416838321119) -->
- <skip />
+ <string name="accessibility_freeform_caption" msgid="7873194416838321119">"<xliff:g id="APP_NAME">%1$s</xliff:g> ஆப்ஸில் உள்ள பாப் அப் சாளரம்."</string>
</resources>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index 63821aa9008c..9600172079b7 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -188,6 +188,8 @@
<string name="work_profile_deleted_details" msgid="3773706828364418016">"కార్యాలయ ప్రొఫైల్ నిర్వాహక యాప్ లేదు లేదా పాడైంది. తత్ఫలితంగా, మీ కార్యాలయ ప్రొఫైల్ మరియు సంబంధిత డేటా తొలగించబడ్డాయి. సహాయం కోసం మీ నిర్వాహకులను సంప్రదించండి."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"ఈ పరికరంలో మీ కార్యాలయ ప్రొఫైల్ ఇప్పుడు అందుబాటులో లేదు"</string>
<string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"చాలా ఎక్కువ పాస్‌వర్డ్ ప్రయత్నాలు చేసారు"</string>
+ <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+ <skip />
<string name="network_logging_notification_title" msgid="554983187553845004">"పరికరం నిర్వహించబడింది"</string>
<string name="network_logging_notification_text" msgid="1327373071132562512">"మీ సంస్థ ఈ పరికరాన్ని నిర్వహిస్తుంది మరియు నెట్‌వర్క్ ట్రాఫిక్‌ని పర్యవేక్షించవచ్చు. వివరాల కోసం నొక్కండి."</string>
<string name="factory_reset_warning" msgid="6858705527798047809">"మీ పరికరంలోని డేటా తొలగించబడుతుంది"</string>
@@ -1116,10 +1118,8 @@
<string name="loading" msgid="3138021523725055037">"లోడ్ చేస్తోంది…"</string>
<string name="capital_on" msgid="2770685323900821829">"ఆన్‌లో ఉంది"</string>
<string name="capital_off" msgid="7443704171014626777">"ఆఫ్‌"</string>
- <!-- no translation found for checked (9179896827054513119) -->
- <skip />
- <!-- no translation found for not_checked (7972320087569023342) -->
- <skip />
+ <string name="checked" msgid="9179896827054513119">"ఎంచుకోబడింది"</string>
+ <string name="not_checked" msgid="7972320087569023342">"ఎంచుకోలేదు"</string>
<string name="whichApplication" msgid="5432266899591255759">"దీన్ని ఉపయోగించి చర్యను పూర్తి చేయండి"</string>
<string name="whichApplicationNamed" msgid="6969946041713975681">"%1$sను ఉపయోగించి చర్యను పూర్తి చేయి"</string>
<string name="whichApplicationLabel" msgid="7852182961472531728">"చర్యను పూర్తి చేయి"</string>
@@ -2004,6 +2004,5 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"స్క్రీన్ విభజనను టోగుల్ చేయి"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"స్క్రీన్‌ను లాక్ చేయి"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"స్క్రీన్‌షాట్"</string>
- <!-- no translation found for accessibility_freeform_caption (7873194416838321119) -->
- <skip />
+ <string name="accessibility_freeform_caption" msgid="7873194416838321119">"పాప్-అప్ విండోలో <xliff:g id="APP_NAME">%1$s</xliff:g> యాప్ ఉంది."</string>
</resources>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index d4646b94d388..4dd0d0fa54aa 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -188,6 +188,8 @@
<string name="work_profile_deleted_details" msgid="3773706828364418016">"แอปผู้ดูแลระบบโปรไฟล์งานไม่มีอยู่หรือเสียหาย ระบบจึงทำการลบโปรไฟล์งานและข้อมูลที่เกี่ยวข้องของคุณออก โปรดติดต่อผู้ดูแลระบบเพื่อรับความช่วยเหลือ"</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"โปรไฟล์งานของคุณไม่สามารถใช้ในอุปกรณ์นี้อีกต่อไป"</string>
<string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"ลองป้อนรหัสผ่านหลายครั้งเกินไป"</string>
+ <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+ <skip />
<string name="network_logging_notification_title" msgid="554983187553845004">"อุปกรณ์มีการจัดการ"</string>
<string name="network_logging_notification_text" msgid="1327373071132562512">"องค์กรของคุณจัดการอุปกรณ์นี้และอาจตรวจสอบการจราจรของข้อมูลในเครือข่าย แตะเพื่อดูรายละเอียด"</string>
<string name="factory_reset_warning" msgid="6858705527798047809">"ระบบจะลบข้อมูลในอุปกรณ์ของคุณ"</string>
@@ -1116,10 +1118,8 @@
<string name="loading" msgid="3138021523725055037">"กำลังโหลด..."</string>
<string name="capital_on" msgid="2770685323900821829">"เปิด"</string>
<string name="capital_off" msgid="7443704171014626777">"ปิด"</string>
- <!-- no translation found for checked (9179896827054513119) -->
- <skip />
- <!-- no translation found for not_checked (7972320087569023342) -->
- <skip />
+ <string name="checked" msgid="9179896827054513119">"เลือกไว้"</string>
+ <string name="not_checked" msgid="7972320087569023342">"ยังไม่เลือก"</string>
<string name="whichApplication" msgid="5432266899591255759">"ทำงานให้เสร็จโดยใช้"</string>
<string name="whichApplicationNamed" msgid="6969946041713975681">"ดำเนินการให้เสร็จสมบูรณ์โดยใช้ %1$s"</string>
<string name="whichApplicationLabel" msgid="7852182961472531728">"ทำงานให้เสร็จสิ้น"</string>
@@ -2004,6 +2004,5 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"เปิด/ปิดการแบ่งหน้าจอ"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"หน้าจอล็อก"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"ภาพหน้าจอ"</string>
- <!-- no translation found for accessibility_freeform_caption (7873194416838321119) -->
- <skip />
+ <string name="accessibility_freeform_caption" msgid="7873194416838321119">"แอป <xliff:g id="APP_NAME">%1$s</xliff:g> ในหน้าต่างป๊อปอัป"</string>
</resources>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 93ec51799fbc..bde4027fd73b 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -188,6 +188,8 @@
<string name="work_profile_deleted_details" msgid="3773706828364418016">"Nawawala o nasira ang admin app ng profile sa trabaho. Dahil dito, na-delete ang profile mo sa trabaho at nauugnay na data. Makipag-ugnayan sa iyong admin para sa tulong."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Hindi na available sa device na ito ang iyong profile sa trabaho"</string>
<string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Masyadong maraming pagsubok sa password"</string>
+ <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+ <skip />
<string name="network_logging_notification_title" msgid="554983187553845004">"Pinamamahalaan ang device"</string>
<string name="network_logging_notification_text" msgid="1327373071132562512">"Pinamamahalaan ng iyong organisasyon ang device na ito, at maaari nitong subaybayan ang trapiko sa network. I-tap para sa mga detalye."</string>
<string name="factory_reset_warning" msgid="6858705527798047809">"Buburahin ang iyong device"</string>
@@ -1116,10 +1118,8 @@
<string name="loading" msgid="3138021523725055037">"Naglo-load…"</string>
<string name="capital_on" msgid="2770685323900821829">"I-ON"</string>
<string name="capital_off" msgid="7443704171014626777">"I-OFF"</string>
- <!-- no translation found for checked (9179896827054513119) -->
- <skip />
- <!-- no translation found for not_checked (7972320087569023342) -->
- <skip />
+ <string name="checked" msgid="9179896827054513119">"nilagyan ng check"</string>
+ <string name="not_checked" msgid="7972320087569023342">"hindi nilagyan ng check"</string>
<string name="whichApplication" msgid="5432266899591255759">"Kumpletuhin ang pagkilos gamit ang"</string>
<string name="whichApplicationNamed" msgid="6969946041713975681">"Tapusin ang pagkilos gamit ang %1$s"</string>
<string name="whichApplicationLabel" msgid="7852182961472531728">"Gawin ang pagkilos"</string>
@@ -2004,6 +2004,5 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"I-toggle ang Split Screen"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Lock Screen"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Screenshot"</string>
- <!-- no translation found for accessibility_freeform_caption (7873194416838321119) -->
- <skip />
+ <string name="accessibility_freeform_caption" msgid="7873194416838321119">"<xliff:g id="APP_NAME">%1$s</xliff:g> app sa Pop-up na window."</string>
</resources>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 1a4d5324de5f..0168ba0af607 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -188,6 +188,8 @@
<string name="work_profile_deleted_details" msgid="3773706828364418016">"İş profili yönetici uygulaması eksik ya da bozuk. Bunun sonucunda iş profiliniz ve ilgili veriler silindi. Yardım almak için yöneticiniz ile iletişim kurun."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"İş profiliniz arık bu cihazda kullanılamıyor"</string>
<string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Çok fazla şifre denemesi yapıldı"</string>
+ <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+ <skip />
<string name="network_logging_notification_title" msgid="554983187553845004">"Cihaz yönetiliyor"</string>
<string name="network_logging_notification_text" msgid="1327373071132562512">"Kuruluşunuz bu cihazı yönetmekte olup ağ trafiğini izleyebilir. Ayrıntılar için dokunun."</string>
<string name="factory_reset_warning" msgid="6858705527798047809">"Cihazınız silinecek"</string>
@@ -1116,10 +1118,8 @@
<string name="loading" msgid="3138021523725055037">"Yükleniyor..."</string>
<string name="capital_on" msgid="2770685323900821829">"AÇIK"</string>
<string name="capital_off" msgid="7443704171014626777">"KAPALI"</string>
- <!-- no translation found for checked (9179896827054513119) -->
- <skip />
- <!-- no translation found for not_checked (7972320087569023342) -->
- <skip />
+ <string name="checked" msgid="9179896827054513119">"işaretli"</string>
+ <string name="not_checked" msgid="7972320087569023342">"işaretli değil"</string>
<string name="whichApplication" msgid="5432266899591255759">"İşlemi şunu kullanarak tamamla"</string>
<string name="whichApplicationNamed" msgid="6969946041713975681">"İşlemi %1$s kullanarak tamamla"</string>
<string name="whichApplicationLabel" msgid="7852182961472531728">"İşlemi tamamla"</string>
@@ -2004,6 +2004,5 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Bölünmüş Ekranı aç/kapat"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Kilit Ekranı"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Ekran görüntüsü"</string>
- <!-- no translation found for accessibility_freeform_caption (7873194416838321119) -->
- <skip />
+ <string name="accessibility_freeform_caption" msgid="7873194416838321119">"Pop-up pencerede <xliff:g id="APP_NAME">%1$s</xliff:g> uygulaması."</string>
</resources>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index b785e060f610..32042efd98be 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -192,6 +192,8 @@
<string name="work_profile_deleted_details" msgid="3773706828364418016">"Додаток адміністратора в робочому профілі відсутній або пошкоджений. У результаті ваш робочий профіль і пов’язані з ним дані видалено. Зверніться до свого адміністратора по допомогу."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Робочий профіль більше не доступний на цьому пристрої"</string>
<string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Забагато спроб ввести пароль"</string>
+ <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+ <skip />
<string name="network_logging_notification_title" msgid="554983187553845004">"Пристрій контролюється"</string>
<string name="network_logging_notification_text" msgid="1327373071132562512">"Адміністратор вашої організації контролює цей пристрій і відстежує мережевий трафік. Торкніться, щоб дізнатися більше."</string>
<string name="factory_reset_warning" msgid="6858705527798047809">"З вашого пристрою буде стерто всі дані"</string>
@@ -1156,10 +1158,8 @@
<string name="loading" msgid="3138021523725055037">"Завантаження..."</string>
<string name="capital_on" msgid="2770685323900821829">"УВІМК"</string>
<string name="capital_off" msgid="7443704171014626777">"ВИМК"</string>
- <!-- no translation found for checked (9179896827054513119) -->
- <skip />
- <!-- no translation found for not_checked (7972320087569023342) -->
- <skip />
+ <string name="checked" msgid="9179896827054513119">"вибрано"</string>
+ <string name="not_checked" msgid="7972320087569023342">"не вибрано"</string>
<string name="whichApplication" msgid="5432266899591255759">"Завершити дію за доп."</string>
<string name="whichApplicationNamed" msgid="6969946041713975681">"Завершити дію за допомогою %1$s"</string>
<string name="whichApplicationLabel" msgid="7852182961472531728">"Завершити дію"</string>
@@ -2072,6 +2072,5 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Розділити екран"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Заблокувати екран"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Знімок екрана"</string>
- <!-- no translation found for accessibility_freeform_caption (7873194416838321119) -->
- <skip />
+ <string name="accessibility_freeform_caption" msgid="7873194416838321119">"Додаток <xliff:g id="APP_NAME">%1$s</xliff:g> у спливаючому вікні."</string>
</resources>
diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml
index b54653ed7c62..1dd8911fa4b3 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -188,6 +188,8 @@
<string name="work_profile_deleted_details" msgid="3773706828364418016">"دفتری پروفائل کی منتظم ایپ یا تو غائب ہے یا خراب ہے۔ اس کی وجہ سے، آپ کا دفتری پروفائل اور متعلقہ ڈیٹا حذف کر دیے گئے ہیں۔ مدد کیلئے اپنے منتظم سے رابطہ کریں۔"</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"آپ کا دفتری پروفائل اس آلہ پر مزید دستیاب نہیں ہے"</string>
<string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"پاس ورڈ کی بہت ساری کوششیں"</string>
+ <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+ <skip />
<string name="network_logging_notification_title" msgid="554983187553845004">"آلہ زیر انتظام ہے"</string>
<string name="network_logging_notification_text" msgid="1327373071132562512">"آپ کی تنظیم اس آلے کا نظم کرتی ہے اور وہ نیٹ ورک ٹریفک کی نگرانی کر سکتی ہے۔ تفاصیل کیلئے تھپتھپائیں۔"</string>
<string name="factory_reset_warning" msgid="6858705527798047809">"آپ کا آلہ صاف کر دیا جائے گا"</string>
@@ -1116,10 +1118,8 @@
<string name="loading" msgid="3138021523725055037">"لوڈ ہو رہا ہے…"</string>
<string name="capital_on" msgid="2770685323900821829">"آن"</string>
<string name="capital_off" msgid="7443704171014626777">"آف"</string>
- <!-- no translation found for checked (9179896827054513119) -->
- <skip />
- <!-- no translation found for not_checked (7972320087569023342) -->
- <skip />
+ <string name="checked" msgid="9179896827054513119">"چیک کیا گیا"</string>
+ <string name="not_checked" msgid="7972320087569023342">"چیک نہیں کیا گیا"</string>
<string name="whichApplication" msgid="5432266899591255759">"اس کا استعمال کرکے کارروائی مکمل کریں"</string>
<string name="whichApplicationNamed" msgid="6969946041713975681">"‏%1$s کا استعمال کر کے کارروائی مکمل کریں"</string>
<string name="whichApplicationLabel" msgid="7852182961472531728">"کارروائی مکمل کریں"</string>
@@ -2004,6 +2004,5 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"اسپلٹ اسکرین ٹوگل کریں"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"مقفل اسکرین"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"اسکرین شاٹ"</string>
- <!-- no translation found for accessibility_freeform_caption (7873194416838321119) -->
- <skip />
+ <string name="accessibility_freeform_caption" msgid="7873194416838321119">"پوپ-اپ ونڈو میں <xliff:g id="APP_NAME">%1$s</xliff:g> ایپ۔"</string>
</resources>
diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml
index c440e5321d46..4b7847d11de9 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -188,6 +188,8 @@
<string name="work_profile_deleted_details" msgid="3773706828364418016">"Ishchi profilning administrator ilovasi yo‘q yoki buzilgan. Shuning uchun, ishchi profilingiz va unga aloqador ma’lumotlar o‘chirib tashlandi. Yordam olish uchun administratoringizga murojaat qiling."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Bu qurilmada endi ishchi profilingiz mavjud emas"</string>
<string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Parol ko‘p marta xato kiritildi"</string>
+ <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+ <skip />
<string name="network_logging_notification_title" msgid="554983187553845004">"Bu – boshqariladigan qurilma"</string>
<string name="network_logging_notification_text" msgid="1327373071132562512">"Tashkilotingiz bu qurilmani boshqaradi va tarmoq trafigini nazorat qilishi mumkin. Tafsilotlar uchun bosing."</string>
<string name="factory_reset_warning" msgid="6858705527798047809">"Qurilmangizdagi ma’lumotlar o‘chirib tashlanadi"</string>
@@ -1116,10 +1118,8 @@
<string name="loading" msgid="3138021523725055037">"Yuklanmoqda…"</string>
<string name="capital_on" msgid="2770685323900821829">"I"</string>
<string name="capital_off" msgid="7443704171014626777">"O"</string>
- <!-- no translation found for checked (9179896827054513119) -->
- <skip />
- <!-- no translation found for not_checked (7972320087569023342) -->
- <skip />
+ <string name="checked" msgid="9179896827054513119">"belgilandi"</string>
+ <string name="not_checked" msgid="7972320087569023342">"belgilanmadi"</string>
<string name="whichApplication" msgid="5432266899591255759">"Ilovani tanlang"</string>
<string name="whichApplicationNamed" msgid="6969946041713975681">"“%1$s” bilan ochish"</string>
<string name="whichApplicationLabel" msgid="7852182961472531728">"Amalni bajarish"</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index e3623829a8bc..971cf34fd351 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -188,6 +188,8 @@
<string name="work_profile_deleted_details" msgid="3773706828364418016">"Ứng dụng quản trị hồ sơ công việc bị thiếu hoặc hỏng. Do vậy, hồ sơ công việc của bạn và dữ liệu liên quan đã bị xóa. Hãy liên hệ với quản trị viên của bạn để được trợ giúp."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Hồ sơ công việc của bạn không có sẵn trên thiết bị này nữa"</string>
<string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Quá nhiều lần nhập mật khẩu"</string>
+ <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+ <skip />
<string name="network_logging_notification_title" msgid="554983187553845004">"Thiết bị được quản lý"</string>
<string name="network_logging_notification_text" msgid="1327373071132562512">"Tổ chức của bạn sẽ quản lý thiết bị này và có thể theo dõi lưu lượng truy cập mạng. Nhấn để biết chi tiết."</string>
<string name="factory_reset_warning" msgid="6858705527798047809">"Thiết bị của bạn sẽ bị xóa"</string>
@@ -1116,10 +1118,8 @@
<string name="loading" msgid="3138021523725055037">"Đang tải…"</string>
<string name="capital_on" msgid="2770685323900821829">"BẬT"</string>
<string name="capital_off" msgid="7443704171014626777">"TẮT"</string>
- <!-- no translation found for checked (9179896827054513119) -->
- <skip />
- <!-- no translation found for not_checked (7972320087569023342) -->
- <skip />
+ <string name="checked" msgid="9179896827054513119">"đã chọn"</string>
+ <string name="not_checked" msgid="7972320087569023342">"chưa chọn"</string>
<string name="whichApplication" msgid="5432266899591255759">"Hoàn tất tác vụ đang sử dụng"</string>
<string name="whichApplicationNamed" msgid="6969946041713975681">"Hoàn tất tác vụ bằng %1$s"</string>
<string name="whichApplicationLabel" msgid="7852182961472531728">"Hoàn thành tác vụ"</string>
@@ -2004,6 +2004,5 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Bật/tắt chế độ chia đôi màn hình"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Khóa màn hình"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Chụp ảnh màn hình"</string>
- <!-- no translation found for accessibility_freeform_caption (7873194416838321119) -->
- <skip />
+ <string name="accessibility_freeform_caption" msgid="7873194416838321119">"Ứng dụng <xliff:g id="APP_NAME">%1$s</xliff:g> trong Cửa sổ bật lên."</string>
</resources>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 6df232adec81..d7dd8b19089b 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -188,6 +188,8 @@
<string name="work_profile_deleted_details" msgid="3773706828364418016">"工作资料管理应用缺失或损坏,因此系统已删除您的工作资料及相关数据。如需帮助,请与您的管理员联系。"</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"您的工作资料已不在此设备上"</string>
<string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"密码尝试次数过多"</string>
+ <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+ <skip />
<string name="network_logging_notification_title" msgid="554983187553845004">"设备为受管理设备"</string>
<string name="network_logging_notification_text" msgid="1327373071132562512">"贵单位会管理该设备,且可能会监控网络流量。点按即可了解详情。"</string>
<string name="factory_reset_warning" msgid="6858705527798047809">"系统将清空您的设备"</string>
@@ -1116,10 +1118,8 @@
<string name="loading" msgid="3138021523725055037">"正在加载..."</string>
<string name="capital_on" msgid="2770685323900821829">"开启"</string>
<string name="capital_off" msgid="7443704171014626777">"关闭"</string>
- <!-- no translation found for checked (9179896827054513119) -->
- <skip />
- <!-- no translation found for not_checked (7972320087569023342) -->
- <skip />
+ <string name="checked" msgid="9179896827054513119">"已勾选"</string>
+ <string name="not_checked" msgid="7972320087569023342">"未勾选"</string>
<string name="whichApplication" msgid="5432266899591255759">"选择要使用的应用:"</string>
<string name="whichApplicationNamed" msgid="6969946041713975681">"使用%1$s完成操作"</string>
<string name="whichApplicationLabel" msgid="7852182961472531728">"完成操作"</string>
@@ -2004,6 +2004,5 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"开启/关闭分屏"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"锁定屏幕"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"屏幕截图"</string>
- <!-- no translation found for accessibility_freeform_caption (7873194416838321119) -->
- <skip />
+ <string name="accessibility_freeform_caption" msgid="7873194416838321119">"以弹出式窗口形式打开的<xliff:g id="APP_NAME">%1$s</xliff:g>应用。"</string>
</resources>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index 41dcbed7001f..1a3784419393 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -188,6 +188,8 @@
<string name="work_profile_deleted_details" msgid="3773706828364418016">"工作設定檔管理員應用程式已遺失或損毀。因此,您的工作設定檔和相關資料已刪除。請聯絡您的管理員以取得協助。"</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"您的工作設定檔無法再在此裝置上使用"</string>
<string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"密碼輸入錯誤的次數過多"</string>
+ <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+ <skip />
<string name="network_logging_notification_title" msgid="554983187553845004">"裝置已受管理"</string>
<string name="network_logging_notification_text" msgid="1327373071132562512">"您的機構會管理此裝置,並可能會監控網絡流量。輕按即可瞭解詳情。"</string>
<string name="factory_reset_warning" msgid="6858705527798047809">"您的裝置將被清除"</string>
@@ -1116,10 +1118,8 @@
<string name="loading" msgid="3138021523725055037">"正在載入..."</string>
<string name="capital_on" msgid="2770685323900821829">"開啟"</string>
<string name="capital_off" msgid="7443704171014626777">"關"</string>
- <!-- no translation found for checked (9179896827054513119) -->
- <skip />
- <!-- no translation found for not_checked (7972320087569023342) -->
- <skip />
+ <string name="checked" msgid="9179896827054513119">"已勾選"</string>
+ <string name="not_checked" msgid="7972320087569023342">"未勾選"</string>
<string name="whichApplication" msgid="5432266899591255759">"完成操作需使用"</string>
<string name="whichApplicationNamed" msgid="6969946041713975681">"完成操作需使用 %1$s"</string>
<string name="whichApplicationLabel" msgid="7852182961472531728">"完成操作"</string>
@@ -2004,6 +2004,5 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"切換分割螢幕"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"將畫面上鎖"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"螢幕截圖"</string>
- <!-- no translation found for accessibility_freeform_caption (7873194416838321119) -->
- <skip />
+ <string name="accessibility_freeform_caption" msgid="7873194416838321119">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」應用程式在彈出式視窗中顯示。"</string>
</resources>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index d49df97c2d79..5e655ac1faef 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -188,6 +188,8 @@
<string name="work_profile_deleted_details" msgid="3773706828364418016">"工作資料夾管理員應用程式遺失或已毀損,因此系統刪除了你的工作資料夾和相關資料。如需協助,請與你的管理員聯絡。"</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"你的工作資料夾已不在這個裝置上"</string>
<string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"密碼輸入錯誤的次數過多"</string>
+ <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+ <skip />
<string name="network_logging_notification_title" msgid="554983187553845004">"裝置受到管理"</string>
<string name="network_logging_notification_text" msgid="1327373071132562512">"貴機構會管理這個裝置,且可能監控網路流量。輕觸即可瞭解詳情。"</string>
<string name="factory_reset_warning" msgid="6858705527798047809">"你的裝置資料將遭到清除"</string>
@@ -1116,10 +1118,8 @@
<string name="loading" msgid="3138021523725055037">"載入中…"</string>
<string name="capital_on" msgid="2770685323900821829">"開啟"</string>
<string name="capital_off" msgid="7443704171014626777">"關閉"</string>
- <!-- no translation found for checked (9179896827054513119) -->
- <skip />
- <!-- no translation found for not_checked (7972320087569023342) -->
- <skip />
+ <string name="checked" msgid="9179896827054513119">"已勾選"</string>
+ <string name="not_checked" msgid="7972320087569023342">"未勾選"</string>
<string name="whichApplication" msgid="5432266899591255759">"選擇要使用的應用程式"</string>
<string name="whichApplicationNamed" msgid="6969946041713975681">"完成操作需使用 %1$s"</string>
<string name="whichApplicationLabel" msgid="7852182961472531728">"完成操作"</string>
@@ -2004,6 +2004,5 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"切換分割畫面模式"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"螢幕鎖定"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"擷取螢幕畫面"</string>
- <!-- no translation found for accessibility_freeform_caption (7873194416838321119) -->
- <skip />
+ <string name="accessibility_freeform_caption" msgid="7873194416838321119">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」應用程式顯示在彈出式視窗中。"</string>
</resources>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index e99b592c395b..5f8d61ebc271 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -188,6 +188,8 @@
<string name="work_profile_deleted_details" msgid="3773706828364418016">"Uhlelo lokusebenza lokulawula lephrofayela yomsebenzi kungenzeka alukho noma lonakele. Njengomphumela, iphrofayela yakho yomsebenzi nedatha ehlobene isusiwe. Xhumana nomlawuli wakho ukuze uthole usizo."</string>
<string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"Iphrofayela yakho yomsebenzi ayisatholakali kule divayisi"</string>
<string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Imizamo yamaphasiwedi eminingi kakhulu"</string>
+ <!-- no translation found for device_ownership_relinquished (4080886992183195724) -->
+ <skip />
<string name="network_logging_notification_title" msgid="554983187553845004">"Idivayisi iphethwe"</string>
<string name="network_logging_notification_text" msgid="1327373071132562512">"Inhlangano yakho iphethe le divayisi futhi kungenzeka ingaqaphi ithrafikhi yenethiwekhi. Thephela imininingwane."</string>
<string name="factory_reset_warning" msgid="6858705527798047809">"Idivayisi yakho izosulwa"</string>
@@ -1116,10 +1118,8 @@
<string name="loading" msgid="3138021523725055037">"Iyalayisha…"</string>
<string name="capital_on" msgid="2770685323900821829">"VULIWE"</string>
<string name="capital_off" msgid="7443704171014626777">"VALIWE"</string>
- <!-- no translation found for checked (9179896827054513119) -->
- <skip />
- <!-- no translation found for not_checked (7972320087569023342) -->
- <skip />
+ <string name="checked" msgid="9179896827054513119">"kuhloliwe"</string>
+ <string name="not_checked" msgid="7972320087569023342">"akuhloliwe"</string>
<string name="whichApplication" msgid="5432266899591255759">"Qedela isenzo usebenzisa"</string>
<string name="whichApplicationNamed" msgid="6969946041713975681">"Qedela isenzo usebenzisa i-%1$s"</string>
<string name="whichApplicationLabel" msgid="7852182961472531728">"Qedela isenzo"</string>
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index ffcfe4310f06..166cde0d7005 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -298,9 +298,6 @@
<!-- Additional flag from base permission type: this permission can be automatically
granted to the system telephony apps -->
<flag name="telephony" value="0x400000" />
- <!-- Additional flag from base permission type: this permission can be automatically
- granted to the system wifi app-->
- <flag name="wifi" value="0x800000" />
</attr>
<!-- Flags indicating more context for a permission group. -->
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 74bb2cf6658d..76d95618b67c 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2363,9 +2363,11 @@
1 (0b001) - enforce (only install system packages if they are whitelisted)
2 (0b010) - log (log when a non-whitelisted package is run)
4 (0b100) - treat any package not mentioned in the whitelist file as implicitly whitelisted
+ 8 (0b1000) - ignore OTAs (don't install system packages during OTAs)
Note: This list must be kept current with PACKAGE_WHITELIST_MODE_PROP in
frameworks/base/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java -->
- <integer name="config_userTypePackageWhitelistMode">5</integer> <!-- 0b101 -->
+ <integer name="config_userTypePackageWhitelistMode">13</integer> <!-- 0b1101 -->
+ <!-- TODO(b/143200798): Change to value 5, i.e. 0b0101, when b/143200798 is resolved. -->
<!-- Whether UI for multi user should be shown -->
<bool name="config_enableMultiUserUI">false</bool>
@@ -3517,6 +3519,7 @@
-->
<string name="config_defaultWellbeingPackage" translatable="false"></string>
+
<!-- The package name for the system telephony apps.
This package must be trusted, as it will be granted with permissions with special telephony
protection level. Note, framework by default support multiple telephony apps, each package
@@ -3525,13 +3528,6 @@
-->
<string name="config_telephonyPackages" translatable="false">"com.android.phone,com.android.stk,com.android.providers.telephony,com.android.ons,com.android.cellbroadcastservice"</string>
- <!-- The package name for the default system wifi app.
- This package must be trusted, as it has the permissions to control wifi
- connectivity on the device.
- Example: "com.android.wifi"
- -->
- <string name="config_wifiPackage" translatable="false">"com.android.wifi"</string>
-
<!-- The component name for the default system attention service.
This service must be trusted, as it can be activated without explicit consent of the user.
See android.attention.AttentionManagerService.
@@ -4179,4 +4175,10 @@
<!-- Whether or not to show the built-in charging animation when the device begins charging
wirelessly. -->
<bool name="config_showBuiltinWirelessChargingAnim">true</bool>
+
+ <!-- A list of potential packages, in priority order, that can supply rules to
+ AppIntegrityManager. These need to be apps on the system partition. -->
+ <string-array name="config_integrityRuleProviderPackages" translatable="false">
+ <!-- Add packages here -->
+ </string-array>
</resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index a0aa18690b51..7310dafe3ecc 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -5083,11 +5083,14 @@
data (for example, username, password and credit card info) [CHAR LIMIT=NONE] -->
<string name="autofill_update_title_with_3types">Update these items in <b><xliff:g id="label" example="MyPass">%4$s</xliff:g></b>: <xliff:g id="type" example="Username">%1$s</xliff:g>, <xliff:g id="type" example="Password">%2$s</xliff:g>, and <xliff:g id="type" example="Credit Card">%3$s</xliff:g> ?</string>
-
<!-- Label for the autofill save button [CHAR LIMIT=NONE] -->
<string name="autofill_save_yes">Save</string>
<!-- Label for the autofill cancel button [CHAR LIMIT=NONE] -->
<string name="autofill_save_no">No thanks</string>
+ <!-- Label for the autofill cancel button, saying not to save the filled data at this moment. [CHAR LIMIT=NONE] -->
+ <string name="autofill_save_notnow">Not now</string>
+ <!-- Label for the autofill reject button, saying never to save the filled data. [CHAR LIMIT=NONE] -->
+ <string name="autofill_save_never">Never</string>
<!-- Label for the autofill update button [CHAR LIMIT=NONE] -->
<string name="autofill_update_yes">Update</string>
<!-- Label for the autofill continue button [CHAR LIMIT=NONE] -->
@@ -5333,5 +5336,5 @@
<string name="accessibility_system_action_screenshot_label">Screenshot</string>
<!-- Accessibility description of caption view -->
- <string name="accessibility_freeform_caption"><xliff:g id="app_name">%1$s</xliff:g> app in Pop-up window.</string>
+ <string name="accessibility_freeform_caption">Caption bar of <xliff:g id="app_name">%1$s</xliff:g>.</string>
</resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 1d5133901064..130b31f092e0 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -456,6 +456,7 @@
<java-symbol type="string" name="config_deviceSpecificDevicePolicyManagerService" />
<java-symbol type="string" name="config_deviceSpecificAudioService" />
<java-symbol type="integer" name="config_num_physical_slots" />
+ <java-symbol type="array" name="config_integrityRuleProviderPackages" />
<java-symbol type="color" name="tab_indicator_text_v4" />
@@ -3247,6 +3248,8 @@
<java-symbol type="string" name="autofill_save_title_with_3types" />
<java-symbol type="string" name="autofill_save_yes" />
<java-symbol type="string" name="autofill_save_no" />
+ <java-symbol type="string" name="autofill_save_notnow" />
+ <java-symbol type="string" name="autofill_save_never" />
<java-symbol type="string" name="autofill_save_type_password" />
<java-symbol type="string" name="autofill_save_type_address" />
<java-symbol type="string" name="autofill_save_type_credit_card" />
@@ -3360,7 +3363,6 @@
<java-symbol type="array" name="config_defaultTextClassifierPackages" />
<java-symbol type="string" name="config_defaultWellbeingPackage" />
<java-symbol type="string" name="config_telephonyPackages" />
- <java-symbol type="string" name="config_wifiPackage" />
<java-symbol type="string" name="config_defaultContentCaptureService" />
<java-symbol type="string" name="config_defaultAugmentedAutofillService" />
<java-symbol type="string" name="config_defaultAppPredictionService" />
diff --git a/core/tests/coretests/src/android/app/timedetector/PhoneTimeSuggestionTest.java b/core/tests/coretests/src/android/app/timedetector/PhoneTimeSuggestionTest.java
index 1b5ad8868a01..c9a86dcea84c 100644
--- a/core/tests/coretests/src/android/app/timedetector/PhoneTimeSuggestionTest.java
+++ b/core/tests/coretests/src/android/app/timedetector/PhoneTimeSuggestionTest.java
@@ -30,17 +30,22 @@ public class PhoneTimeSuggestionTest {
@Test
public void testEquals() {
- PhoneTimeSuggestion one =
- new PhoneTimeSuggestion(PHONE_ID, new TimestampedValue<>(1111L, 2222L));
+ PhoneTimeSuggestion one = new PhoneTimeSuggestion(PHONE_ID);
assertEquals(one, one);
- PhoneTimeSuggestion two =
- new PhoneTimeSuggestion(PHONE_ID, new TimestampedValue<>(1111L, 2222L));
+ PhoneTimeSuggestion two = new PhoneTimeSuggestion(PHONE_ID);
assertEquals(one, two);
assertEquals(two, one);
- PhoneTimeSuggestion three =
- new PhoneTimeSuggestion(PHONE_ID + 1, new TimestampedValue<>(1111L, 2222L));
+ one.setUtcTime(new TimestampedValue<>(1111L, 2222L));
+ assertEquals(one, one);
+
+ two.setUtcTime(new TimestampedValue<>(1111L, 2222L));
+ assertEquals(one, two);
+ assertEquals(two, one);
+
+ PhoneTimeSuggestion three = new PhoneTimeSuggestion(PHONE_ID + 1);
+ three.setUtcTime(new TimestampedValue<>(1111L, 2222L));
assertNotEquals(one, three);
assertNotEquals(three, one);
@@ -52,8 +57,10 @@ public class PhoneTimeSuggestionTest {
@Test
public void testParcelable() {
- PhoneTimeSuggestion one =
- new PhoneTimeSuggestion(PHONE_ID, new TimestampedValue<>(1111L, 2222L));
+ PhoneTimeSuggestion one = new PhoneTimeSuggestion(PHONE_ID);
+ assertEquals(one, roundTripParcelable(one));
+
+ one.setUtcTime(new TimestampedValue<>(1111L, 2222L));
assertEquals(one, roundTripParcelable(one));
// DebugInfo should also be stored (but is not checked by equals()
diff --git a/core/tests/coretests/src/android/app/timezonedetector/PhoneTimeZoneSuggestionTest.java b/core/tests/coretests/src/android/app/timezonedetector/PhoneTimeZoneSuggestionTest.java
new file mode 100644
index 000000000000..ae91edc5db35
--- /dev/null
+++ b/core/tests/coretests/src/android/app/timezonedetector/PhoneTimeZoneSuggestionTest.java
@@ -0,0 +1,170 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.timezonedetector;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertTrue;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import org.junit.Test;
+
+public class PhoneTimeZoneSuggestionTest {
+ private static final int PHONE_ID = 99999;
+
+ @Test
+ public void testEquals() {
+ PhoneTimeZoneSuggestion.Builder builder1 = new PhoneTimeZoneSuggestion.Builder(PHONE_ID);
+ {
+ PhoneTimeZoneSuggestion one = builder1.build();
+ assertEquals(one, one);
+ }
+
+ PhoneTimeZoneSuggestion.Builder builder2 = new PhoneTimeZoneSuggestion.Builder(PHONE_ID);
+ {
+ PhoneTimeZoneSuggestion one = builder1.build();
+ PhoneTimeZoneSuggestion two = builder2.build();
+ assertEquals(one, two);
+ assertEquals(two, one);
+ }
+
+ PhoneTimeZoneSuggestion.Builder builder3 =
+ new PhoneTimeZoneSuggestion.Builder(PHONE_ID + 1);
+ {
+ PhoneTimeZoneSuggestion one = builder1.build();
+ PhoneTimeZoneSuggestion three = builder3.build();
+ assertNotEquals(one, three);
+ assertNotEquals(three, one);
+ }
+
+ builder1.setZoneId("Europe/London");
+ builder1.setMatchType(PhoneTimeZoneSuggestion.MATCH_TYPE_NETWORK_COUNTRY_ONLY);
+ builder1.setQuality(PhoneTimeZoneSuggestion.QUALITY_SINGLE_ZONE);
+ {
+ PhoneTimeZoneSuggestion one = builder1.build();
+ PhoneTimeZoneSuggestion two = builder2.build();
+ assertNotEquals(one, two);
+ }
+
+ builder2.setZoneId("Europe/Paris");
+ builder2.setMatchType(PhoneTimeZoneSuggestion.MATCH_TYPE_NETWORK_COUNTRY_ONLY);
+ builder2.setQuality(PhoneTimeZoneSuggestion.QUALITY_SINGLE_ZONE);
+ {
+ PhoneTimeZoneSuggestion one = builder1.build();
+ PhoneTimeZoneSuggestion two = builder2.build();
+ assertNotEquals(one, two);
+ }
+
+ builder1.setZoneId("Europe/Paris");
+ {
+ PhoneTimeZoneSuggestion one = builder1.build();
+ PhoneTimeZoneSuggestion two = builder2.build();
+ assertEquals(one, two);
+ }
+
+ builder1.setMatchType(PhoneTimeZoneSuggestion.MATCH_TYPE_EMULATOR_ZONE_ID);
+ builder2.setMatchType(PhoneTimeZoneSuggestion.MATCH_TYPE_NETWORK_COUNTRY_ONLY);
+ {
+ PhoneTimeZoneSuggestion one = builder1.build();
+ PhoneTimeZoneSuggestion two = builder2.build();
+ assertNotEquals(one, two);
+ }
+
+ builder1.setMatchType(PhoneTimeZoneSuggestion.MATCH_TYPE_NETWORK_COUNTRY_ONLY);
+ {
+ PhoneTimeZoneSuggestion one = builder1.build();
+ PhoneTimeZoneSuggestion two = builder2.build();
+ assertEquals(one, two);
+ }
+
+ builder1.setQuality(PhoneTimeZoneSuggestion.QUALITY_SINGLE_ZONE);
+ builder2.setQuality(PhoneTimeZoneSuggestion.QUALITY_MULTIPLE_ZONES_WITH_DIFFERENT_OFFSETS);
+ {
+ PhoneTimeZoneSuggestion one = builder1.build();
+ PhoneTimeZoneSuggestion two = builder2.build();
+ assertNotEquals(one, two);
+ }
+
+ builder1.setQuality(PhoneTimeZoneSuggestion.QUALITY_MULTIPLE_ZONES_WITH_DIFFERENT_OFFSETS);
+ {
+ PhoneTimeZoneSuggestion one = builder1.build();
+ PhoneTimeZoneSuggestion two = builder2.build();
+ assertEquals(one, two);
+ }
+
+ // DebugInfo must not be considered in equals().
+ {
+ PhoneTimeZoneSuggestion one = builder1.build();
+ PhoneTimeZoneSuggestion two = builder2.build();
+ one.addDebugInfo("Debug info 1");
+ two.addDebugInfo("Debug info 2");
+ assertEquals(one, two);
+ }
+ }
+
+ @Test(expected = RuntimeException.class)
+ public void testBuilderValidates_emptyZone_badMatchType() {
+ PhoneTimeZoneSuggestion.Builder builder = new PhoneTimeZoneSuggestion.Builder(PHONE_ID);
+ // No zone ID, so match type should be left unset.
+ builder.setMatchType(PhoneTimeZoneSuggestion.MATCH_TYPE_NETWORK_COUNTRY_AND_OFFSET);
+ builder.build();
+ }
+
+ @Test(expected = RuntimeException.class)
+ public void testBuilderValidates_zoneSet_badMatchType() {
+ PhoneTimeZoneSuggestion.Builder builder = new PhoneTimeZoneSuggestion.Builder(PHONE_ID);
+ builder.setZoneId("Europe/London");
+ builder.setQuality(PhoneTimeZoneSuggestion.QUALITY_SINGLE_ZONE);
+ builder.build();
+ }
+
+ @Test
+ public void testParcelable() {
+ PhoneTimeZoneSuggestion.Builder builder = new PhoneTimeZoneSuggestion.Builder(PHONE_ID);
+ assertRoundTripParcelable(builder.build());
+
+ builder.setZoneId("Europe/London");
+ builder.setMatchType(PhoneTimeZoneSuggestion.MATCH_TYPE_EMULATOR_ZONE_ID);
+ builder.setQuality(PhoneTimeZoneSuggestion.QUALITY_SINGLE_ZONE);
+ PhoneTimeZoneSuggestion suggestion1 = builder.build();
+ assertRoundTripParcelable(suggestion1);
+
+ // DebugInfo should also be stored (but is not checked by equals()
+ String debugString = "This is debug info";
+ suggestion1.addDebugInfo(debugString);
+ PhoneTimeZoneSuggestion suggestion1_2 = roundTripParcelable(suggestion1);
+ assertEquals(suggestion1, suggestion1_2);
+ assertTrue(suggestion1_2.getDebugInfo().contains(debugString));
+ }
+
+ private static void assertRoundTripParcelable(PhoneTimeZoneSuggestion instance) {
+ assertEquals(instance, roundTripParcelable(instance));
+ }
+
+ @SuppressWarnings("unchecked")
+ private static <T extends Parcelable> T roundTripParcelable(T one) {
+ Parcel parcel = Parcel.obtain();
+ parcel.writeTypedObject(one, 0);
+ parcel.setDataPosition(0);
+
+ T toReturn = (T) parcel.readTypedObject(PhoneTimeZoneSuggestion.CREATOR);
+ parcel.recycle();
+ return toReturn;
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/integrity/model/AtomicFormulaTest.java b/core/tests/coretests/src/android/content/integrity/AtomicFormulaTest.java
index 988e18b8e194..e48f1c3a89c7 100644
--- a/services/tests/servicestests/src/com/android/server/integrity/model/AtomicFormulaTest.java
+++ b/core/tests/coretests/src/android/content/integrity/AtomicFormulaTest.java
@@ -14,20 +14,19 @@
* limitations under the License.
*/
-package com.android.server.integrity.model;
+package android.content.integrity;
-import static com.android.server.testutils.TestUtils.assertExpectException;
+import static android.content.integrity.TestUtils.assertExpectException;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import android.content.integrity.AtomicFormula.BooleanAtomicFormula;
+import android.content.integrity.AtomicFormula.IntAtomicFormula;
+import android.content.integrity.AtomicFormula.StringAtomicFormula;
import android.os.Parcel;
-import com.android.server.integrity.model.AtomicFormula.BooleanAtomicFormula;
-import com.android.server.integrity.model.AtomicFormula.IntAtomicFormula;
-import com.android.server.integrity.model.AtomicFormula.StringAtomicFormula;
-
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
@@ -38,8 +37,8 @@ public class AtomicFormulaTest {
@Test
public void testValidAtomicFormula_stringValue() {
StringAtomicFormula stringAtomicFormula =
- new StringAtomicFormula(AtomicFormula.PACKAGE_NAME,
- "com.test.app", /* isHashedValue= */ false);
+ new StringAtomicFormula(
+ AtomicFormula.PACKAGE_NAME, "com.test.app", /* isHashedValue= */ false);
assertEquals(AtomicFormula.PACKAGE_NAME, stringAtomicFormula.getKey());
}
@@ -65,10 +64,12 @@ public class AtomicFormulaTest {
assertExpectException(
IllegalArgumentException.class,
/* expectedExceptionMessageRegex */
- String.format(
- "Key VERSION_CODE cannot be used with StringAtomicFormula"),
- () -> new StringAtomicFormula(AtomicFormula.VERSION_CODE, "test-value",
- /* isHashedValue= */ false));
+ String.format("Key VERSION_CODE cannot be used with StringAtomicFormula"),
+ () ->
+ new StringAtomicFormula(
+ AtomicFormula.VERSION_CODE,
+ "test-value",
+ /* isHashedValue= */ false));
}
@Test
@@ -76,8 +77,7 @@ public class AtomicFormulaTest {
assertExpectException(
IllegalArgumentException.class,
/* expectedExceptionMessageRegex */
- String.format(
- "Key PACKAGE_NAME cannot be used with IntAtomicFormula"),
+ String.format("Key PACKAGE_NAME cannot be used with IntAtomicFormula"),
() -> new IntAtomicFormula(AtomicFormula.PACKAGE_NAME, AtomicFormula.EQ, 1));
}
@@ -86,16 +86,15 @@ public class AtomicFormulaTest {
assertExpectException(
IllegalArgumentException.class,
/* expectedExceptionMessageRegex */
- String.format(
- "Key PACKAGE_NAME cannot be used with BooleanAtomicFormula"),
+ String.format("Key PACKAGE_NAME cannot be used with BooleanAtomicFormula"),
() -> new BooleanAtomicFormula(AtomicFormula.PACKAGE_NAME, true));
}
@Test
public void testIsSatisfiable_string_true() {
StringAtomicFormula stringAtomicFormula =
- new StringAtomicFormula(AtomicFormula.PACKAGE_NAME,
- "com.test.app", /* isHashedValue= */ false);
+ new StringAtomicFormula(
+ AtomicFormula.PACKAGE_NAME, "com.test.app", /* isHashedValue= */ false);
AppInstallMetadata appInstallMetadata =
getAppInstallMetadataBuilder().setPackageName("com.test.app").build();
@@ -105,8 +104,8 @@ public class AtomicFormulaTest {
@Test
public void testIsSatisfiable_string_false() {
StringAtomicFormula stringAtomicFormula =
- new StringAtomicFormula(AtomicFormula.PACKAGE_NAME,
- "com.test.app", /* isHashedValue= */ false);
+ new StringAtomicFormula(
+ AtomicFormula.PACKAGE_NAME, "com.test.app", /* isHashedValue= */ false);
AppInstallMetadata appInstallMetadata =
getAppInstallMetadataBuilder().setPackageName("com.foo.bar").build();
@@ -235,8 +234,9 @@ public class AtomicFormulaTest {
@Test
public void testParcelUnparcel_string() {
- StringAtomicFormula formula = new StringAtomicFormula(AtomicFormula.PACKAGE_NAME, "abc",
- /* isHashedValue= */ false);
+ StringAtomicFormula formula =
+ new StringAtomicFormula(
+ AtomicFormula.PACKAGE_NAME, "abc", /* isHashedValue= */ false);
Parcel p = Parcel.obtain();
formula.writeToParcel(p, 0);
p.setDataPosition(0);
diff --git a/services/tests/servicestests/src/com/android/server/integrity/model/OpenFormulaTest.java b/core/tests/coretests/src/android/content/integrity/CompoundFormulaTest.java
index b58ffd7dd6c6..927e4dbb5200 100644
--- a/services/tests/servicestests/src/com/android/server/integrity/model/OpenFormulaTest.java
+++ b/core/tests/coretests/src/android/content/integrity/CompoundFormulaTest.java
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-package com.android.server.integrity.model;
+package android.content.integrity;
-import static com.android.server.testutils.TestUtils.assertExpectException;
+import static android.content.integrity.TestUtils.assertExpectException;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -32,21 +32,23 @@ import java.util.Arrays;
import java.util.Collections;
@RunWith(JUnit4.class)
-public class OpenFormulaTest {
+public class CompoundFormulaTest {
private static final AtomicFormula ATOMIC_FORMULA_1 =
- new AtomicFormula.StringAtomicFormula(AtomicFormula.PACKAGE_NAME, "test1",
- /* isHashedValue= */ false);
+ new AtomicFormula.StringAtomicFormula(
+ AtomicFormula.PACKAGE_NAME, "test1", /* isHashedValue= */ false);
private static final AtomicFormula ATOMIC_FORMULA_2 =
new AtomicFormula.IntAtomicFormula(AtomicFormula.VERSION_CODE, AtomicFormula.EQ, 1);
@Test
- public void testValidOpenFormula() {
- OpenFormula openFormula =
- new OpenFormula(OpenFormula.AND, Arrays.asList(ATOMIC_FORMULA_1, ATOMIC_FORMULA_2));
+ public void testValidCompoundFormula() {
+ CompoundFormula compoundFormula =
+ new CompoundFormula(
+ CompoundFormula.AND, Arrays.asList(ATOMIC_FORMULA_1, ATOMIC_FORMULA_2));
- assertEquals(OpenFormula.AND, openFormula.getConnector());
- assertEquals(Arrays.asList(ATOMIC_FORMULA_1, ATOMIC_FORMULA_2), openFormula.getFormulas());
+ assertEquals(CompoundFormula.AND, compoundFormula.getConnector());
+ assertEquals(
+ Arrays.asList(ATOMIC_FORMULA_1, ATOMIC_FORMULA_2), compoundFormula.getFormulas());
}
@Test
@@ -56,8 +58,8 @@ public class OpenFormulaTest {
/* expectedExceptionMessageRegex */
"Connector AND must have at least 2 formulas",
() ->
- new OpenFormula(
- OpenFormula.AND, Collections.singletonList(ATOMIC_FORMULA_1)));
+ new CompoundFormula(
+ CompoundFormula.AND, Collections.singletonList(ATOMIC_FORMULA_1)));
}
@Test
@@ -67,158 +69,169 @@ public class OpenFormulaTest {
/* expectedExceptionMessageRegex */
"Connector NOT must have 1 formula only",
() ->
- new OpenFormula(
- OpenFormula.NOT,
+ new CompoundFormula(
+ CompoundFormula.NOT,
Arrays.asList(ATOMIC_FORMULA_1, ATOMIC_FORMULA_2)));
}
@Test
public void testIsSatisfiable_notFalse_true() {
- OpenFormula openFormula = new OpenFormula(OpenFormula.NOT,
- Collections.singletonList(ATOMIC_FORMULA_1));
+ CompoundFormula compoundFormula =
+ new CompoundFormula(CompoundFormula.NOT, Arrays.asList(ATOMIC_FORMULA_1));
AppInstallMetadata appInstallMetadata =
getAppInstallMetadataBuilder().setPackageName("test2").build();
// validate assumptions about the metadata
assertFalse(ATOMIC_FORMULA_1.isSatisfied(appInstallMetadata));
- assertTrue(openFormula.isSatisfied(appInstallMetadata));
+ assertTrue(compoundFormula.isSatisfied(appInstallMetadata));
}
@Test
public void testIsSatisfiable_notTrue_false() {
- OpenFormula openFormula = new OpenFormula(OpenFormula.NOT,
- Collections.singletonList(ATOMIC_FORMULA_1));
+ CompoundFormula compoundFormula =
+ new CompoundFormula(CompoundFormula.NOT, Arrays.asList(ATOMIC_FORMULA_1));
AppInstallMetadata appInstallMetadata =
getAppInstallMetadataBuilder().setPackageName("test1").build();
// validate assumptions about the metadata
assertTrue(ATOMIC_FORMULA_1.isSatisfied(appInstallMetadata));
- assertFalse(openFormula.isSatisfied(appInstallMetadata));
+ assertFalse(compoundFormula.isSatisfied(appInstallMetadata));
}
@Test
public void testIsSatisfiable_trueAndTrue_true() {
- OpenFormula openFormula =
- new OpenFormula(OpenFormula.AND, Arrays.asList(ATOMIC_FORMULA_1, ATOMIC_FORMULA_2));
+ CompoundFormula compoundFormula =
+ new CompoundFormula(
+ CompoundFormula.AND, Arrays.asList(ATOMIC_FORMULA_1, ATOMIC_FORMULA_2));
AppInstallMetadata appInstallMetadata =
getAppInstallMetadataBuilder().setPackageName("test1").setVersionCode(1).build();
// validate assumptions about the metadata
assertTrue(ATOMIC_FORMULA_1.isSatisfied(appInstallMetadata));
assertTrue(ATOMIC_FORMULA_2.isSatisfied(appInstallMetadata));
- assertTrue(openFormula.isSatisfied(appInstallMetadata));
+ assertTrue(compoundFormula.isSatisfied(appInstallMetadata));
}
@Test
public void testIsSatisfiable_trueAndFalse_false() {
- OpenFormula openFormula =
- new OpenFormula(OpenFormula.AND, Arrays.asList(ATOMIC_FORMULA_1, ATOMIC_FORMULA_2));
+ CompoundFormula compoundFormula =
+ new CompoundFormula(
+ CompoundFormula.AND, Arrays.asList(ATOMIC_FORMULA_1, ATOMIC_FORMULA_2));
AppInstallMetadata appInstallMetadata =
getAppInstallMetadataBuilder().setPackageName("test1").setVersionCode(2).build();
// validate assumptions about the metadata
assertTrue(ATOMIC_FORMULA_1.isSatisfied(appInstallMetadata));
assertFalse(ATOMIC_FORMULA_2.isSatisfied(appInstallMetadata));
- assertFalse(openFormula.isSatisfied(appInstallMetadata));
+ assertFalse(compoundFormula.isSatisfied(appInstallMetadata));
}
@Test
public void testIsSatisfiable_falseAndTrue_false() {
- OpenFormula openFormula =
- new OpenFormula(OpenFormula.AND, Arrays.asList(ATOMIC_FORMULA_1, ATOMIC_FORMULA_2));
+ CompoundFormula compoundFormula =
+ new CompoundFormula(
+ CompoundFormula.AND, Arrays.asList(ATOMIC_FORMULA_1, ATOMIC_FORMULA_2));
AppInstallMetadata appInstallMetadata =
getAppInstallMetadataBuilder().setPackageName("test2").setVersionCode(1).build();
// validate assumptions about the metadata
assertFalse(ATOMIC_FORMULA_1.isSatisfied(appInstallMetadata));
assertTrue(ATOMIC_FORMULA_2.isSatisfied(appInstallMetadata));
- assertFalse(openFormula.isSatisfied(appInstallMetadata));
+ assertFalse(compoundFormula.isSatisfied(appInstallMetadata));
}
@Test
public void testIsSatisfiable_falseAndFalse_false() {
- OpenFormula openFormula =
- new OpenFormula(OpenFormula.AND, Arrays.asList(ATOMIC_FORMULA_1, ATOMIC_FORMULA_2));
+ CompoundFormula compoundFormula =
+ new CompoundFormula(
+ CompoundFormula.AND, Arrays.asList(ATOMIC_FORMULA_1, ATOMIC_FORMULA_2));
AppInstallMetadata appInstallMetadata =
getAppInstallMetadataBuilder().setPackageName("test2").setVersionCode(2).build();
// validate assumptions about the metadata
assertFalse(ATOMIC_FORMULA_1.isSatisfied(appInstallMetadata));
assertFalse(ATOMIC_FORMULA_2.isSatisfied(appInstallMetadata));
- assertFalse(openFormula.isSatisfied(appInstallMetadata));
+ assertFalse(compoundFormula.isSatisfied(appInstallMetadata));
}
@Test
public void testIsSatisfiable_trueOrTrue_true() {
- OpenFormula openFormula =
- new OpenFormula(OpenFormula.OR, Arrays.asList(ATOMIC_FORMULA_1, ATOMIC_FORMULA_2));
+ CompoundFormula compoundFormula =
+ new CompoundFormula(
+ CompoundFormula.OR, Arrays.asList(ATOMIC_FORMULA_1, ATOMIC_FORMULA_2));
AppInstallMetadata appInstallMetadata =
getAppInstallMetadataBuilder().setPackageName("test1").setVersionCode(1).build();
// validate assumptions about the metadata
assertTrue(ATOMIC_FORMULA_1.isSatisfied(appInstallMetadata));
assertTrue(ATOMIC_FORMULA_2.isSatisfied(appInstallMetadata));
- assertTrue(openFormula.isSatisfied(appInstallMetadata));
+ assertTrue(compoundFormula.isSatisfied(appInstallMetadata));
}
@Test
public void testIsSatisfiable_trueOrFalse_true() {
- OpenFormula openFormula =
- new OpenFormula(OpenFormula.OR, Arrays.asList(ATOMIC_FORMULA_1, ATOMIC_FORMULA_2));
+ CompoundFormula compoundFormula =
+ new CompoundFormula(
+ CompoundFormula.OR, Arrays.asList(ATOMIC_FORMULA_1, ATOMIC_FORMULA_2));
AppInstallMetadata appInstallMetadata =
getAppInstallMetadataBuilder().setPackageName("test1").setVersionCode(2).build();
// validate assumptions about the metadata
assertTrue(ATOMIC_FORMULA_1.isSatisfied(appInstallMetadata));
assertFalse(ATOMIC_FORMULA_2.isSatisfied(appInstallMetadata));
- assertTrue(openFormula.isSatisfied(appInstallMetadata));
+ assertTrue(compoundFormula.isSatisfied(appInstallMetadata));
}
@Test
public void testIsSatisfiable_falseOrTrue_true() {
- OpenFormula openFormula =
- new OpenFormula(OpenFormula.OR, Arrays.asList(ATOMIC_FORMULA_1, ATOMIC_FORMULA_2));
+ CompoundFormula compoundFormula =
+ new CompoundFormula(
+ CompoundFormula.OR, Arrays.asList(ATOMIC_FORMULA_1, ATOMIC_FORMULA_2));
AppInstallMetadata appInstallMetadata =
getAppInstallMetadataBuilder().setPackageName("test2").setVersionCode(1).build();
// validate assumptions about the metadata
assertFalse(ATOMIC_FORMULA_1.isSatisfied(appInstallMetadata));
assertTrue(ATOMIC_FORMULA_2.isSatisfied(appInstallMetadata));
- assertTrue(openFormula.isSatisfied(appInstallMetadata));
+ assertTrue(compoundFormula.isSatisfied(appInstallMetadata));
}
@Test
public void testIsSatisfiable_falseOrFalse_false() {
- OpenFormula openFormula =
- new OpenFormula(OpenFormula.OR, Arrays.asList(ATOMIC_FORMULA_1, ATOMIC_FORMULA_2));
+ CompoundFormula compoundFormula =
+ new CompoundFormula(
+ CompoundFormula.OR, Arrays.asList(ATOMIC_FORMULA_1, ATOMIC_FORMULA_2));
AppInstallMetadata appInstallMetadata =
getAppInstallMetadataBuilder().setPackageName("test2").setVersionCode(2).build();
// validate assumptions about the metadata
assertFalse(ATOMIC_FORMULA_1.isSatisfied(appInstallMetadata));
assertFalse(ATOMIC_FORMULA_2.isSatisfied(appInstallMetadata));
- assertFalse(openFormula.isSatisfied(appInstallMetadata));
+ assertFalse(compoundFormula.isSatisfied(appInstallMetadata));
}
@Test
public void testParcelUnparcel() {
- OpenFormula formula =
- new OpenFormula(OpenFormula.AND, Arrays.asList(ATOMIC_FORMULA_2, ATOMIC_FORMULA_1));
+ CompoundFormula formula =
+ new CompoundFormula(
+ CompoundFormula.AND, Arrays.asList(ATOMIC_FORMULA_2, ATOMIC_FORMULA_1));
Parcel p = Parcel.obtain();
formula.writeToParcel(p, 0);
p.setDataPosition(0);
- OpenFormula newFormula = OpenFormula.CREATOR.createFromParcel(p);
+ CompoundFormula newFormula = CompoundFormula.CREATOR.createFromParcel(p);
assertEquals(formula, newFormula);
}
@Test
- public void testInvalidOpenFormula_invalidConnector() {
+ public void testInvalidCompoundFormula_invalidConnector() {
assertExpectException(
IllegalArgumentException.class,
/* expectedExceptionMessageRegex */ "Unknown connector: -1",
- () -> new OpenFormula(/* connector= */ -1,
- Arrays.asList(ATOMIC_FORMULA_1, ATOMIC_FORMULA_2)));
+ () ->
+ new CompoundFormula(
+ /* connector= */ -1,
+ Arrays.asList(ATOMIC_FORMULA_1, ATOMIC_FORMULA_2)));
}
/** Returns a builder with all fields filled with some dummy data. */
diff --git a/services/tests/servicestests/src/com/android/server/integrity/model/RuleTest.java b/core/tests/coretests/src/android/content/integrity/RuleTest.java
index cad392826d42..19e74e6b93cc 100644
--- a/services/tests/servicestests/src/com/android/server/integrity/model/RuleTest.java
+++ b/core/tests/coretests/src/android/content/integrity/RuleTest.java
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-package com.android.server.integrity.model;
+package android.content.integrity;
-import static com.android.server.testutils.TestUtils.assertExpectException;
+import static android.content.integrity.TestUtils.assertExpectException;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
@@ -60,11 +60,11 @@ public class RuleTest {
@Test
public void testToString() {
- OpenFormula openFormula =
- new OpenFormula(
- OpenFormula.AND,
+ CompoundFormula compoundFormula =
+ new CompoundFormula(
+ CompoundFormula.AND,
Arrays.asList(PACKAGE_NAME_ATOMIC_FORMULA, APP_CERTIFICATE_ATOMIC_FORMULA));
- Rule rule = new Rule(openFormula, Rule.DENY);
+ Rule rule = new Rule(compoundFormula, Rule.DENY);
assertEquals(
String.format(
@@ -93,12 +93,12 @@ public class RuleTest {
public void testParcelUnparcel() {
Rule rule =
new Rule(
- new OpenFormula(
- OpenFormula.AND,
+ new CompoundFormula(
+ CompoundFormula.AND,
Arrays.asList(
APP_CERTIFICATE_ATOMIC_FORMULA,
- new OpenFormula(
- OpenFormula.NOT,
+ new CompoundFormula(
+ CompoundFormula.NOT,
Arrays.asList(PACKAGE_NAME_ATOMIC_FORMULA)))),
Rule.DENY);
Parcel p = Parcel.obtain();
diff --git a/core/tests/coretests/src/android/content/integrity/TEST_MAPPING b/core/tests/coretests/src/android/content/integrity/TEST_MAPPING
new file mode 100644
index 000000000000..2920716f5d5d
--- /dev/null
+++ b/core/tests/coretests/src/android/content/integrity/TEST_MAPPING
@@ -0,0 +1,12 @@
+{
+ "presubmit": [
+ {
+ "name": "FrameworksCoreTests",
+ "options": [
+ {
+ "include-filter": "android.content.integrity."
+ }
+ ]
+ }
+ ]
+}
diff --git a/core/tests/coretests/src/android/content/integrity/TestUtils.java b/core/tests/coretests/src/android/content/integrity/TestUtils.java
new file mode 100644
index 000000000000..af984cf318f5
--- /dev/null
+++ b/core/tests/coretests/src/android/content/integrity/TestUtils.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.content.integrity;
+
+import android.test.MoreAsserts;
+
+import junit.framework.Assert;
+
+/** Helper methods used in tests. */
+class TestUtils {
+ private TestUtils() {}
+
+ public interface ExceptionRunnable {
+ void run() throws Exception;
+ }
+
+ public static void assertExpectException(
+ Class<? extends Throwable> expectedExceptionType,
+ String expectedExceptionMessageRegex,
+ ExceptionRunnable r) {
+ try {
+ r.run();
+ } catch (Throwable e) {
+ Assert.assertTrue(
+ "Expected exception type was "
+ + expectedExceptionType.getName()
+ + " but caught "
+ + e.getClass().getName(),
+ expectedExceptionType.isAssignableFrom(e.getClass()));
+ if (expectedExceptionMessageRegex != null) {
+ MoreAsserts.assertContainsRegex(expectedExceptionMessageRegex, e.getMessage());
+ }
+ return; // Pass.
+ }
+ Assert.fail(
+ "Expected exception type " + expectedExceptionType.getName() + " was not thrown");
+ }
+}
diff --git a/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java b/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java
index 17fe61d879f3..deb0f182156e 100644
--- a/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java
@@ -548,8 +548,10 @@ public class TextClassifierTest {
}
@Test
- public void testSuggetsConversationActions_deduplicate() {
- if (isTextClassifierDisabled()) return;
+ public void testSuggestConversationActions_deduplicate() {
+ Context context = new FakeContextBuilder()
+ .setIntentComponent(Intent.ACTION_SENDTO, FakeContextBuilder.DEFAULT_COMPONENT)
+ .build();
ConversationActions.Message message =
new ConversationActions.Message.Builder(
ConversationActions.Message.PERSON_USER_OTHERS)
@@ -560,7 +562,8 @@ public class TextClassifierTest {
.setMaxSuggestions(3)
.build();
- ConversationActions conversationActions = mClassifier.suggestConversationActions(request);
+ TextClassifier classifier = new TextClassifierImpl(context, TC_CONSTANTS);
+ ConversationActions conversationActions = classifier.suggestConversationActions(request);
Truth.assertThat(conversationActions.getConversationActions()).isEmpty();
}
diff --git a/data/etc/preinstalled-packages-platform.xml b/data/etc/preinstalled-packages-platform.xml
index ccd8b5bb5347..10fc59d2a999 100644
--- a/data/etc/preinstalled-packages-platform.xml
+++ b/data/etc/preinstalled-packages-platform.xml
@@ -16,19 +16,30 @@
<!--
This XML file declares which system packages should be initially installed for new users based on
-the type of user. All system packages on the device should ideally have an entry in an xml file
+their user type. All system packages on the device should ideally have an entry in an xml file
(keys by its manifest name).
-Main user-types (every user will be at least one of these types) are:
+Base user-types (every user will be at least one of these types) are:
SYSTEM (user 0)
FULL (any non-profile human user)
PROFILE (profile human user)
-
-Additional optional types are: GUEST, RESTRICTED, MANAGED_PROFILE, EPHEMERAL, DEMO
-
-The meaning of each of these user types is delineated by flags in
+the precise meaning of which is defined in
frameworks/base/core/java/android/content/pm/UserInfo.java.
-See frameworks/base/services/core/java/com/android/server/pm/UserSystemPackageInstaller#getFlagsFromUserTypes
+TODO(b/143784345): When UserInfo flags are categorized, reference the "base type" category here.
+
+More granular control is also available by specifying individual user types (every user is exactly
+one of these user types).
+This includes AOSP user types defined in frameworks/base/core/java/android/os/UserManager.java, like
+ android.os.usertype.full.SYSTEM
+ android.os.usertype.full.SECONDARY
+ android.os.usertype.full.GUEST
+ android.os.usertype.full.DEMO
+ android.os.usertype.full.RESTRICTED
+ android.os.usertype.profile.MANAGED
+ android.os.usertype.system.HEADLESS
+as well as any OEM custom user types defined using
+frameworks/base/services/core/java/com/android/server/pm/UserTypeFactory.java.
+Any specified user types must be valid user types on the device (i.e. created in UserTypeFactory).
The following three examples should cover most normal cases:
@@ -63,16 +74,24 @@ Some system packages truly are required to be on all users, regardless of type,
<install-in user-type="PROFILE">
</install-in-user-type>
-More fine-grained options are also available (see below). Additionally, packages can blacklist
-user types. Blacklists override any whitelisting (in any file).
+More fine-grained options are also available by specifying individual user types.
+E.g.
+ <install-in-user-type package="com.android.example">
+ <install-in user-type="android.os.usertype.profile.MANAGED">
+ <install-in user-type="android.os.usertype.full.GUEST">
+ <install-in user-type="SYSTEM">
+ </install-in-user-type>
+which installs this package on any user whose user type is a managed profile or a guest, or is of
+a SYSTEM base type.
+
+Additionally, packages can blacklist user types. Blacklists override any whitelisting (in any file).
E.g.
<install-in-user-type package="com.android.example">
<install-in user-type="FULL" />
- <do-not-install-in user-type="GUEST" />
+ <do-not-install-in user-type="android.os.usertype.full.GUEST" />
</install-in-user-type>
-
-If a user is of type FULL and GUEST, this package will NOT be installed, because the
-'do-not-install-in' takes precedence over 'install-in'.
+If a user is of type android.os.usertype.full.GUEST (which itself is a subtype of FULL), this
+package will NOT be installed, because the 'do-not-install-in' takes precedence over 'install-in'.
The way that a device treats system packages that do not have any entry (for any user type) at all
is determined by the config resource value config_userTypePackageWhitelistMode.
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index fe539e4ca22b..f2a6452d6e44 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -367,22 +367,4 @@ applications that come with the platform
<permission name="android.permission.REBOOT"/>
<permission name="android.permission.MANAGE_DYNAMIC_SYSTEM"/>
</privapp-permissions>
-
- <privapp-permissions package="com.android.wifi">
- <permission name="android.permission.CHANGE_CONFIGURATION"/>
- <permission name="android.permission.CONNECTIVITY_INTERNAL"/>
- <permission name="android.permission.DUMP"/>
- <permission name="android.permission.INTERACT_ACROSS_USERS_FULL"/>
- <permission name="android.permission.INTERNAL_SYSTEM_WINDOW"/>
- <permission name="android.permission.LOCAL_MAC_ADDRESS"/>
- <permission name="android.permission.MANAGE_USERS"/>
- <permission name="android.permission.PACKAGE_USAGE_STATS"/>
- <permission name="android.permission.READ_DEVICE_CONFIG"/>
- <permission name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
- <permission name="android.permission.REQUEST_NETWORK_SCORES"/>
- <permission name="android.permission.WRITE_SECURE_SETTINGS"/>
- <permission name="android.permission.UPDATE_DEVICE_STATS"/>
- <permission name="android.permission.UPDATE_APP_OPS_STATS"/>
- <permission name="android.permission.LOCATION_HARDWARE"/>
- </privapp-permissions>
</permissions>
diff --git a/libs/hwui/tests/unit/VectorDrawableTests.cpp b/libs/hwui/tests/unit/VectorDrawableTests.cpp
index 60fd7a753f2d..6d4c57413f00 100644
--- a/libs/hwui/tests/unit/VectorDrawableTests.cpp
+++ b/libs/hwui/tests/unit/VectorDrawableTests.cpp
@@ -85,9 +85,9 @@ const static TestData sTestDataSet[] = {
outPath->rCubicTo(8.0, 8.0, 8.0, 8.0, 8.0, 8.0);
outPath->cubicTo(16.0, 16.0, 9.0, 9.0, 9.0, 9.0);
outPath->rCubicTo(0.0, 0.0, 9.0, 9.0, 9.0, 9.0);
- outPath->arcTo(10.0, 10.0, 0.0, SkPath::kLarge_ArcSize, SkPath::kCW_Direction, 10.0,
+ outPath->arcTo(10.0, 10.0, 0.0, SkPath::kLarge_ArcSize, SkPathDirection::kCW, 10.0,
10.0);
- outPath->arcTo(10.0, 10.0, 0.0, SkPath::kLarge_ArcSize, SkPath::kCW_Direction, 20.0,
+ outPath->arcTo(10.0, 10.0, 0.0, SkPath::kLarge_ArcSize, SkPathDirection::kCW, 20.0,
20.0);
}},
@@ -159,7 +159,7 @@ const static TestData sTestDataSet[] = {
},
[](SkPath* outPath) {
outPath->moveTo(300.0, 70.0);
- outPath->arcTo(230.0, 230.0, 0.0, SkPath::kLarge_ArcSize, SkPath::kCCW_Direction,
+ outPath->arcTo(230.0, 230.0, 0.0, SkPath::kLarge_ArcSize, SkPathDirection::kCCW,
301.0, 70.0);
outPath->close();
outPath->moveTo(300.0, 70.0);
diff --git a/libs/hwui/utils/VectorDrawableUtils.cpp b/libs/hwui/utils/VectorDrawableUtils.cpp
index 6b8f3154dd36..bd963df6750e 100644
--- a/libs/hwui/utils/VectorDrawableUtils.cpp
+++ b/libs/hwui/utils/VectorDrawableUtils.cpp
@@ -300,7 +300,7 @@ void PathResolver::addCommand(SkPath* outPath, char previousCmd, char cmd,
// (rx ry x-axis-rotation large-arc-flag sweep-flag x y)
outPath->arcTo(points->at(k + 0), points->at(k + 1), points->at(k + 2),
(SkPath::ArcSize) (points->at(k + 3) != 0),
- (SkPath::Direction) (points->at(k + 4) == 0),
+ (SkPathDirection) (points->at(k + 4) == 0),
points->at(k + 5) + currentX, points->at(k + 6) + currentY);
currentX += points->at(k + 5);
currentY += points->at(k + 6);
@@ -310,7 +310,7 @@ void PathResolver::addCommand(SkPath* outPath, char previousCmd, char cmd,
case 'A': // Draws an elliptical arc
outPath->arcTo(points->at(k + 0), points->at(k + 1), points->at(k + 2),
(SkPath::ArcSize) (points->at(k + 3) != 0),
- (SkPath::Direction) (points->at(k + 4) == 0),
+ (SkPathDirection) (points->at(k + 4) == 0),
points->at(k + 5), points->at(k + 6));
currentX = points->at(k + 5);
currentY = points->at(k + 6);
diff --git a/location/TEST_MAPPING b/location/TEST_MAPPING
index 2f386271dcb7..a9dbda458e3a 100644
--- a/location/TEST_MAPPING
+++ b/location/TEST_MAPPING
@@ -1,10 +1,13 @@
{
"presubmit": [
{
+ "name": "CtsLocationFineTestCases"
+ },
+ {
"name": "CtsLocationCoarseTestCases"
},
{
"name": "CtsLocationNoneTestCases"
}
]
-}
+} \ No newline at end of file
diff --git a/location/java/android/location/GnssStatus.java b/location/java/android/location/GnssStatus.java
index 2f1eeda9c4cf..89a3bc070578 100644
--- a/location/java/android/location/GnssStatus.java
+++ b/location/java/android/location/GnssStatus.java
@@ -34,7 +34,7 @@ import java.util.ArrayList;
*/
public final class GnssStatus {
- // these must match the definitions in gps.h
+ // These must match the definitions in GNSS HAL.
//
// Note: these constants are also duplicated in GnssStatusCompat.java in the androidx support
// library. if adding a constellation, please update that file as well.
@@ -63,9 +63,10 @@ public final class GnssStatus {
private static final int SVID_FLAGS_HAS_ALMANAC_DATA = (1 << 1);
private static final int SVID_FLAGS_USED_IN_FIX = (1 << 2);
private static final int SVID_FLAGS_HAS_CARRIER_FREQUENCY = (1 << 3);
+ private static final int SVID_FLAGS_HAS_BASEBAND_CN0 = (1 << 4);
- private static final int SVID_SHIFT_WIDTH = 8;
- private static final int CONSTELLATION_TYPE_SHIFT_WIDTH = 4;
+ private static final int SVID_SHIFT_WIDTH = 12;
+ private static final int CONSTELLATION_TYPE_SHIFT_WIDTH = 8;
private static final int CONSTELLATION_TYPE_MASK = 0xf;
/**
@@ -123,9 +124,10 @@ public final class GnssStatus {
*/
@NonNull
public static GnssStatus wrap(int svCount, int[] svidWithFlags, float[] cn0DbHzs,
- float[] elevations, float[] azimuths, float[] carrierFrequencies) {
+ float[] elevations, float[] azimuths, float[] carrierFrequencies,
+ float[] basebandCn0DbHzs) {
return new GnssStatus(svCount, svidWithFlags, cn0DbHzs, elevations, azimuths,
- carrierFrequencies);
+ carrierFrequencies, basebandCn0DbHzs);
}
private final int mSvCount;
@@ -134,15 +136,17 @@ public final class GnssStatus {
private final float[] mElevations;
private final float[] mAzimuths;
private final float[] mCarrierFrequencies;
+ private final float[] mBasebandCn0DbHzs;
private GnssStatus(int svCount, int[] svidWithFlags, float[] cn0DbHzs, float[] elevations,
- float[] azimuths, float[] carrierFrequencies) {
+ float[] azimuths, float[] carrierFrequencies, float[] basebandCn0DbHzs) {
mSvCount = svCount;
mSvidWithFlags = svidWithFlags;
mCn0DbHzs = cn0DbHzs;
mElevations = elevations;
mAzimuths = azimuths;
mCarrierFrequencies = carrierFrequencies;
+ mBasebandCn0DbHzs = basebandCn0DbHzs;
}
/**
@@ -284,6 +288,26 @@ public final class GnssStatus {
}
/**
+ * Reports whether a valid {@link #getBasebandCn0DbHz(int satelliteIndex)} is available.
+ *
+ * @param satelliteIndex An index from zero to {@link #getSatelliteCount()} - 1
+ */
+ public boolean hasBasebandCn0DbHz(@IntRange(from = 0) int satelliteIndex) {
+ return (mSvidWithFlags[satelliteIndex] & SVID_FLAGS_HAS_BASEBAND_CN0) != 0;
+ }
+
+ /**
+ * Retrieves the baseband carrier-to-noise density of the satellite at the specified index in
+ * dB-Hz.
+ *
+ * @param satelliteIndex An index from zero to {@link #getSatelliteCount()} - 1
+ */
+ @FloatRange(from = 0, to = 63)
+ public float getBasebandCn0DbHz(@IntRange(from = 0) int satelliteIndex) {
+ return mBasebandCn0DbHzs[satelliteIndex];
+ }
+
+ /**
* Returns the string representation of a constellation type.
*
* @param constellationType the constellation type.
@@ -334,6 +358,8 @@ public final class GnssStatus {
* @param usedInFix whether the satellite was used in the most recent location fix
* @param hasCarrierFrequency whether carrier frequency data is available
* @param carrierFrequency satellite carrier frequency in Hz
+ * @param hasBasebandCn0DbHz whether baseband carrier-to-noise density is available
+ * @param basebandCn0DbHz baseband carrier-to-noise density in dB-Hz
*/
@NonNull
public Builder addSatellite(@ConstellationType int constellationType,
@@ -345,9 +371,12 @@ public final class GnssStatus {
boolean hasAlmanac,
boolean usedInFix,
boolean hasCarrierFrequency,
- @FloatRange(from = 0) float carrierFrequency) {
+ @FloatRange(from = 0) float carrierFrequency,
+ boolean hasBasebandCn0DbHz,
+ @FloatRange(from = 0, to = 63) float basebandCn0DbHz) {
mSatellites.add(new GnssSvInfo(constellationType, svid, cn0DbHz, elevation, azimuth,
- hasEphemeris, hasAlmanac, usedInFix, hasCarrierFrequency, carrierFrequency));
+ hasEphemeris, hasAlmanac, usedInFix, hasCarrierFrequency, carrierFrequency,
+ hasBasebandCn0DbHz, basebandCn0DbHz));
return this;
}
@@ -371,6 +400,7 @@ public final class GnssStatus {
float[] elevations = new float[svCount];
float[] azimuths = new float[svCount];
float[] carrierFrequencies = new float[svCount];
+ float[] basebandCn0DbHzs = new float[svCount];
for (int i = 0; i < svidWithFlags.length; i++) {
svidWithFlags[i] = mSatellites.get(i).mSvidWithFlags;
@@ -387,9 +417,12 @@ public final class GnssStatus {
for (int i = 0; i < carrierFrequencies.length; i++) {
carrierFrequencies[i] = mSatellites.get(i).mCarrierFrequency;
}
+ for (int i = 0; i < basebandCn0DbHzs.length; i++) {
+ basebandCn0DbHzs[i] = mSatellites.get(i).mBasebandCn0DbHz;
+ }
return wrap(svCount, svidWithFlags, cn0DbHzs, elevations, azimuths,
- carrierFrequencies);
+ carrierFrequencies, basebandCn0DbHzs);
}
}
@@ -400,21 +433,25 @@ public final class GnssStatus {
private final float mElevation;
private final float mAzimuth;
private final float mCarrierFrequency;
+ private final float mBasebandCn0DbHz;
private GnssSvInfo(int constellationType, int svid, float cn0DbHz,
float elevation, float azimuth, boolean hasEphemeris, boolean hasAlmanac,
- boolean usedInFix, boolean hasCarrierFrequency, float carrierFrequency) {
+ boolean usedInFix, boolean hasCarrierFrequency, float carrierFrequency,
+ boolean hasBasebandCn0DbHz, float basebandCn0DbHz) {
mSvidWithFlags = (svid << SVID_SHIFT_WIDTH)
| ((constellationType & CONSTELLATION_TYPE_MASK)
<< CONSTELLATION_TYPE_SHIFT_WIDTH)
| (hasEphemeris ? SVID_FLAGS_HAS_EPHEMERIS_DATA : SVID_FLAGS_NONE)
| (hasAlmanac ? SVID_FLAGS_HAS_ALMANAC_DATA : SVID_FLAGS_NONE)
| (usedInFix ? SVID_FLAGS_USED_IN_FIX : SVID_FLAGS_NONE)
- | (hasCarrierFrequency ? SVID_FLAGS_HAS_CARRIER_FREQUENCY : SVID_FLAGS_NONE);
+ | (hasCarrierFrequency ? SVID_FLAGS_HAS_CARRIER_FREQUENCY : SVID_FLAGS_NONE)
+ | (hasBasebandCn0DbHz ? SVID_FLAGS_HAS_BASEBAND_CN0 : SVID_FLAGS_NONE);
mCn0DbHz = cn0DbHz;
mElevation = elevation;
mAzimuth = azimuth;
mCarrierFrequency = carrierFrequency;
+ mBasebandCn0DbHz = basebandCn0DbHz;
}
}
}
diff --git a/location/java/android/location/IGnssStatusListener.aidl b/location/java/android/location/IGnssStatusListener.aidl
index d824cb18765a..1931a005d66f 100644
--- a/location/java/android/location/IGnssStatusListener.aidl
+++ b/location/java/android/location/IGnssStatusListener.aidl
@@ -28,6 +28,6 @@ oneway interface IGnssStatusListener
void onFirstFix(int ttff);
void onSvStatusChanged(int svCount, in int[] svidWithFlags, in float[] cn0s,
in float[] elevations, in float[] azimuths,
- in float[] carrierFreqs);
+ in float[] carrierFreqs, in float[] basebandCn0s);
void onNmeaReceived(long timestamp, String nmea);
}
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index 75e1cd45689c..c0041722c475 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -2818,9 +2818,10 @@ public class LocationManager {
@Override
public void onSvStatusChanged(int svCount, int[] svidWithFlags, float[] cn0s,
- float[] elevations, float[] azimuths, float[] carrierFreqs) {
+ float[] elevations, float[] azimuths, float[] carrierFreqs,
+ float[] basebandCn0s) {
GnssStatus localStatus = GnssStatus.wrap(svCount, svidWithFlags, cn0s,
- elevations, azimuths, carrierFreqs);
+ elevations, azimuths, carrierFreqs, basebandCn0s);
mGnssStatus = localStatus;
execute((callback) -> callback.onSatelliteStatusChanged(localStatus));
}
diff --git a/location/tests/locationtests/src/android/location/GnssStatusTest.java b/location/tests/locationtests/src/android/location/GnssStatusTest.java
deleted file mode 100644
index 79ea0d61b799..000000000000
--- a/location/tests/locationtests/src/android/location/GnssStatusTest.java
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package android.location;
-
-import android.test.suitebuilder.annotation.SmallTest;
-import android.util.Log;
-import java.lang.reflect.Constructor;
-import java.util.ArrayList;
-import java.util.List;
-import junit.framework.TestCase;
-
-/**
- * Unit tests for {@link GnssStatus}.
- */
-@SmallTest
-public class GnssStatusTest extends TestCase {
-
- private static final String TAG = GnssStatusTest.class.getSimpleName();
- public void setUp() throws Exception {
- super.setUp();
- }
-
- /*
- * Create {@link GnssStatus} with default value, verify whether its fields are set correctly.
- *
- */
- public void testEmptyGnssStatus() throws Exception {
- Log.i(TAG, "testEmptyGnssStatus");
- List<SatelliteInfo> svInfos = new ArrayList<>();
- GnssStatus gnssStatus = createGnssStatus(svInfos);
- verifyGnssStatus(svInfos, gnssStatus);
- }
-
- /*
- * Create {@link GnssStatus} with only one satellite info, verify whether its fields are set
- * correctly.
- */
- public void testOneSatelliteGnssStatus() throws Exception {
- Log.i(TAG, "testOneSatelliteGnssStatus");
- List<SatelliteInfo> svInfos = new ArrayList<>();
- SatelliteInfo svInfo =
- new SatelliteInfo(100,1, true, true, true, true, 100f, 20.3f, 45.5f, 100.23f);
- svInfos.add(svInfo);
- GnssStatus gnssStatus = createGnssStatus(svInfos);
- verifyGnssStatus(svInfos, gnssStatus);
- }
-
- /*
- * Create {@link GnssStatus} with multiple satellite info, verify whether its fields are set
- * correctly.
- */
- public void testMultipleSatellitesGnssStatus() throws Exception {
- Log.i(TAG, "testMultipleSatellitesGnssStatus");
- List<SatelliteInfo> svInfos = new ArrayList<>();
- SatelliteInfo svInfo1 =
- new SatelliteInfo(20, 1,true, true, true, true, 10.1f, 20.3f, 45.5f, 111.23f);
- SatelliteInfo svInfo2 =
- new SatelliteInfo(50, 2, true, false, true, false, 20.2f, 21.3f, 46.5f, 222.23f);
- SatelliteInfo svInfo3 =
- new SatelliteInfo(192, 3, false, true, false, true, 30.3f, 22.3f, 47.5f, 333.23f);
- SatelliteInfo svInfo4 =
- new SatelliteInfo(250, 4, false, false, false, false, 40.4f, 23.3f, 48.5f, 444.23f);
- svInfos.add(svInfo1);
- svInfos.add(svInfo2);
- svInfos.add(svInfo3);
- svInfos.add(svInfo4);
- GnssStatus gnssStatus = createGnssStatus(svInfos);
- verifyGnssStatus(svInfos, gnssStatus);
- }
-
- private void verifyGnssStatus(List<SatelliteInfo> svInfos, GnssStatus gnssStatus) {
- Log.i(TAG, String.format("Verifing {0} satellites info.",svInfos.size()));
- assertEquals(TAG + "::SatelliteCount", svInfos.size(),
- gnssStatus.getSatelliteCount());
- for (int i = 0; i< svInfos.size(); i++) {
- SatelliteInfo svInfo = svInfos.get(i);
- assertEquals(TAG + "::Svid", svInfo.mSvid, gnssStatus.getSvid(i));
- assertEquals(TAG + "::ConstellationType", svInfo.mConstellationType,
- gnssStatus.getConstellationType(i));
- assertEquals(TAG + "::Cn0DbHz", svInfo.mCn0DbHz, gnssStatus.getCn0DbHz(i));
- assertEquals(TAG + "::Elevation", svInfo.mElevation,
- gnssStatus.getElevationDegrees(i));
- assertEquals(TAG + "::Azimuth", svInfo.mAzimuth, gnssStatus.getAzimuthDegrees(i));
- assertEquals(TAG + "::CarrierFrequencyHz", svInfo.mCarrierFrequency,
- gnssStatus.getCarrierFrequencyHz(i));
- assertEquals(TAG + "::hasEphemerisData", svInfo.mHasEphemris,
- gnssStatus.hasEphemerisData(i));
- assertEquals(TAG + "::HasAlmanacData", svInfo.mHasAlmanac,
- gnssStatus.hasAlmanacData(i));
- assertEquals(TAG + "::UsedInFix", svInfo.mUsedInFix, gnssStatus.usedInFix(i));
- assertEquals(TAG + "::HasCarrierFrequencyHz", svInfo.mHasCarriesFrequency,
- gnssStatus.hasCarrierFrequencyHz(i));
- }
- }
-
- private static GnssStatus createGnssStatus(List<SatelliteInfo> svInfos) throws Exception {
- Class<?> intClass = Integer.TYPE;
- Class<?> floatArrayClass = Class.forName("[F");
- Class<?> intArrayClass = Class.forName("[I");
- Class[] cArg = new Class[6];
- cArg[0] = intClass;
- cArg[1] = intArrayClass;
- cArg[2] = floatArrayClass;
- cArg[3] = floatArrayClass;
- cArg[4] = floatArrayClass;
- cArg[5] = floatArrayClass;
- Constructor<GnssStatus> ctor = GnssStatus.class.getDeclaredConstructor(cArg);
- ctor.setAccessible(true);
- return ctor.newInstance(svInfos.size(),
- SatelliteInfo.getSvidWithFlagsArray(svInfos),
- SatelliteInfo.getCn0sArray(svInfos),
- SatelliteInfo.getElevationsArray(svInfos),
- SatelliteInfo.getAzimuthsArray(svInfos),
- SatelliteInfo.getCarrierFrequencyArray(svInfos));
- }
-}
diff --git a/location/tests/locationtests/src/android/location/SatelliteInfo.java b/location/tests/locationtests/src/android/location/SatelliteInfo.java
deleted file mode 100644
index b6453ef0eabc..000000000000
--- a/location/tests/locationtests/src/android/location/SatelliteInfo.java
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package android.location;
-
-import java.util.List;
-
-/*
- * Helper class to store single Satellite info, only used it in the unit test.
- */
-public class SatelliteInfo {
- private static final int SVID_MAX_BIT_INDEX = 32;
- private static final int SVID_SHIFT_WIDTH = 8;
- private static final int CONSTELLATION_TYPE_SHIFT_WIDTH = 4;
-
- // Index for the bits in mSvidWithFlag
- private static final int GNSS_SV_FLAGS_HAS_EPHEMERIS_DATA_BIT_INDEX = 0;
- private static final int GNSS_SV_FLAGS_HAS_ALMANAC_DATA_BIT_INDEX = 1;
- private static final int GNSS_SV_FLAGS_USED_IN_FIX_BIT_INDEX = 2;
- private static final int GNSS_SV_FLAGS_HAS_CARRIER_FREQUENCY_BIT_INDEX = 3;
- public int mSvid;
- public int mSvidWithFlag;
- public float mCn0DbHz;
- public float mElevation;
- public float mAzimuth;
- public float mCarrierFrequency;
-
- /*
- * Flag fields, it stores the same information as svidWithFlag, but in different format, easy for
- * the unit test.
- */
- public int mConstellationType;
- public boolean mHasEphemris;
- public boolean mHasAlmanac;
- public boolean mUsedInFix;
- public boolean mHasCarriesFrequency;
-
- public SatelliteInfo(int svid, int constellationType, boolean hasEphemris, boolean hasAlmanac,
- boolean usedInFix, boolean hasCarriesFrequency, float cn0, float elevation, float azimuth,
- float carrierFrequency) {
- mSvidWithFlag =
- setRange(mSvidWithFlag, constellationType, CONSTELLATION_TYPE_SHIFT_WIDTH, SVID_SHIFT_WIDTH);
- mSvidWithFlag = setRange(mSvidWithFlag, svid, SVID_SHIFT_WIDTH, SVID_MAX_BIT_INDEX);
- mSvidWithFlag = setBit(mSvidWithFlag, hasEphemris, GNSS_SV_FLAGS_HAS_EPHEMERIS_DATA_BIT_INDEX);
- mSvidWithFlag = setBit(mSvidWithFlag, hasAlmanac, GNSS_SV_FLAGS_HAS_ALMANAC_DATA_BIT_INDEX);
- mSvidWithFlag = setBit(mSvidWithFlag, usedInFix, GNSS_SV_FLAGS_USED_IN_FIX_BIT_INDEX);
- mSvidWithFlag =
- setBit(mSvidWithFlag, hasCarriesFrequency, GNSS_SV_FLAGS_HAS_CARRIER_FREQUENCY_BIT_INDEX);
- this.mSvid = svid;
- this.mConstellationType = constellationType;
- this.mCn0DbHz = cn0;
- this.mElevation = elevation;
- this.mAzimuth = azimuth;
- this.mCarrierFrequency = carrierFrequency;
- this.mHasEphemris = hasEphemris;
- this.mHasAlmanac = hasAlmanac;
- this.mUsedInFix = usedInFix;
- this.mHasCarriesFrequency = hasCarriesFrequency;
- }
-
- /*
- * Gernerate svidWithFlags array from svInfos
- */
- public static int[] getSvidWithFlagsArray(List<SatelliteInfo> svInfos) {
- int[] svidWithFlags = new int[svInfos.size()];
- for (int i = 0; i< svInfos.size(); i++) {
- svidWithFlags[i] = svInfos.get(i).mSvidWithFlag;
- }
- return svidWithFlags;
- }
-
- /*
- * Gernerate cn0s array from svInfos
- */
- public static float[] getCn0sArray(List<SatelliteInfo> svInfos) {
- float[] cn0s = new float[svInfos.size()];
- for (int i = 0; i< svInfos.size(); i++) {
- cn0s[i] = svInfos.get(i).mCn0DbHz;
- }
- return cn0s;
- }
-
- /*
- * Gernerate elevations array from svInfos
- */
- public static float[] getElevationsArray(List<SatelliteInfo> svInfos) {
- float[] elevations = new float[svInfos.size()];
- for (int i = 0; i< svInfos.size(); i++) {
- elevations[i] = svInfos.get(i).mElevation;
- }
- return elevations;
- }
-
- /*
- * Gernerate azimuths array from svInfos
- */
- public static float[] getAzimuthsArray(List<SatelliteInfo> svInfos) {
- float[] azimuths = new float[svInfos.size()];
- for (int i = 0; i< svInfos.size(); i++) {
- azimuths[i] = svInfos.get(i).mAzimuth;
- }
- return azimuths;
- }
-
- /*
- * Gernerate carrierFrequency array from svInfos
- */
- public static float[] getCarrierFrequencyArray(List<SatelliteInfo> svInfos) {
- float[] carrierFrequencies = new float[svInfos.size()];
- for (int i = 0; i< svInfos.size(); i++) {
- carrierFrequencies[i] = svInfos.get(i).mCarrierFrequency;
- }
- return carrierFrequencies;
- }
-
- private int setBit(int targetValue, boolean value, int index) {
- if (value) {
- targetValue = targetValue | (1 << index);
- } else {
- targetValue = targetValue & ~(1 << index);
- }
- return targetValue;
- }
-
- /*
- * Set the bit in the range [fromIndex, toIndex), index start from the lowest bit.
- * value -> 1 1 0 1 1 0 1 0
- * index -> 7 6 5 4 3 2 1 0
- * This function will set the bit in the range to the lowest X bits of the value.
- */
- private int setRange(int targetValue, int value, int fromIndex, int toIndex) {
- int rangeLen = toIndex - fromIndex;
- int valueMask = (1 << rangeLen) -1;
- value &= valueMask;
- value = value << fromIndex;
- valueMask = valueMask << fromIndex;
- targetValue &= (~valueMask);
- targetValue |= value;
- return targetValue;
- }
-
-} \ No newline at end of file
diff --git a/media/java/android/media/IMediaRoute2ProviderClient.aidl b/media/java/android/media/IMediaRoute2ProviderClient.aidl
index 6f44d45c0a12..f4fb7f450fb8 100644
--- a/media/java/android/media/IMediaRoute2ProviderClient.aidl
+++ b/media/java/android/media/IMediaRoute2ProviderClient.aidl
@@ -17,10 +17,13 @@
package android.media;
import android.media.MediaRoute2ProviderInfo;
+import android.media.MediaRoute2Info;
+import android.os.Bundle;
/**
* @hide
*/
oneway interface IMediaRoute2ProviderClient {
void updateProviderInfo(in MediaRoute2ProviderInfo info);
+ void notifyRouteSelected(String packageName, String routeId, in Bundle controlHints, int seq);
}
diff --git a/media/java/android/media/MediaRoute2ProviderService.java b/media/java/android/media/MediaRoute2ProviderService.java
index 386d2dc54a88..1b6183e361c8 100644
--- a/media/java/android/media/MediaRoute2ProviderService.java
+++ b/media/java/android/media/MediaRoute2ProviderService.java
@@ -18,14 +18,19 @@ package android.media;
import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.Service;
import android.content.Intent;
+import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.RemoteException;
import android.util.Log;
+import java.util.Objects;
+
/**
* @hide
*/
@@ -44,7 +49,7 @@ public abstract class MediaRoute2ProviderService extends Service {
}
@Override
- public IBinder onBind(Intent intent) {
+ public IBinder onBind(@NonNull Intent intent) {
//TODO: Allow binding from media router service only?
if (SERVICE_INTERFACE.equals(intent.getAction())) {
if (mStub == null) {
@@ -57,11 +62,17 @@ public abstract class MediaRoute2ProviderService extends Service {
/**
* Called when selectRoute is called on a route of the provider.
+ * Once the route is ready to be used , call {@link #notifyRouteSelected(SelectToken, Bundle)}
+ * to notify that.
*
* @param packageName the package name of the application that selected the route
* @param routeId the id of the route being selected
+ * @param token token that contains select info
+ *
+ * @see #notifyRouteSelected
*/
- public abstract void onSelectRoute(String packageName, String routeId);
+ public abstract void onSelectRoute(@NonNull String packageName, @NonNull String routeId,
+ @NonNull SelectToken token);
/**
* Called when unselectRoute is called on a route of the provider.
@@ -69,7 +80,7 @@ public abstract class MediaRoute2ProviderService extends Service {
* @param packageName the package name of the application that has selected the route.
* @param routeId the id of the route being unselected
*/
- public abstract void onUnselectRoute(String packageName, String routeId);
+ public abstract void onUnselectRoute(@NonNull String packageName, @NonNull String routeId);
/**
* Called when sendControlRequest is called on a route of the provider
@@ -78,21 +89,21 @@ public abstract class MediaRoute2ProviderService extends Service {
* @param request the media control request intent
*/
//TODO: Discuss what to use for request (e.g., Intent? Request class?)
- public abstract void onControlRequest(String routeId, Intent request);
+ public abstract void onControlRequest(@NonNull String routeId, @NonNull Intent request);
/**
* Called when requestSetVolume is called on a route of the provider
* @param routeId the id of the route
* @param volume the target volume
*/
- public abstract void onSetVolume(String routeId, int volume);
+ public abstract void onSetVolume(@NonNull String routeId, int volume);
/**
* Called when requestUpdateVolume is called on a route of the provider
* @param routeId id of the route
* @param delta the delta to add to the current volume
*/
- public abstract void onUpdateVolume(String routeId, int delta);
+ public abstract void onUpdateVolume(@NonNull String routeId, int delta);
/**
* Updates provider info and publishes routes
@@ -102,6 +113,29 @@ public abstract class MediaRoute2ProviderService extends Service {
publishState();
}
+ /**
+ * Notifies the client of that the selected route is ready for use. If the selected route can be
+ * controlled, pass a {@link Bundle} that contains how to control it.
+ *
+ * @param token token passed in {@link #onSelectRoute}
+ * @param controlHints a {@link Bundle} that contains how to control the given route.
+ * Pass {@code null} if the route is not available.
+ */
+ public final void notifyRouteSelected(@NonNull SelectToken token,
+ @Nullable Bundle controlHints) {
+ Objects.requireNonNull(token, "token must not be null");
+
+ if (mClient == null) {
+ return;
+ }
+ try {
+ mClient.notifyRouteSelected(token.mPackageName, token.mRouteId,
+ controlHints, token.mSeq);
+ } catch (RemoteException ex) {
+ Log.w(TAG, "Failed to notify route selected");
+ }
+ }
+
void setClient(IMediaRoute2ProviderClient client) {
mClient = client;
publishState();
@@ -118,6 +152,23 @@ public abstract class MediaRoute2ProviderService extends Service {
}
}
+ /**
+ * Route selection information.
+ *
+ * @see #notifyRouteSelected
+ */
+ public final class SelectToken {
+ final String mPackageName;
+ final String mRouteId;
+ final int mSeq;
+
+ SelectToken(String packageName, String routeId, int seq) {
+ mPackageName = packageName;
+ mRouteId = routeId;
+ mSeq = seq;
+ }
+ }
+
final class ProviderStub extends IMediaRoute2Provider.Stub {
ProviderStub() { }
@@ -129,10 +180,10 @@ public abstract class MediaRoute2ProviderService extends Service {
@Override
public void requestSelectRoute(String packageName, String id, int seq) {
- // TODO: When introducing MediaRoute2ProviderService#sendConnectionHints(),
- // use the sequence number here properly.
mHandler.sendMessage(obtainMessage(MediaRoute2ProviderService::onSelectRoute,
- MediaRoute2ProviderService.this, packageName, id));
+ MediaRoute2ProviderService.this, packageName, id,
+ new SelectToken(packageName, id, seq)));
+
}
@Override
diff --git a/media/java/android/media/MediaRouter.java b/media/java/android/media/MediaRouter.java
index 9cb78696f19b..7b15d9554534 100644
--- a/media/java/android/media/MediaRouter.java
+++ b/media/java/android/media/MediaRouter.java
@@ -1318,6 +1318,7 @@ public class MediaRouter {
sStatic.rebindAsUser(userId);
}
+ //TODO: remove this and Client1Record in MediaRouter2ServiceImpl.
/**
* Sets the control categories of the application.
* Routes that support at least one of the given control categories only exists and are handled
diff --git a/media/java/android/media/MediaRouter2.java b/media/java/android/media/MediaRouter2.java
index 94ac77af3ac3..35cb066f9790 100644
--- a/media/java/android/media/MediaRouter2.java
+++ b/media/java/android/media/MediaRouter2.java
@@ -57,7 +57,8 @@ public class MediaRouter2 {
@IntDef(value = {
SELECT_REASON_UNKNOWN,
SELECT_REASON_USER_SELECTED,
- SELECT_REASON_FALLBACK})
+ SELECT_REASON_FALLBACK,
+ SELECT_REASON_SYSTEM_SELECTED})
public @interface SelectReason {}
/**
@@ -80,6 +81,13 @@ public class MediaRouter2 {
*/
public static final int SELECT_REASON_FALLBACK = 2;
+ /**
+ * This is passed from {@link com.android.server.media.MediaRouterService} when the route
+ * is selected in response to a request from other apps (e.g. System UI).
+ * @hide
+ */
+ public static final int SELECT_REASON_SYSTEM_SELECTED = 3;
+
private static final String TAG = "MR2";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
private static final Object sLock = new Object();
@@ -485,6 +493,9 @@ public class MediaRouter2 {
}
mSelectingRoute = null;
}
+ if (reason == SELECT_REASON_SYSTEM_SELECTED) {
+ reason = SELECT_REASON_USER_SELECTED;
+ }
mSelectedRoute = route;
notifyRouteSelected(route, reason, controlHints);
}
diff --git a/media/jni/Android.bp b/media/jni/Android.bp
index 2f53cbb24129..064ac75d3a84 100644
--- a/media/jni/Android.bp
+++ b/media/jni/Android.bp
@@ -41,6 +41,7 @@ cc_library_shared {
"libmedia_omx",
"libmediametrics",
"libmediadrm",
+ "libmediadrmmetrics_consumer",
"libhwui",
"libui",
"liblog",
diff --git a/media/jni/android_media_MediaDataSource.h b/media/jni/android_media_MediaDataSource.h
index 378baf433fed..b65039d37139 100644
--- a/media/jni/android_media_MediaDataSource.h
+++ b/media/jni/android_media_MediaDataSource.h
@@ -19,7 +19,7 @@
#include "jni.h"
-#include <media/IDataSource.h>
+#include <android/IDataSource.h>
#include <media/stagefright/foundation/ABase.h>
#include <utils/Errors.h>
#include <utils/Mutex.h>
diff --git a/media/jni/android_media_MediaDrm.cpp b/media/jni/android_media_MediaDrm.cpp
index 3833c6bfb676..acda18ea3dc2 100644
--- a/media/jni/android_media_MediaDrm.cpp
+++ b/media/jni/android_media_MediaDrm.cpp
@@ -32,7 +32,9 @@
#include <cutils/properties.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/MediaErrors.h>
+#include <mediadrm/DrmMetricsConsumer.h>
#include <mediadrm/DrmUtils.h>
+#include <mediadrm/IDrmMetricsConsumer.h>
#include <mediadrm/IDrm.h>
using ::android::os::PersistableBundle;
@@ -1889,7 +1891,8 @@ android_media_MediaDrm_native_getMetrics(JNIEnv *env, jobject thiz)
// Retrieve current metrics snapshot from drm.
PersistableBundle metrics;
- status_t err = drm->getMetrics(&metrics);
+ sp<IDrmMetricsConsumer> consumer(new DrmMetricsConsumer(&metrics));
+ status_t err = drm->getMetrics(consumer);
if (err != OK) {
ALOGE("getMetrics failed: %d", (int)err);
return (jobject) NULL;
diff --git a/media/jni/android_media_Streams.cpp b/media/jni/android_media_Streams.cpp
index b7cbd97409a2..4fd515323181 100644
--- a/media/jni/android_media_Streams.cpp
+++ b/media/jni/android_media_Streams.cpp
@@ -28,67 +28,6 @@
namespace android {
-AssetStream::AssetStream(SkStream* stream)
- : mStream(stream), mPosition(0) {
-}
-
-AssetStream::~AssetStream() {
-}
-
-piex::Error AssetStream::GetData(
- const size_t offset, const size_t length, std::uint8_t* data) {
- // Seek first.
- if (mPosition != offset) {
- if (!mStream->seek(offset)) {
- return piex::Error::kFail;
- }
- }
-
- // Read bytes.
- size_t size = mStream->read((void*)data, length);
- mPosition = offset + size;
-
- return size == length ? piex::Error::kOk : piex::Error::kFail;
-}
-
-BufferedStream::BufferedStream(SkStream* stream)
- : mStream(stream) {
-}
-
-BufferedStream::~BufferedStream() {
-}
-
-piex::Error BufferedStream::GetData(
- const size_t offset, const size_t length, std::uint8_t* data) {
- // Seek first.
- if (offset + length > mStreamBuffer.bytesWritten()) {
- size_t sizeToRead = offset + length - mStreamBuffer.bytesWritten();
- if (sizeToRead <= kMinSizeToRead) {
- sizeToRead = kMinSizeToRead;
- }
-
- void* tempBuffer = malloc(sizeToRead);
- if (tempBuffer == NULL) {
- return piex::Error::kFail;
- }
-
- size_t bytesRead = mStream->read(tempBuffer, sizeToRead);
- if (bytesRead != sizeToRead) {
- free(tempBuffer);
- return piex::Error::kFail;
- }
- mStreamBuffer.write(tempBuffer, bytesRead);
- free(tempBuffer);
- }
-
- // Read bytes.
- if (mStreamBuffer.read((void*)data, offset, length)) {
- return piex::Error::kOk;
- } else {
- return piex::Error::kFail;
- }
-}
-
FileStream::FileStream(const int fd)
: mPosition(0) {
mFile = fdopen(fd, "r");
diff --git a/media/jni/android_media_Streams.h b/media/jni/android_media_Streams.h
index d174f9a6650c..800591c1654f 100644
--- a/media/jni/android_media_Streams.h
+++ b/media/jni/android_media_Streams.h
@@ -25,53 +25,9 @@
#include <utils/KeyedVector.h>
#include <utils/String8.h>
#include <utils/StrongPointer.h>
-#include <SkStream.h>
-
namespace android {
-class AssetStream : public piex::StreamInterface {
-private:
- SkStream *mStream;
- size_t mPosition;
-
-public:
- explicit AssetStream(SkStream* stream);
- ~AssetStream();
-
- // Reads 'length' amount of bytes from 'offset' to 'data'. The 'data' buffer
- // provided by the caller, guaranteed to be at least "length" bytes long.
- // On 'kOk' the 'data' pointer contains 'length' valid bytes beginning at
- // 'offset' bytes from the start of the stream.
- // Returns 'kFail' if 'offset' + 'length' exceeds the stream and does not
- // change the contents of 'data'.
- piex::Error GetData(
- const size_t offset, const size_t length, std::uint8_t* data) override;
-};
-
-class BufferedStream : public piex::StreamInterface {
-private:
- SkStream *mStream;
- // Growable memory stream
- SkDynamicMemoryWStream mStreamBuffer;
-
- // Minimum size to read on filling the buffer.
- const size_t kMinSizeToRead = 8192;
-
-public:
- explicit BufferedStream(SkStream* stream);
- ~BufferedStream();
-
- // Reads 'length' amount of bytes from 'offset' to 'data'. The 'data' buffer
- // provided by the caller, guaranteed to be at least "length" bytes long.
- // On 'kOk' the 'data' pointer contains 'length' valid bytes beginning at
- // 'offset' bytes from the start of the stream.
- // Returns 'kFail' if 'offset' + 'length' exceeds the stream and does not
- // change the contents of 'data'.
- piex::Error GetData(
- const size_t offset, const size_t length, std::uint8_t* data) override;
-};
-
class FileStream : public piex::StreamInterface {
private:
FILE *mFile;
diff --git a/media/tests/MediaRouteProvider/src/com/android/mediarouteprovider/example/SampleMediaRoute2ProviderService.java b/media/tests/MediaRouteProvider/src/com/android/mediarouteprovider/example/SampleMediaRoute2ProviderService.java
index f4f8d0b73658..6650f9618638 100644
--- a/media/tests/MediaRouteProvider/src/com/android/mediarouteprovider/example/SampleMediaRoute2ProviderService.java
+++ b/media/tests/MediaRouteProvider/src/com/android/mediarouteprovider/example/SampleMediaRoute2ProviderService.java
@@ -20,6 +20,7 @@ import android.content.Intent;
import android.media.MediaRoute2Info;
import android.media.MediaRoute2ProviderInfo;
import android.media.MediaRoute2ProviderService;
+import android.os.Bundle;
import android.os.IBinder;
import java.util.HashMap;
@@ -95,7 +96,7 @@ public class SampleMediaRoute2ProviderService extends MediaRoute2ProviderService
}
@Override
- public void onSelectRoute(String packageName, String routeId) {
+ public void onSelectRoute(String packageName, String routeId, SelectToken token) {
MediaRoute2Info route = mRoutes.get(routeId);
if (route == null) {
return;
@@ -104,6 +105,7 @@ public class SampleMediaRoute2ProviderService extends MediaRoute2ProviderService
.setClientPackageName(packageName)
.build());
publishRoutes();
+ notifyRouteSelected(token, Bundle.EMPTY);
}
@Override
diff --git a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java
index d0f7c780ceb2..c70ad8d8755c 100644
--- a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java
+++ b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java
@@ -23,23 +23,19 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.argThat;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.timeout;
-import static org.mockito.Mockito.verify;
import android.content.Context;
import android.content.Intent;
import android.media.MediaRoute2Info;
import android.media.MediaRouter2;
import android.media.MediaRouter2Manager;
+import android.os.Bundle;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import android.text.TextUtils;
-import org.junit.Assert;
+import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -95,9 +91,14 @@ public class MediaRouterManagerTest {
private Executor mExecutor;
private String mPackageName;
+ private final List<MediaRouter2Manager.Callback> mManagerCallbacks = new ArrayList<>();
+ private final List<MediaRouter2.Callback> mRouterCallbacks = new ArrayList<>();
+ private Map<String, MediaRoute2Info> mRoutes;
+
private static final List<String> CATEGORIES_ALL = new ArrayList();
private static final List<String> CATEGORIES_SPECIAL = new ArrayList();
private static final List<String> CATEGORIES_LIVE_AUDIO = new ArrayList<>();
+
static {
CATEGORIES_ALL.add(CATEGORY_SAMPLE);
CATEGORIES_ALL.add(CATEGORY_SPECIAL);
@@ -108,6 +109,7 @@ public class MediaRouterManagerTest {
CATEGORIES_LIVE_AUDIO.add(CATEGORY_LIVE_AUDIO);
}
+
@Before
public void setUp() throws Exception {
mContext = InstrumentationRegistry.getTargetContext();
@@ -116,6 +118,16 @@ public class MediaRouterManagerTest {
//TODO: If we need to support thread pool executors, change this to thread pool executor.
mExecutor = Executors.newSingleThreadExecutor();
mPackageName = mContext.getPackageName();
+
+ // ensure media router 2 client
+ addRouterCallback(new MediaRouter2.Callback());
+ mRoutes = waitAndGetRoutesWithManager(CATEGORIES_ALL);
+ }
+
+ @After
+ public void tearDown() {
+ // unregister callbacks
+ clearCallbacks();
}
//TODO: Move to a separate file
@@ -132,10 +144,13 @@ public class MediaRouterManagerTest {
assertNotEquals(routeInfo1, routeInfo3);
}
+ /**
+ * Tests if routes are added correctly when a new callback is registered.
+ */
@Test
public void testOnRoutesAdded() throws Exception {
CountDownLatch latch = new CountDownLatch(1);
- MediaRouter2Manager.Callback callback = new MediaRouter2Manager.Callback() {
+ addManagerCallback(new MediaRouter2Manager.Callback() {
@Override
public void onRoutesAdded(List<MediaRoute2Info> routes) {
assertTrue(routes.size() > 0);
@@ -145,27 +160,15 @@ public class MediaRouterManagerTest {
}
}
}
- };
- mManager.registerCallback(mExecutor, callback);
+ });
assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
-
- mManager.unregisterCallback(callback);
}
@Test
public void testOnRoutesRemoved() throws Exception {
- MediaRouter2Manager.Callback mockCallback = mock(MediaRouter2Manager.Callback.class);
- mManager.registerCallback(mExecutor, mockCallback);
-
- MediaRouter2.Callback routerCallback = new MediaRouter2.Callback();
- mRouter2.registerCallback(mExecutor, routerCallback);
-
- Map<String, MediaRoute2Info> routes =
- waitAndGetRoutesWithManager(CATEGORIES_ALL);
-
CountDownLatch latch = new CountDownLatch(1);
- MediaRouter2Manager.Callback callback = new MediaRouter2Manager.Callback() {
+ addManagerCallback(new MediaRouter2Manager.Callback() {
@Override
public void onRoutesRemoved(List<MediaRoute2Info> routes) {
assertTrue(routes.size() > 0);
@@ -175,16 +178,12 @@ public class MediaRouterManagerTest {
}
}
}
- };
- mManager.registerCallback(mExecutor, callback);
+ });
//TODO: Figure out a more proper way to test.
// (Control requests shouldn't be used in this way.)
- mRouter2.sendControlRequest(routes.get(ROUTE_ID2), new Intent(ACTION_REMOVE_ROUTE));
+ mRouter2.sendControlRequest(mRoutes.get(ROUTE_ID2), new Intent(ACTION_REMOVE_ROUTE));
assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
-
- mRouter2.unregisterCallback(routerCallback);
- mManager.unregisterCallback(mockCallback);
}
/**
@@ -192,16 +191,10 @@ public class MediaRouterManagerTest {
*/
@Test
public void testControlCategory() throws Exception {
- MediaRouter2Manager.Callback mockCallback = mock(MediaRouter2Manager.Callback.class);
- mManager.registerCallback(mExecutor, mockCallback);
-
- Map<String, MediaRoute2Info> routes =
- waitAndGetRoutesWithManager(CATEGORIES_SPECIAL);
-
- Assert.assertEquals(1, routes.size());
- Assert.assertNotNull(routes.get(ROUTE_ID_SPECIAL_CATEGORY));
+ Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(CATEGORIES_SPECIAL);
- mManager.unregisterCallback(mockCallback);
+ assertEquals(1, routes.size());
+ assertNotNull(routes.get(ROUTE_ID_SPECIAL_CATEGORY));
}
/**
@@ -209,57 +202,74 @@ public class MediaRouterManagerTest {
*/
@Test
public void testGetRoutes() throws Exception {
- MediaRouter2.Callback mockCallback = mock(MediaRouter2.Callback.class);
- mRouter2.registerCallback(mExecutor, mockCallback);
-
Map<String, MediaRoute2Info> routes = waitAndGetRoutes(CATEGORIES_SPECIAL);
- Assert.assertEquals(1, routes.size());
- Assert.assertNotNull(routes.get(ROUTE_ID_SPECIAL_CATEGORY));
-
- mRouter2.unregisterCallback(mockCallback);
+ assertEquals(1, routes.size());
+ assertNotNull(routes.get(ROUTE_ID_SPECIAL_CATEGORY));
}
+ /**
+ * Tests if MR2.Callback.onRouteSelected is called when a route is selected from MR2Manager.
+ */
@Test
- public void testOnRouteSelected() throws Exception {
- MediaRouter2.Callback routerCallback = new MediaRouter2.Callback();
- MediaRouter2Manager.Callback managerCallback = mock(MediaRouter2Manager.Callback.class);
-
- mManager.registerCallback(mExecutor, managerCallback);
- mRouter2.registerCallback(mExecutor, routerCallback);
+ public void testRouterOnRouteSelected() throws Exception {
+ CountDownLatch latch = new CountDownLatch(1);
- Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(CATEGORIES_ALL);
+ addRouterCallback(new MediaRouter2.Callback() {
+ @Override
+ public void onRouteSelected(MediaRoute2Info route, int reason, Bundle controlHints) {
+ if (route != null && TextUtils.equals(route.getId(), ROUTE_ID1)) {
+ latch.countDown();
+ }
+ }
+ });
- MediaRoute2Info routeToSelect = routes.get(ROUTE_ID1);
+ MediaRoute2Info routeToSelect = mRoutes.get(ROUTE_ID1);
assertNotNull(routeToSelect);
mManager.selectRoute(mPackageName, routeToSelect);
- verify(managerCallback, timeout(TIMEOUT_MS))
- .onRouteSelected(eq(mPackageName),
- argThat(route -> route != null && route.equals(routeToSelect)));
- mRouter2.unregisterCallback(routerCallback);
- mManager.unregisterCallback(managerCallback);
+ assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
}
/**
- * Tests selecting and unselecting routes of a single provider.
+ * Tests if MR2Manager.Callback.onRouteSelected is called
+ * when a route is selected by MR2Manager.
*/
@Test
- public void testSingleProviderSelect() throws Exception {
- MediaRouter2.Callback routerCallback = mock(MediaRouter2.Callback.class);
+ public void testManagerOnRouteSelected() throws Exception {
+ CountDownLatch latch = new CountDownLatch(1);
- mRouter2.registerCallback(mExecutor, routerCallback);
+ addManagerCallback(new MediaRouter2Manager.Callback() {
+ @Override
+ public void onRouteSelected(String packageName, MediaRoute2Info route) {
+ if (TextUtils.equals(mPackageName, packageName)
+ && route != null && TextUtils.equals(route.getId(), ROUTE_ID1)) {
+ latch.countDown();
+ }
+ }
+ });
+
+ MediaRoute2Info routeToSelect = mRoutes.get(ROUTE_ID1);
+ assertNotNull(routeToSelect);
+
+ mManager.selectRoute(mPackageName, routeToSelect);
- Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(CATEGORIES_ALL);
+ assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+ }
+ /**
+ * Tests selecting and unselecting routes of a single provider.
+ */
+ @Test
+ public void testSingleProviderSelect() throws Exception {
awaitOnRouteChangedManager(
- () -> mManager.selectRoute(mPackageName, routes.get(ROUTE_ID1)),
+ () -> mManager.selectRoute(mPackageName, mRoutes.get(ROUTE_ID1)),
ROUTE_ID1,
route -> TextUtils.equals(route.getClientPackageName(), mPackageName));
awaitOnRouteChangedManager(
- () -> mManager.selectRoute(mPackageName, routes.get(ROUTE_ID2)),
+ () -> mManager.selectRoute(mPackageName, mRoutes.get(ROUTE_ID2)),
ROUTE_ID2,
route -> TextUtils.equals(route.getClientPackageName(), mPackageName));
@@ -267,8 +277,6 @@ public class MediaRouterManagerTest {
() -> mManager.unselectRoute(mPackageName),
ROUTE_ID2,
route -> TextUtils.equals(route.getClientPackageName(), null));
-
- mRouter2.unregisterCallback(routerCallback);
}
@Test
@@ -292,12 +300,7 @@ public class MediaRouterManagerTest {
@Test
public void testControlVolumeWithManager() throws Exception {
- MediaRouter2.Callback mockCallback = mock(MediaRouter2.Callback.class);
-
- mRouter2.registerCallback(mExecutor, mockCallback);
- Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(CATEGORIES_ALL);
-
- MediaRoute2Info volRoute = routes.get(ROUTE_ID_VARIABLE_VOLUME);
+ MediaRoute2Info volRoute = mRoutes.get(ROUTE_ID_VARIABLE_VOLUME);
int originalVolume = volRoute.getVolume();
int deltaVolume = (originalVolume == volRoute.getVolumeMax() ? -1 : 1);
@@ -310,24 +313,16 @@ public class MediaRouterManagerTest {
() -> mManager.requestSetVolume(volRoute, originalVolume),
ROUTE_ID_VARIABLE_VOLUME,
(route -> route.getVolume() == originalVolume));
-
- mRouter2.unregisterCallback(mockCallback);
}
@Test
public void testVolumeHandling() throws Exception {
- MediaRouter2.Callback mockCallback = mock(MediaRouter2.Callback.class);
- mRouter2.registerCallback(mExecutor, mockCallback);
- Map<String, MediaRoute2Info> routes = waitAndGetRoutes(CATEGORIES_ALL);
-
- MediaRoute2Info fixedVolumeRoute = routes.get(ROUTE_ID_FIXED_VOLUME);
- MediaRoute2Info variableVolumeRoute = routes.get(ROUTE_ID_VARIABLE_VOLUME);
+ MediaRoute2Info fixedVolumeRoute = mRoutes.get(ROUTE_ID_FIXED_VOLUME);
+ MediaRoute2Info variableVolumeRoute = mRoutes.get(ROUTE_ID_VARIABLE_VOLUME);
assertEquals(PLAYBACK_VOLUME_FIXED, fixedVolumeRoute.getVolumeHandling());
assertEquals(PLAYBACK_VOLUME_VARIABLE, variableVolumeRoute.getVolumeHandling());
assertEquals(VOLUME_MAX, variableVolumeRoute.getVolumeMax());
-
- mRouter2.unregisterCallback(mockCallback);
}
@Test
@@ -368,6 +363,7 @@ public class MediaRouterManagerTest {
latch.countDown();
}
}
+
@Override
public void onControlCategoriesChanged(String packageName) {
if (TextUtils.equals(mPackageName, packageName)) {
@@ -401,7 +397,7 @@ public class MediaRouterManagerTest {
};
mRouter2.registerCallback(mExecutor, callback);
try {
- new Thread(task).start();
+ task.run();
assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
} finally {
mRouter2.unregisterCallback(callback);
@@ -422,7 +418,7 @@ public class MediaRouterManagerTest {
};
mManager.registerCallback(mExecutor, callback);
try {
- new Thread(task).start();
+ task.run();
assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
} finally {
mManager.unregisterCallback(callback);
@@ -433,9 +429,31 @@ public class MediaRouterManagerTest {
static Map<String, MediaRoute2Info> createRouteMap(List<MediaRoute2Info> routes) {
Map<String, MediaRoute2Info> routeMap = new HashMap<>();
for (MediaRoute2Info route : routes) {
- // intentionally not route.getUniqueId() for convenience.
+ // intentionally not using route.getUniqueId() for convenience.
routeMap.put(route.getId(), route);
}
return routeMap;
}
+
+ private void addManagerCallback(MediaRouter2Manager.Callback callback) {
+ mManagerCallbacks.add(callback);
+ mManager.registerCallback(mExecutor, callback);
+ }
+
+ private void addRouterCallback(MediaRouter2.Callback callback) {
+ mRouterCallbacks.add(callback);
+ mRouter2.registerCallback(mExecutor, callback);
+ }
+
+ private void clearCallbacks() {
+ for (MediaRouter2Manager.Callback callback : mManagerCallbacks) {
+ mManager.unregisterCallback(callback);
+ }
+ mManagerCallbacks.clear();
+
+ for (MediaRouter2.Callback callback : mRouterCallbacks) {
+ mRouter2.unregisterCallback(callback);
+ }
+ mRouterCallbacks.clear();
+ }
}
diff --git a/packages/CarSystemUI/src/com/android/systemui/TEST_MAPPING b/packages/CarSystemUI/src/com/android/systemui/TEST_MAPPING
index f90947cbeb15..f2bf81102ab3 100644
--- a/packages/CarSystemUI/src/com/android/systemui/TEST_MAPPING
+++ b/packages/CarSystemUI/src/com/android/systemui/TEST_MAPPING
@@ -1,5 +1,5 @@
{
- "auto-postsubmit": [
+ "auto-end-to-end-postsubmit": [
{
"name": "AndroidAutoUiTests",
"options" : [
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/UserGridRecyclerView.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/UserGridRecyclerView.java
index fb1870a6ea42..7500bcd9b8f7 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/UserGridRecyclerView.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/UserGridRecyclerView.java
@@ -296,14 +296,42 @@ public class UserGridRecyclerView extends RecyclerView {
}
}
+ /**
+ * Get the maximum number of real (non-guest, non-managed profile) users that can be created
+ * on the device. This is a dynamic value and it decreases with the increase of the number
+ * of managed profiles on the device.
+ *
+ * <p> It excludes system user in headless system user model.
+ *
+ * @return Maximum number of real users that can be created.
+ */
+ private int getMaxSupportedRealUsers() {
+ int maxSupportedUsers = UserManager.getMaxSupportedUsers();
+ if (UserManager.isHeadlessSystemUserMode()) {
+ maxSupportedUsers -= 1;
+ }
+
+ List<UserInfo> users = mUserManager.getUsers(/* excludeDying= */ true);
+
+ // Count all users that are managed profiles of another user.
+ int managedProfilesCount = 0;
+ for (UserInfo user : users) {
+ if (user.isManagedProfile()) {
+ managedProfilesCount++;
+ }
+ }
+
+ return maxSupportedUsers - managedProfilesCount;
+ }
+
private void showMaxUserLimitReachedDialog() {
AlertDialog maxUsersDialog = new Builder(mContext,
com.android.internal.R.style.Theme_DeviceDefault_Dialog_Alert)
.setTitle(R.string.user_limit_reached_title)
.setMessage(getResources().getQuantityString(
R.plurals.user_limit_reached_message,
- mCarUserManagerHelper.getMaxSupportedRealUsers(),
- mCarUserManagerHelper.getMaxSupportedRealUsers()))
+ getMaxSupportedRealUsers(),
+ getMaxSupportedRealUsers()))
.setPositiveButton(android.R.string.ok, null)
.create();
// Sets window flags for the SysUI dialog
diff --git a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
index 4a50210d1a60..7b2922ba961b 100644
--- a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
+++ b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
@@ -50,6 +50,7 @@ import android.util.Log;
import android.util.Pair;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.content.FileSystemProvider;
import com.android.internal.util.IndentingPrintWriter;
@@ -308,37 +309,26 @@ public class ExternalStorageProvider extends FileSystemProvider {
@Override
protected boolean shouldBlockFromTree(@NonNull String docId) {
try {
- final File dir = getFileForDocId(docId, true /* visible */).getCanonicalFile();
- if (!dir.isDirectory()) {
+ final File dir = getFileForDocId(docId, false /* visible */);
+
+ // the file is null or it is not a directory
+ if (dir == null || !dir.isDirectory()) {
return false;
}
- final String path = dir.getAbsolutePath();
+ final String path = getPathFromDocId(docId);
- // Block Download folder from tree
- if (MediaStore.Downloads.isDownloadDir(path)) {
+ // Block the root of the storage
+ if (path.isEmpty()) {
return true;
}
- final ArrayMap<String, RootInfo> roots = new ArrayMap<>();
-
- synchronized (mRootsLock) {
- roots.putAll(mRoots);
+ // Block Download folder from tree
+ if (TextUtils.equals(Environment.DIRECTORY_DOWNLOADS.toLowerCase(),
+ path.toLowerCase())) {
+ return true;
}
- // block root of storage
- for (int i = 0; i < roots.size(); i++) {
- RootInfo rootInfo = roots.valueAt(i);
- // skip home root
- if (TextUtils.equals(rootInfo.rootId, ROOT_ID_HOME)) {
- continue;
- }
-
- // block the root of storage
- if (TextUtils.equals(path, rootInfo.visiblePath.getAbsolutePath())) {
- return true;
- }
- }
return false;
} catch (IOException e) {
throw new IllegalArgumentException(
@@ -430,6 +420,23 @@ public class ExternalStorageProvider extends FileSystemProvider {
return Pair.create(root, buildFile(root, docId, visible, true));
}
+ @VisibleForTesting
+ static String getPathFromDocId(String docId) {
+ final int splitIndex = docId.indexOf(':', 1);
+ final String path = docId.substring(splitIndex + 1);
+
+ if (path.isEmpty()) {
+ return path;
+ }
+
+ // remove trailing "/"
+ if (path.charAt(path.length() - 1) == '/') {
+ return path.substring(0, path.length() - 1);
+ } else {
+ return path;
+ }
+ }
+
private RootInfo getRootFromDocId(String docId) throws FileNotFoundException {
final int splitIndex = docId.indexOf(':', 1);
final String tag = docId.substring(0, splitIndex);
diff --git a/packages/ExternalStorageProvider/tests/src/com/android/externalstorage/ExternalStorageProviderTest.java b/packages/ExternalStorageProvider/tests/src/com/android/externalstorage/ExternalStorageProviderTest.java
index fbf2e4b8ff19..ed8320fa7fef 100644
--- a/packages/ExternalStorageProvider/tests/src/com/android/externalstorage/ExternalStorageProviderTest.java
+++ b/packages/ExternalStorageProvider/tests/src/com/android/externalstorage/ExternalStorageProviderTest.java
@@ -17,7 +17,10 @@
package com.android.externalstorage;
import static com.android.externalstorage.ExternalStorageProvider.AUTHORITY;
+import static com.android.externalstorage.ExternalStorageProvider.getPathFromDocId;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.atLeast;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
@@ -51,4 +54,18 @@ public class ExternalStorageProviderTest {
verify(spyProvider, atLeast(1)).updateVolumes();
}
+
+ @Test
+ public void testGetPathFromDocId() throws Exception {
+ final String root = "root";
+ final String path = "abc/def/ghi";
+ String docId = root + ":" + path;
+ assertEquals(getPathFromDocId(docId), path);
+
+ docId = root + ":" + path + "/";
+ assertEquals(getPathFromDocId(docId), path);
+
+ docId = root + ":";
+ assertTrue(getPathFromDocId(docId).isEmpty());
+ }
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/VisibilityLoggerMixin.java b/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/VisibilityLoggerMixin.java
index 1c6287907fbd..0a1a1226d0a3 100644
--- a/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/VisibilityLoggerMixin.java
+++ b/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/VisibilityLoggerMixin.java
@@ -76,6 +76,19 @@ public class VisibilityLoggerMixin implements LifecycleObserver, OnAttach {
}
/**
+ * Logs the elapsed time from onAttach to calling {@link #writeElapsedTimeMetric(int, String)}.
+ * @param action : The value of the Action Enums.
+ * @param key : The value of special key string.
+ */
+ public void writeElapsedTimeMetric(int action, String key) {
+ if (mMetricsFeature == null || mMetricsCategory == METRICS_CATEGORY_UNKNOWN) {
+ return;
+ }
+ final int elapse = (int) (SystemClock.elapsedRealtime() - mTimestamp);
+ mMetricsFeature.action(METRICS_CATEGORY_UNKNOWN, action, mMetricsCategory, key, elapse);
+ }
+
+ /**
* Sets source metrics category for this logger. Source is the caller that opened this UI.
*/
public void setSourceMetricsCategory(Activity activity) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
index f2af40e3d93f..b0bdf1dd8594 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
@@ -33,7 +33,6 @@ import android.net.NetworkKey;
import android.net.NetworkScoreManager;
import android.net.NetworkScorerAppData;
import android.net.ScoredNetwork;
-import android.net.wifi.IWifiManager;
import android.net.wifi.ScanResult;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiConfiguration.KeyMgmt;
@@ -47,7 +46,6 @@ import android.net.wifi.hotspot2.ProvisioningCallback;
import android.os.Bundle;
import android.os.Parcelable;
import android.os.RemoteException;
-import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.UserHandle;
import android.provider.Settings;
@@ -1612,13 +1610,8 @@ public class AccessPoint implements Comparable<AccessPoint> {
final ConnectivityManager cm = (ConnectivityManager)
context.getSystemService(Context.CONNECTIVITY_SERVICE);
if (state == DetailedState.CONNECTED) {
- IWifiManager wifiManager = IWifiManager.Stub.asInterface(
- ServiceManager.getService(Context.WIFI_SERVICE));
- NetworkCapabilities nc = null;
-
- try {
- nc = cm.getNetworkCapabilities(wifiManager.getCurrentNetwork());
- } catch (RemoteException e) {}
+ WifiManager wifiManager = context.getSystemService(WifiManager.class);
+ NetworkCapabilities nc = cm.getNetworkCapabilities(wifiManager.getCurrentNetwork());
if (nc != null) {
if (nc.hasCapability(nc.NET_CAPABILITY_CAPTIVE_PORTAL)) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
index 23754c5c73f9..23b16e811606 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
@@ -224,9 +224,7 @@ public class WifiTracker implements LifecycleObserver, OnStart, OnStop, OnDestro
mConnectivityManager = connectivityManager;
// check if verbose logging developer option has been turned on or off
- sVerboseLogging = Settings.Global.getInt(
- mContext.getContentResolver(),
- Settings.Global.WIFI_VERBOSE_LOGGING_ENABLED, 0) > 0;
+ sVerboseLogging = mWifiManager != null && (mWifiManager.getVerboseLoggingLevel() > 0);
mFilter = filter;
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
index 146f30d788d3..3b929b901e49 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
@@ -126,6 +126,7 @@ public class SecureSettings {
Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS,
Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS,
Settings.Secure.SHOW_NOTIFICATION_SNOOZE,
+ Settings.Secure.NOTIFICATION_HISTORY_ENABLED,
Settings.Secure.ZEN_DURATION,
Settings.Secure.SHOW_ZEN_UPGRADE_NOTIFICATION,
Settings.Secure.SHOW_ZEN_SETTINGS_SUGGESTION,
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
index 0c3254a5ed02..9460d27f7843 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
@@ -182,6 +182,7 @@ public class SecureSettingsValidators {
VALIDATORS.put(Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.SHOW_NOTIFICATION_SNOOZE, BOOLEAN_VALIDATOR);
+ VALIDATORS.put(Secure.NOTIFICATION_HISTORY_ENABLED, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.ZEN_DURATION, ANY_INTEGER_VALIDATOR);
VALIDATORS.put(Secure.SHOW_ZEN_UPGRADE_NOTIFICATION, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.SHOW_ZEN_SETTINGS_SUGGESTION, BOOLEAN_VALIDATOR);
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index 7b022a268170..eefba5db60ff 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -684,6 +684,7 @@ public class SettingsBackupTest {
Settings.Secure.SEARCH_SHORTCUT_REFRESH_MAX_POOL_SIZE,
Settings.Secure.SEARCH_SOURCE_TIMEOUT_MILLIS,
Settings.Secure.SEARCH_THREAD_KEEPALIVE_SECONDS,
+ Settings.Secure.SECURE_FRP_MODE,
Settings.Secure.SEARCH_WEB_RESULTS_OVERRIDE_LIMIT,
Settings.Secure.SELECTED_INPUT_METHOD_SUBTYPE,
Settings.Secure.SELECTED_SPELL_CHECKER, // Intentionally removed in Q
diff --git a/packages/SystemUI/TEST_MAPPING b/packages/SystemUI/TEST_MAPPING
new file mode 100644
index 000000000000..281406f24cb2
--- /dev/null
+++ b/packages/SystemUI/TEST_MAPPING
@@ -0,0 +1,23 @@
+{
+ // Looking for unit test presubmit configuration?
+ // This currently lives in ATP config apct/system_ui/unit_test
+ "staged-platinum-postsubmit": [
+ {
+ "name": "PlatformScenarioTests",
+ "options": [
+ {
+ "include-filter": "android.platform.test.scenario.sysui"
+ },
+ {
+ "include-filter": "android.platform.test.scenario.quicksettings"
+ },
+ {
+ "include-filter": "android.platform.test.scenario.notification"
+ },
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ }
+ ]
+ }
+ ]
+}
diff --git a/packages/SystemUI/res/drawable/action_chip_background.xml b/packages/SystemUI/res/drawable/action_chip_background.xml
new file mode 100644
index 000000000000..fc3dfeb9c1fd
--- /dev/null
+++ b/packages/SystemUI/res/drawable/action_chip_background.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2019 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<ripple
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:color="@color/global_screenshot_button_ripple">
+ <item android:id="@android:id/background">
+ <shape android:shape="rectangle">
+ <stroke android:width="1dp" android:color="@color/global_screenshot_button_text"/>
+ <solid android:color="@color/global_screenshot_button_background"/>
+ <corners android:radius="@dimen/screenshot_button_corner_radius"/>
+ </shape>
+ </item>
+</ripple> \ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/action_chip_container_background.xml b/packages/SystemUI/res/drawable/action_chip_container_background.xml
new file mode 100644
index 000000000000..095213e38e92
--- /dev/null
+++ b/packages/SystemUI/res/drawable/action_chip_container_background.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2019 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <solid android:color="@color/global_screenshot_button_background"/>
+ <corners android:radius="@dimen/screenshot_action_container_corner_radius"/>
+</shape> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/global_screenshot.xml b/packages/SystemUI/res/layout/global_screenshot.xml
index 59952e09555f..6ac9da4291c6 100644
--- a/packages/SystemUI/res/layout/global_screenshot.xml
+++ b/packages/SystemUI/res/layout/global_screenshot.xml
@@ -39,4 +39,13 @@
android:layout_height="match_parent"
android:visibility="gone"
android:pointerIcon="crosshair"/>
+ <LinearLayout
+ android:id="@+id/global_screenshot_actions"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="bottom|center"
+ android:gravity="center"
+ android:paddingVertical="@dimen/screenshot_action_container_padding"
+ android:visibility="gone"
+ android:background="@drawable/action_chip_container_background"/>
</FrameLayout>
diff --git a/packages/SystemUI/res/layout/global_screenshot_action_chip.xml b/packages/SystemUI/res/layout/global_screenshot_action_chip.xml
new file mode 100644
index 000000000000..6b424002d7ff
--- /dev/null
+++ b/packages/SystemUI/res/layout/global_screenshot_action_chip.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2019 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT 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/global_screenshot_action_chip"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginHorizontal="@dimen/screenshot_action_chip_margin_horizontal"
+ android:paddingVertical="@dimen/screenshot_action_chip_padding_vertical"
+ android:paddingHorizontal="@dimen/screenshot_action_chip_padding_horizontal"
+ android:background="@drawable/action_chip_background"
+ android:textColor="@color/global_screenshot_button_text"/>
diff --git a/packages/SystemUI/res/values-night/colors.xml b/packages/SystemUI/res/values-night/colors.xml
index 0febc8ed4262..9a66e8bc8791 100644
--- a/packages/SystemUI/res/values-night/colors.xml
+++ b/packages/SystemUI/res/values-night/colors.xml
@@ -78,6 +78,11 @@
<!-- The color of the text in the Global Actions menu -->
<color name="global_actions_alert_text">@color/GM2_red_300</color>
+ <!-- Global screenshot actions -->
+ <color name="global_screenshot_button_background">@color/GM2_grey_900</color>
+ <color name="global_screenshot_button_ripple">#42FFFFFF</color>
+ <color name="global_screenshot_button_text">@color/GM2_blue_300</color>
+
<!-- Biometric dialog colors -->
<color name="biometric_dialog_gray">#ff888888</color>
<color name="biometric_dialog_accent">#ff80cbc4</color> <!-- light teal -->
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index bda1c52f27c0..92c74770a3c4 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -180,6 +180,11 @@
<!-- Color for the Assistant invocation lights -->
<color name="default_invocation_lights_color">#ffffffff</color> <!-- white -->
+ <!-- Global screenshot actions -->
+ <color name="global_screenshot_button_background">#F5F5F5</color>
+ <color name="global_screenshot_button_ripple">#1f000000</color>
+ <color name="global_screenshot_button_text">@color/GM2_blue_500</color>
+
<!-- GM2 colors -->
<color name="GM2_grey_50">#F8F9FA</color>
<color name="GM2_grey_100">#F1F3F4</color>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 86ef0310b4eb..076cd226f931 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -281,7 +281,6 @@
<item>com.android.systemui.statusbar.phone.StatusBar</item>
<item>com.android.systemui.usb.StorageNotification</item>
<item>com.android.systemui.power.PowerUI</item>
- <item>com.android.systemui.power.InattentiveSleepWarningController</item>
<item>com.android.systemui.media.RingtonePlayer</item>
<item>com.android.systemui.keyboard.KeyboardUI</item>
<item>com.android.systemui.pip.PipUI</item>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 64b2892efc9a..f7b92b564dac 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -285,8 +285,18 @@
<!-- the padding between dots in the icon overflow -->
<dimen name="overflow_icon_dot_padding">3dp</dimen>
+ <!-- Dimensions related to screenshots -->
+
<!-- The padding on the global screenshot background image -->
<dimen name="global_screenshot_bg_padding">20dp</dimen>
+ <dimen name="screenshot_action_container_corner_radius">10dp</dimen>
+ <dimen name="screenshot_action_container_padding">20dp</dimen>
+ <!-- Radius of the chip background on global screenshot actions -->
+ <dimen name="screenshot_button_corner_radius">20dp</dimen>
+ <dimen name="screenshot_action_chip_margin_horizontal">10dp</dimen>
+ <dimen name="screenshot_action_chip_padding_vertical">10dp</dimen>
+ <dimen name="screenshot_action_chip_padding_horizontal">15dp</dimen>
+
<!-- The width of the view containing navigation buttons -->
<dimen name="navigation_key_width">70dp</dimen>
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java b/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java
index 2ec09a9dbea2..793f8b9bc05b 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java
@@ -686,6 +686,10 @@ public class StackAnimationController extends
} else {
// If there's no other bubbles, and we were in the dismiss target, reset the flag.
mWithinDismissTarget = false;
+ // When all children are removed ensure stack position is sane
+ setStackPosition(mRestingStackPosition == null
+ ? getDefaultStartPosition()
+ : mRestingStackPosition);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java
index 25986c5f4160..3cf14d65e5b8 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java
@@ -25,7 +25,6 @@ import com.android.systemui.biometrics.AuthController;
import com.android.systemui.globalactions.GlobalActionsComponent;
import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.pip.PipUI;
-import com.android.systemui.power.InattentiveSleepWarningController;
import com.android.systemui.power.PowerUI;
import com.android.systemui.recents.Recents;
import com.android.systemui.recents.RecentsModule;
@@ -103,13 +102,6 @@ public abstract class SystemUIBinder {
@ClassKey(PowerUI.class)
public abstract SystemUI bindPowerUI(PowerUI sysui);
- /** Inject into InattentiveSleepWarningController. */
- @Binds
- @IntoMap
- @ClassKey(InattentiveSleepWarningController.class)
- public abstract SystemUI bindInattentiveSleepWarningController(
- InattentiveSleepWarningController sysui);
-
/** Inject into Recents. */
@Binds
@IntoMap
diff --git a/packages/SystemUI/src/com/android/systemui/dock/DockManager.java b/packages/SystemUI/src/com/android/systemui/dock/DockManager.java
index c7637fb42889..b6f7cd04c75f 100644
--- a/packages/SystemUI/src/com/android/systemui/dock/DockManager.java
+++ b/packages/SystemUI/src/com/android/systemui/dock/DockManager.java
@@ -35,6 +35,12 @@ public interface DockManager {
int STATE_DOCKED_HIDE = 2;
/**
+ * Indicates there's no alignment info. This could happen when the device is unable to decide
+ * its alignment condition.
+ */
+ int ALIGN_STATE_UNKNOWN = -1;
+
+ /**
* Indicates there's no alignment issue.
*/
int ALIGN_STATE_GOOD = 0;
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java
index d5f5a5a00500..53053fc27216 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java
@@ -17,9 +17,11 @@ package com.android.systemui.globalactions;
import static android.app.StatusBarManager.DISABLE2_GLOBAL_ACTIONS;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
+import android.annotation.Nullable;
+import android.annotation.StringRes;
import android.app.Dialog;
-import android.app.KeyguardManager;
import android.content.Context;
+import android.os.PowerManager;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
@@ -134,14 +136,22 @@ public class GlobalActionsImpl implements GlobalActions, CommandQueue.Callbacks,
int color = Utils.getColorAttrDefaultColor(mContext,
com.android.systemui.R.attr.wallpaperTextColor);
- boolean onKeyguard = mContext.getSystemService(
- KeyguardManager.class).isKeyguardLocked();
ProgressBar bar = d.findViewById(R.id.progress);
bar.getIndeterminateDrawable().setTint(color);
- TextView message = d.findViewById(R.id.text1);
- message.setTextColor(color);
- if (isReboot) message.setText(R.string.reboot_to_reset_message);
+
+ TextView reasonView = d.findViewById(R.id.text1);
+ TextView messageView = d.findViewById(R.id.text2);
+
+ reasonView.setTextColor(color);
+ messageView.setTextColor(color);
+
+ messageView.setText(getRebootMessage(isReboot, reason));
+ String rebootReasonMessage = getReasonMessage(reason);
+ if (rebootReasonMessage != null) {
+ reasonView.setVisibility(View.VISIBLE);
+ reasonView.setText(rebootReasonMessage);
+ }
GradientColors colors = Dependency.get(SysuiColorExtractor.class).getNeutralColors();
background.setColor(colors.getMainColor(), false);
@@ -149,6 +159,30 @@ public class GlobalActionsImpl implements GlobalActions, CommandQueue.Callbacks,
d.show();
}
+ @StringRes
+ private int getRebootMessage(boolean isReboot, @Nullable String reason) {
+ if (reason != null && reason.startsWith(PowerManager.REBOOT_RECOVERY_UPDATE)) {
+ return R.string.reboot_to_update_reboot;
+ } else if (reason != null && reason.equals(PowerManager.REBOOT_RECOVERY)) {
+ return R.string.reboot_to_reset_message;
+ } else if (isReboot) {
+ return R.string.reboot_to_reset_message;
+ } else {
+ return R.string.shutdown_progress;
+ }
+ }
+
+ @Nullable
+ private String getReasonMessage(@Nullable String reason) {
+ if (reason != null && reason.startsWith(PowerManager.REBOOT_RECOVERY_UPDATE)) {
+ return mContext.getString(R.string.reboot_to_update_title);
+ } else if (reason != null && reason.equals(PowerManager.REBOOT_RECOVERY)) {
+ return mContext.getString(R.string.reboot_to_reset_title);
+ } else {
+ return null;
+ }
+ }
+
@Override
public void disable(int displayId, int state1, int state2, boolean animate) {
final boolean disabled = (state2 & DISABLE2_GLOBAL_ACTIONS) != 0;
diff --git a/packages/SystemUI/src/com/android/systemui/power/InattentiveSleepWarningController.java b/packages/SystemUI/src/com/android/systemui/power/InattentiveSleepWarningController.java
deleted file mode 100644
index 7d4bd019e72b..000000000000
--- a/packages/SystemUI/src/com/android/systemui/power/InattentiveSleepWarningController.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES 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.systemui.power;
-
-import android.content.Context;
-
-import com.android.systemui.SystemUI;
-import com.android.systemui.statusbar.CommandQueue;
-
-import javax.inject.Inject;
-import javax.inject.Singleton;
-
-/**
- * Receives messages sent from {@link com.android.server.power.InattentiveSleepWarningController}
- * and shows the appropriate inattentive sleep UI (e.g. {@link InattentiveSleepWarningView}).
- */
-@Singleton
-public class InattentiveSleepWarningController extends SystemUI implements CommandQueue.Callbacks {
- private final CommandQueue mCommandQueue;
- private InattentiveSleepWarningView mOverlayView;
-
- @Inject
- public InattentiveSleepWarningController(Context context, CommandQueue commandQueue) {
- super(context);
- mCommandQueue = commandQueue;
- }
-
- @Override
- public void start() {
- mCommandQueue.addCallback(this);
- }
-
- @Override
- public void showInattentiveSleepWarning() {
- if (mOverlayView == null) {
- mOverlayView = new InattentiveSleepWarningView(mContext);
- }
-
- mOverlayView.show();
- }
-
- @Override
- public void dismissInattentiveSleepWarning(boolean animated) {
- if (mOverlayView != null) {
- mOverlayView.dismiss(animated);
- }
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
index f60d9db7ac9c..59ac329e1983 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
@@ -46,6 +46,7 @@ import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.SystemUI;
import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.phone.StatusBar;
import java.io.FileDescriptor;
@@ -60,7 +61,7 @@ import javax.inject.Singleton;
import dagger.Lazy;
@Singleton
-public class PowerUI extends SystemUI {
+public class PowerUI extends SystemUI implements CommandQueue.Callbacks {
static final String TAG = "PowerUI";
static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
@@ -80,6 +81,7 @@ public class PowerUI extends SystemUI {
private PowerManager mPowerManager;
private WarningsUI mWarnings;
+ private InattentiveSleepWarningView mOverlayView;
private final Configuration mLastConfiguration = new Configuration();
private int mPlugType = 0;
private int mInvalidCharger = 0;
@@ -105,13 +107,15 @@ public class PowerUI extends SystemUI {
private IThermalEventListener mSkinThermalEventListener;
private IThermalEventListener mUsbThermalEventListener;
private final BroadcastDispatcher mBroadcastDispatcher;
+ private final CommandQueue mCommandQueue;
private final Lazy<StatusBar> mStatusBarLazy;
@Inject
public PowerUI(Context context, BroadcastDispatcher broadcastDispatcher,
- Lazy<StatusBar> statusBarLazy) {
+ CommandQueue commandQueue, Lazy<StatusBar> statusBarLazy) {
super(context);
mBroadcastDispatcher = broadcastDispatcher;
+ mCommandQueue = commandQueue;
mStatusBarLazy = statusBarLazy;
}
@@ -162,6 +166,7 @@ public class PowerUI extends SystemUI {
}
});
initThermalEventListeners();
+ mCommandQueue.addCallback(this);
}
@Override
@@ -581,6 +586,22 @@ public class PowerUI extends SystemUI {
}
}
+ @Override
+ public void showInattentiveSleepWarning() {
+ if (mOverlayView == null) {
+ mOverlayView = new InattentiveSleepWarningView(mContext);
+ }
+
+ mOverlayView.show();
+ }
+
+ @Override
+ public void dismissInattentiveSleepWarning(boolean animated) {
+ if (mOverlayView != null) {
+ mOverlayView.dismiss(animated);
+ }
+ }
+
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
pw.print("mLowBatteryAlertCloseLevel=");
pw.println(mLowBatteryAlertCloseLevel);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
index 16a39750a9bd..001e09406e3a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
@@ -73,7 +73,6 @@ public class HotspotTile extends QSTileImpl<BooleanState> {
if (listening) {
refreshState();
}
- mHotspotController.handleSetListening(listening);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
index 66cd91996cea..fedd855a858e 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
@@ -19,6 +19,7 @@ package com.android.systemui.screenshot;
import static android.content.Context.NOTIFICATION_SERVICE;
import static android.os.AsyncTask.THREAD_POOL_EXECUTOR;
import static android.provider.DeviceConfig.NAMESPACE_SYSTEMUI;
+import static android.view.View.VISIBLE;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.SCREENSHOT_CORNER_FLOW;
@@ -69,6 +70,8 @@ import android.view.ViewGroup;
import android.view.WindowManager;
import android.view.animation.Interpolator;
import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
import android.widget.Toast;
import com.android.internal.annotations.VisibleForTesting;
@@ -89,7 +92,6 @@ import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.function.Consumer;
-import java.util.function.Function;
import javax.inject.Inject;
import javax.inject.Singleton;
@@ -110,7 +112,7 @@ public class GlobalScreenshot {
public Bitmap image;
public Uri imageUri;
public Consumer<Uri> finisher;
- public Function<PendingIntent, Void> onEditReady;
+ public GlobalScreenshot.ActionsReadyListener mActionsReadyListener;
public int iconSize;
public int previewWidth;
public int previewheight;
@@ -127,6 +129,10 @@ public class GlobalScreenshot {
}
}
+ abstract static class ActionsReadyListener {
+ abstract void onActionsReady(PendingIntent shareAction, PendingIntent editAction);
+ }
+
// These strings are used for communicating the action invoked to
// ScreenshotNotificationSmartActionsProvider.
static final String EXTRA_ACTION_TYPE = "android:screenshot_action_type";
@@ -175,6 +181,10 @@ public class GlobalScreenshot {
private ImageView mBackgroundView;
private ImageView mScreenshotView;
private ImageView mScreenshotFlash;
+ private LinearLayout mActionsView;
+ private TextView mShareAction;
+ private TextView mEditAction;
+ private TextView mScrollAction;
private AnimatorSet mScreenshotAnimation;
@@ -211,17 +221,31 @@ public class GlobalScreenshot {
mScreenshotLayout = layoutInflater.inflate(R.layout.global_screenshot, null);
mBackgroundView = mScreenshotLayout.findViewById(R.id.global_screenshot_background);
mScreenshotView = mScreenshotLayout.findViewById(R.id.global_screenshot);
+ mActionsView = mScreenshotLayout.findViewById(R.id.global_screenshot_actions);
+
+ mShareAction = (TextView) layoutInflater.inflate(
+ R.layout.global_screenshot_action_chip, mActionsView, false);
+ mEditAction = (TextView) layoutInflater.inflate(
+ R.layout.global_screenshot_action_chip, mActionsView, false);
+ mScrollAction = (TextView) layoutInflater.inflate(
+ R.layout.global_screenshot_action_chip, mActionsView, false);
+
+ mShareAction.setText(com.android.internal.R.string.share);
+ mEditAction.setText(com.android.internal.R.string.screenshot_edit);
+ mScrollAction.setText("Scroll"); // TODO (mkephart): Add to resources and translate
+
+ mActionsView.addView(mShareAction);
+ mActionsView.addView(mEditAction);
+ mActionsView.addView(mScrollAction);
+
mScreenshotFlash = mScreenshotLayout.findViewById(R.id.global_screenshot_flash);
mScreenshotSelectorView = mScreenshotLayout.findViewById(R.id.global_screenshot_selector);
mScreenshotLayout.setFocusable(true);
mScreenshotSelectorView.setFocusable(true);
mScreenshotSelectorView.setFocusableInTouchMode(true);
- mScreenshotLayout.setOnTouchListener(new View.OnTouchListener() {
- @Override
- public boolean onTouch(View v, MotionEvent event) {
- // Intercept and ignore all touch events
- return true;
- }
+ mScreenshotLayout.setOnTouchListener((v, event) -> {
+ // Intercept and ignore all touch events
+ return true;
});
// Setup the window that we are going to use
@@ -271,13 +295,13 @@ public class GlobalScreenshot {
* Creates a new worker thread and saves the screenshot to the media store.
*/
private void saveScreenshotInWorkerThread(
- Consumer<Uri> finisher, @Nullable Function<PendingIntent, Void> onEditReady) {
+ Consumer<Uri> finisher, @Nullable ActionsReadyListener actionsReadyListener) {
SaveImageInBackgroundData data = new SaveImageInBackgroundData();
data.context = mContext;
data.image = mScreenBitmap;
data.iconSize = mNotificationIconSize;
data.finisher = finisher;
- data.onEditReady = onEditReady;
+ data.mActionsReadyListener = actionsReadyListener;
data.previewWidth = mPreviewWidth;
data.previewheight = mPreviewHeight;
if (mSaveInBgTask != null) {
@@ -395,6 +419,7 @@ public class GlobalScreenshot {
// Clear any references to the bitmap
mScreenBitmap = null;
mScreenshotView.setImageBitmap(null);
+ mActionsView.setVisibility(View.GONE);
mBackgroundView.setVisibility(View.GONE);
mScreenshotView.setVisibility(View.GONE);
mScreenshotView.setLayerType(View.LAYER_TYPE_NONE, null);
@@ -441,24 +466,13 @@ public class GlobalScreenshot {
saveScreenshotInWorkerThread(finisher);
clearScreenshot();
} else {
- mScreenshotView.requestFocus();
- mScreenshotView.setOnClickListener((v) -> {
- // TODO: remove once we have a better UI to show that we aren't ready yet
- Toast notReadyToast = Toast.makeText(
- mContext, "Screenshot is not ready yet", Toast.LENGTH_SHORT);
- notReadyToast.show();
- });
- saveScreenshotInWorkerThread(finisher, intent -> {
- mScreenshotHandler.post(() -> mScreenshotView.setOnClickListener(v -> {
- try {
- intent.send();
- clearScreenshot();
- } catch (PendingIntent.CanceledException e) {
- Log.e(TAG, "Edit intent cancelled", e);
- }
- mScreenshotHandler.removeMessages(MESSAGE_CORNER_TIMEOUT);
- }));
- return null;
+ saveScreenshotInWorkerThread(finisher, new ActionsReadyListener() {
+ @Override
+ void onActionsReady(PendingIntent shareAction, PendingIntent editAction) {
+ mScreenshotHandler.post(() ->
+ createScreenshotActionsShadeAnimation(shareAction, editAction)
+ .start());
+ }
});
mScreenshotHandler.sendMessageDelayed(
mScreenshotHandler.obtainMessage(MESSAGE_CORNER_TIMEOUT),
@@ -664,6 +678,49 @@ public class GlobalScreenshot {
return anim;
}
+ private ValueAnimator createScreenshotActionsShadeAnimation(
+ PendingIntent shareAction, PendingIntent editAction) {
+ ValueAnimator animator = ValueAnimator.ofFloat(0, 1);
+ mActionsView.setY(mDisplayMetrics.heightPixels);
+ mActionsView.setVisibility(VISIBLE);
+ mActionsView.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
+ float actionsViewHeight = mActionsView.getMeasuredHeight();
+ float screenshotStartHeight = mScreenshotView.getTranslationY();
+
+ animator.addUpdateListener(animation -> {
+ float t = animation.getAnimatedFraction();
+ mScreenshotView.setTranslationY(screenshotStartHeight - actionsViewHeight * t);
+ mActionsView.setY(mDisplayMetrics.heightPixels - actionsViewHeight * t);
+ });
+ animator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ super.onAnimationEnd(animation);
+ mScreenshotView.requestFocus();
+ mShareAction.setOnClickListener(v -> {
+ try {
+ shareAction.send();
+ clearScreenshot();
+ } catch (PendingIntent.CanceledException e) {
+ Log.e(TAG, "Share intent cancelled", e);
+ }
+ });
+ mEditAction.setOnClickListener(v -> {
+ try {
+ editAction.send();
+ clearScreenshot();
+ } catch (PendingIntent.CanceledException e) {
+ Log.e(TAG, "Edit intent cancelled", e);
+ }
+ });
+ Toast scrollNotImplemented = Toast.makeText(
+ mContext, "Not implemented", Toast.LENGTH_SHORT);
+ mScrollAction.setOnClickListener(v -> scrollNotImplemented.show());
+ }
+ });
+ return animator;
+ }
+
static void notifyScreenshotError(Context context, NotificationManager nManager, int msgResId) {
Resources r = context.getResources();
String errorMsg = r.getString(msgResId);
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java b/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java
index 5e5cf743b468..d2268e12c662 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java
@@ -434,8 +434,8 @@ class SaveImageInBackgroundTask extends AsyncTask<Void, Void, Void> {
R.drawable.ic_screenshot_edit,
r.getString(com.android.internal.R.string.screenshot_edit), editAction);
notificationBuilder.addAction(editActionBuilder.build());
- if (editAction != null && mParams.onEditReady != null) {
- mParams.onEditReady.apply(editAction);
+ if (mParams.mActionsReadyListener != null) {
+ mParams.mActionsReadyListener.onActionsReady(shareAction, editAction);
}
// Create a delete action for the notification
@@ -472,7 +472,7 @@ class SaveImageInBackgroundTask extends AsyncTask<Void, Void, Void> {
GlobalScreenshot.notifyScreenshotError(mParams.context, mNotificationManager,
mParams.errorMsgResId);
} else {
- if (mParams.onEditReady != null) {
+ if (mParams.mActionsReadyListener != null) {
// Cancel the "saving screenshot" notification
mNotificationManager.cancel(
SystemMessageProto.SystemMessage.NOTE_GLOBAL_SCREENSHOT);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotController.java
index 8b06a9fa05a1..830b50e35490 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotController.java
@@ -20,8 +20,6 @@ import com.android.systemui.Dumpable;
import com.android.systemui.statusbar.policy.HotspotController.Callback;
public interface HotspotController extends CallbackController<Callback>, Dumpable {
- void handleSetListening(boolean listening);
-
boolean isHotspotEnabled();
boolean isHotspotTransient();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java
index 6331a2d6db1c..cd6ec05d90ec 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java
@@ -54,7 +54,6 @@ public class HotspotControllerImpl implements HotspotController, WifiManager.Sof
private int mHotspotState;
private volatile int mNumConnectedDevices;
private boolean mWaitingForTerminalState;
- private boolean mListening;
/**
* Controller used to retrieve information related to a hotspot.
@@ -109,19 +108,14 @@ public class HotspotControllerImpl implements HotspotController, WifiManager.Sof
if (DEBUG) Log.d(TAG, "addCallback " + callback);
mCallbacks.add(callback);
if (mWifiManager != null) {
- if (mListening) {
- if (mCallbacks.size() == 1) {
- mWifiManager.registerSoftApCallback(new HandlerExecutor(mMainHandler),
- this);
- } else {
- // mWifiManager#registerSoftApCallback triggers a call to
- // onConnectedClientsChanged on the Main Handler. In order to always update
- // the callback on added, we make this call when adding callbacks after the
- // first.
- mMainHandler.post(() ->
- callback.onHotspotChanged(isHotspotEnabled(),
- mNumConnectedDevices));
- }
+ if (mCallbacks.size() == 1) {
+ mWifiManager.registerSoftApCallback(new HandlerExecutor(mMainHandler), this);
+ } else {
+ // mWifiManager#registerSoftApCallback triggers a call to onNumClientsChanged
+ // on the Main Handler. In order to always update the callback on added, we
+ // make this call when adding callbacks after the first.
+ mMainHandler.post(() ->
+ callback.onHotspotChanged(isHotspotEnabled(), mNumConnectedDevices));
}
}
}
@@ -133,24 +127,13 @@ public class HotspotControllerImpl implements HotspotController, WifiManager.Sof
if (DEBUG) Log.d(TAG, "removeCallback " + callback);
synchronized (mCallbacks) {
mCallbacks.remove(callback);
- if (mCallbacks.isEmpty() && mWifiManager != null && mListening) {
+ if (mCallbacks.isEmpty() && mWifiManager != null) {
mWifiManager.unregisterSoftApCallback(this);
}
}
}
@Override
- public void handleSetListening(boolean listening) {
- // Wait for the first |handleSetListening(true))| to register softap callbacks (for lazy
- // registration of the softap callbacks).
- if (mListening || !listening) return;
- mListening = true;
- if (mCallbacks.size() >= 1) {
- mWifiManager.registerSoftApCallback(new HandlerExecutor(mMainHandler), this);
- }
- }
-
- @Override
public boolean isHotspotEnabled() {
return mHotspotState == WifiManager.WIFI_AP_STATE_ENABLED;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
index 05a4b290fb7b..24492bf3ca5b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -325,7 +325,6 @@ public class NetworkControllerImpl extends BroadcastReceiver
filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
filter.addAction(ConnectivityManager.INET_CONDITION_ACTION);
filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
- filter.addAction(Intent.ACTION_BOOT_COMPLETED);
filter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
mBroadcastDispatcher.registerReceiver(this, filter, mReceiverHandler);
mListening = true;
@@ -543,9 +542,6 @@ public class NetworkControllerImpl extends BroadcastReceiver
recalculateEmergency();
}
break;
- case Intent.ACTION_BOOT_COMPLETED:
- mWifiSignalController.handleBootCompleted();
- break;
case CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED:
mConfig = Config.readConfig(mContext);
mReceiverHandler.post(this::handleConfigurationChanged);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java
index 5a4332105e57..e7d1c95db0e3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java
@@ -38,7 +38,6 @@ import java.util.Objects;
public class WifiSignalController extends
SignalController<WifiSignalController.WifiState, SignalController.IconGroup> {
private final boolean mHasMobileData;
- private final WifiManager mWifiManager;
private final WifiStatusTracker mWifiTracker;
public WifiSignalController(Context context, boolean hasMobileData,
@@ -50,11 +49,13 @@ public class WifiSignalController extends
context.getSystemService(NetworkScoreManager.class);
ConnectivityManager connectivityManager =
context.getSystemService(ConnectivityManager.class);
- mWifiManager = wifiManager;
mWifiTracker = new WifiStatusTracker(mContext, wifiManager, networkScoreManager,
connectivityManager, this::handleStatusUpdated);
mWifiTracker.setListening(true);
mHasMobileData = hasMobileData;
+ if (wifiManager != null) {
+ wifiManager.registerTrafficStateCallback(new WifiTrafficStateCallback());
+ }
// WiFi only has one state.
mCurrentState.iconGroup = mLastState.iconGroup = new IconGroup(
"Wi-Fi Icons",
@@ -127,10 +128,6 @@ public class WifiSignalController extends
notifyListenersIfNecessary();
}
- public void handleBootCompleted() {
- mWifiManager.registerTrafficStateCallback(new WifiTrafficStateCallback());
- }
-
/**
* Handler to receive the data activity on wifi.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/usb/UsbConfirmActivity.java b/packages/SystemUI/src/com/android/systemui/usb/UsbConfirmActivity.java
index fd99ef389bec..286b7c049fc7 100644
--- a/packages/SystemUI/src/com/android/systemui/usb/UsbConfirmActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/usb/UsbConfirmActivity.java
@@ -71,6 +71,7 @@ public class UsbConfirmActivity extends AlertActivity
final AlertController.AlertParams ap = mAlertParams;
ap.mTitle = appName;
+ boolean useRecordWarning = false;
if (mDevice == null) {
ap.mMessage = getString(R.string.usb_accessory_confirm_prompt, appName,
mAccessory.getDescription());
@@ -83,7 +84,7 @@ public class UsbConfirmActivity extends AlertActivity
packageName)
== android.content.pm.PackageManager.PERMISSION_GRANTED;
boolean isAudioCaptureDevice = mDevice.getHasAudioCapture();
- boolean useRecordWarning = isAudioCaptureDevice && !hasRecordPermission;
+ useRecordWarning = isAudioCaptureDevice && !hasRecordPermission;
int strID = useRecordWarning
? R.string.usb_device_confirm_prompt_warn
@@ -98,22 +99,23 @@ public class UsbConfirmActivity extends AlertActivity
ap.mNegativeButtonListener = this;
// add "always use" checkbox
- LayoutInflater inflater = (LayoutInflater)getSystemService(
- Context.LAYOUT_INFLATER_SERVICE);
- ap.mView = inflater.inflate(com.android.internal.R.layout.always_use_checkbox, null);
- mAlwaysUse = (CheckBox)ap.mView.findViewById(com.android.internal.R.id.alwaysUse);
- if (mDevice == null) {
- mAlwaysUse.setText(getString(R.string.always_use_accessory, appName,
- mAccessory.getDescription()));
- } else {
- mAlwaysUse.setText(getString(R.string.always_use_device, appName,
- mDevice.getProductName()));
+ if (!useRecordWarning) {
+ LayoutInflater inflater = (LayoutInflater) getSystemService(
+ Context.LAYOUT_INFLATER_SERVICE);
+ ap.mView = inflater.inflate(com.android.internal.R.layout.always_use_checkbox, null);
+ mAlwaysUse = (CheckBox) ap.mView.findViewById(com.android.internal.R.id.alwaysUse);
+ if (mDevice == null) {
+ mAlwaysUse.setText(getString(R.string.always_use_accessory, appName,
+ mAccessory.getDescription()));
+ } else {
+ mAlwaysUse.setText(getString(R.string.always_use_device, appName,
+ mDevice.getProductName()));
+ }
+ mAlwaysUse.setOnCheckedChangeListener(this);
+ mClearDefaultHint = (TextView) ap.mView.findViewById(
+ com.android.internal.R.id.clearDefaultHint);
+ mClearDefaultHint.setVisibility(View.GONE);
}
- mAlwaysUse.setOnCheckedChangeListener(this);
- mClearDefaultHint = (TextView)ap.mView.findViewById(
- com.android.internal.R.id.clearDefaultHint);
- mClearDefaultHint.setVisibility(View.GONE);
-
setupAlert();
}
@@ -133,7 +135,7 @@ public class UsbConfirmActivity extends AlertActivity
IUsbManager service = IUsbManager.Stub.asInterface(b);
final int uid = mResolveInfo.activityInfo.applicationInfo.uid;
final int userId = UserHandle.myUserId();
- boolean alwaysUse = mAlwaysUse.isChecked();
+ boolean alwaysUse = mAlwaysUse != null ? mAlwaysUse.isChecked() : false;
Intent intent = null;
if (mDevice != null) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java b/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java
index e8f19238fdb8..167f361b341a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java
@@ -48,6 +48,7 @@ import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.power.PowerUI.WarningsUI;
+import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.phone.StatusBar;
import org.junit.Before;
@@ -87,6 +88,7 @@ public class PowerUITest extends SysuiTestCase {
private IThermalEventListener mUsbThermalEventListener;
private IThermalEventListener mSkinThermalEventListener;
@Mock private BroadcastDispatcher mBroadcastDispatcher;
+ @Mock private CommandQueue mCommandQueue;
@Mock private Lazy<StatusBar> mStatusBarLazy;
@Mock private StatusBar mStatusBar;
@@ -686,7 +688,7 @@ public class PowerUITest extends SysuiTestCase {
}
private void createPowerUi() {
- mPowerUI = new PowerUI(mContext, mBroadcastDispatcher, mStatusBarLazy);
+ mPowerUI = new PowerUI(mContext, mBroadcastDispatcher, mCommandQueue, mStatusBarLazy);
mPowerUI.mThermalService = mThermalServiceMock;
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotNotificationSmartActionsTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotNotificationSmartActionsTest.java
index 3f32c66b2d03..6d85d37537ea 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotNotificationSmartActionsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotNotificationSmartActionsTest.java
@@ -175,7 +175,7 @@ public class ScreenshotNotificationSmartActionsTest extends SysuiTestCase {
data.image = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888);
data.iconSize = 10;
data.finisher = null;
- data.onEditReady = null;
+ data.mActionsReadyListener = null;
data.previewWidth = 10;
data.previewheight = 10;
SaveImageInBackgroundTask task = new SaveImageInBackgroundTask(mContext, data,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java
index 2068f7ccc3ca..dfd994139af8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java
@@ -40,6 +40,7 @@ import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper;
import com.android.systemui.statusbar.policy.ConfigurationController;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -125,6 +126,7 @@ public class HeadsUpManagerPhoneTest extends AlertingNotificationManagerTest {
assertTrue(mHeadsUpManager.canRemoveImmediately(mEntry.getKey()));
}
+ @Ignore("b/141538055")
@Test
public void testCanRemoveImmediately_notTopEntry() {
NotificationEntry laterEntry = new NotificationEntryBuilder()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HotspotControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HotspotControllerImplTest.java
index 811e6a06e607..631c580a490d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HotspotControllerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HotspotControllerImplTest.java
@@ -77,7 +77,6 @@ public class HotspotControllerImplTest extends SysuiTestCase {
any(WifiManager.SoftApCallback.class));
mController = new HotspotControllerImpl(mContext, new Handler(mLooper.getLooper()));
- mController.handleSetListening(true);
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeHotspotController.java b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeHotspotController.java
index c9681ac558f9..016160aea433 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeHotspotController.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeHotspotController.java
@@ -26,10 +26,6 @@ public class FakeHotspotController extends BaseLeakChecker<Callback> implements
}
@Override
- public void handleSetListening(boolean listening) {
- }
-
- @Override
public boolean isHotspotEnabled() {
return false;
}
diff --git a/packages/Tethering/Android.bp b/packages/Tethering/Android.bp
index 7b35f4d56a7a..7e8721d3cc70 100644
--- a/packages/Tethering/Android.bp
+++ b/packages/Tethering/Android.bp
@@ -22,13 +22,12 @@ java_defaults {
":framework-tethering-shared-srcs",
":net-module-utils-srcs",
":services-tethering-shared-srcs",
- ":servicescore-tethering-src",
],
static_libs: [
"androidx.annotation_annotation",
- "netd_aidl_interface-java",
+ "netd_aidl_interface-unstable-java",
"netlink-client",
- "networkstack-aidl-interfaces-java",
+ "networkstack-aidl-interfaces-unstable-java",
"android.hardware.tetheroffload.control-V1.0-java",
"tethering-client",
],
@@ -41,20 +40,26 @@ android_library {
defaults: ["TetheringAndroidLibraryDefaults"],
}
-cc_library_shared {
+// Due to b/143733063, APK can't access a jni lib that is in APEX (but not in the APK).
+cc_library {
name: "libtetheroffloadjni",
srcs: [
"jni/com_android_server_connectivity_tethering_OffloadHardwareInterface.cpp",
],
shared_libs: [
- "libnativehelper",
- "libcutils",
- "android.hardware.tetheroffload.config@1.0",
+ "libcgrouprc",
+ "libnativehelper_compat_libc++",
+ "libvndksupport",
],
static_libs: [
+ "android.hardware.tetheroffload.config@1.0",
"liblog",
"libbase",
+ "libbinderthreadstate",
+ "libcutils",
"libhidlbase",
+ "libjsoncpp",
+ "libprocessgroup",
"libutils",
],
@@ -64,6 +69,8 @@ cc_library_shared {
"-Wno-unused-parameter",
"-Wthread-safety",
],
+
+ ldflags: ["-Wl,--exclude-libs=ALL,-error-limit=0"],
}
// Common defaults for compiling the actual APK.
@@ -71,7 +78,12 @@ java_defaults {
name: "TetheringAppDefaults",
platform_apis: true,
privileged: true,
+ // Build system doesn't track transitive dependeicies for jni_libs, list all the dependencies
+ // explicitly.
jni_libs: [
+ "libcgrouprc",
+ "libnativehelper_compat_libc++",
+ "libvndksupport",
"libtetheroffloadjni",
],
resource_dirs: [
@@ -83,7 +95,16 @@ java_defaults {
}
// Non-updatable tethering running in the system server process for devices not using the module
-// TODO: build in-process tethering APK here.
+android_app {
+ name: "InProcessTethering",
+ defaults: ["TetheringAppDefaults"],
+ static_libs: ["TetheringApiCurrentLib"],
+ certificate: "platform",
+ manifest: "AndroidManifest_InProcess.xml",
+ // InProcessTethering is a replacement for Tethering
+ overrides: ["Tethering"],
+ // TODO: use PlatformNetworkPermissionConfig.
+}
// Updatable tethering packaged as an application
android_app {
@@ -96,36 +117,3 @@ android_app {
// The permission configuration *must* be included to ensure security of the device
required: ["NetworkPermissionConfig"],
}
-
-// This group will be removed when tethering migration is done.
-filegroup {
- name: "tethering-servicescore-srcs",
- srcs: [
- "src/com/android/server/connectivity/tethering/EntitlementManager.java",
- "src/com/android/server/connectivity/tethering/OffloadController.java",
- "src/com/android/server/connectivity/tethering/OffloadHardwareInterface.java",
- "src/com/android/server/connectivity/tethering/TetheringConfiguration.java",
- "src/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java",
- ],
-}
-
-// This group will be removed when tethering migration is done.
-filegroup {
- name: "tethering-servicesnet-srcs",
- srcs: [
- "src/android/net/dhcp/DhcpServerCallbacks.java",
- "src/android/net/dhcp/DhcpServingParamsParcelExt.java",
- "src/android/net/ip/IpServer.java",
- "src/android/net/ip/RouterAdvertisementDaemon.java",
- "src/android/net/util/InterfaceSet.java",
- "src/android/net/util/PrefixUtils.java",
- ],
-}
-
-// This group would be removed when tethering migration is done.
-filegroup {
- name: "tethering-jni-srcs",
- srcs: [
- "jni/com_android_server_connectivity_tethering_OffloadHardwareInterface.cpp",
- ],
-}
diff --git a/packages/Tethering/AndroidManifest.xml b/packages/Tethering/AndroidManifest.xml
index eb51593e4538..1430ed00aa91 100644
--- a/packages/Tethering/AndroidManifest.xml
+++ b/packages/Tethering/AndroidManifest.xml
@@ -25,5 +25,11 @@
android:process="com.android.networkstack.process"
android:extractNativeLibs="false"
android:persistent="true">
+ <service android:name="com.android.server.connectivity.tethering.TetheringService"
+ android:permission="android.permission.MAINLINE_NETWORK_STACK">
+ <intent-filter>
+ <action android:name="android.net.ITetheringConnector"/>
+ </intent-filter>
+ </service>
</application>
</manifest>
diff --git a/packages/Tethering/AndroidManifest_InProcess.xml b/packages/Tethering/AndroidManifest_InProcess.xml
new file mode 100644
index 000000000000..28d405c3133a
--- /dev/null
+++ b/packages/Tethering/AndroidManifest_InProcess.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.tethering.inprocess"
+ android:sharedUserId="android.uid.system"
+ android:process="system">
+ <uses-sdk android:minSdkVersion="29" android:targetSdkVersion="29" />
+ <application>
+ <!-- TODO: Using MAINLINE_NETWORK_STACK instead of NETWORK_STACK when tethering run in the
+ same process with networkstack -->
+ <service android:name="com.android.server.connectivity.tethering.TetheringService"
+ android:process="system"
+ android:permission="android.permission.NETWORK_STACK">
+ <intent-filter>
+ <action android:name="android.net.ITetheringConnector.InProcess"/>
+ </intent-filter>
+ </service>
+ </application>
+</manifest>
diff --git a/packages/Tethering/CleanSpec.mk b/packages/Tethering/CleanSpec.mk
new file mode 100644
index 000000000000..70db351a6928
--- /dev/null
+++ b/packages/Tethering/CleanSpec.mk
@@ -0,0 +1,52 @@
+# Copyright (C) 2019 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# If you don't need to do a full clean build but would like to touch
+# a file or delete some intermediate files, add a clean step to the end
+# of the list. These steps will only be run once, if they haven't been
+# run before.
+#
+# E.g.:
+# $(call add-clean-step, touch -c external/sqlite/sqlite3.h)
+# $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libz_intermediates)
+#
+# Always use "touch -c" and "rm -f" or "rm -rf" to gracefully deal with
+# files that are missing or have been moved.
+#
+# Use $(PRODUCT_OUT) to get to the "out/target/product/blah/" directory.
+# Use $(OUT_DIR) to refer to the "out" directory.
+#
+# If you need to re-do something that's already mentioned, just copy
+# the command and add it to the bottom of the list. E.g., if a change
+# that you made last week required touching a file and a change you
+# made today requires touching the same file, just copy the old
+# touch step and add it to the end of the list.
+#
+# *****************************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST ABOVE THE BANNER
+# *****************************************************************
+
+# For example:
+#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/AndroidTests_intermediates)
+#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/core_intermediates)
+#$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f)
+#$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*)
+
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/priv-app/Tethering)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/priv-app/InProcessTethering)
+
+# ******************************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST ABOVE THIS BANNER
+# ******************************************************************
diff --git a/packages/Tethering/apex/Android.bp b/packages/Tethering/apex/Android.bp
new file mode 100644
index 000000000000..bca01ebdf819
--- /dev/null
+++ b/packages/Tethering/apex/Android.bp
@@ -0,0 +1,35 @@
+//
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+apex {
+ name: "com.android.tethering.apex",
+ apps: ["Tethering"],
+ manifest: "manifest.json",
+ key: "com.android.tethering.apex.key",
+
+ androidManifest: "AndroidManifest.xml",
+}
+
+apex_key {
+ name: "com.android.tethering.apex.key",
+ public_key: "com.android.tethering.apex.avbpubkey",
+ private_key: "com.android.tethering.apex.pem",
+}
+
+android_app_certificate {
+ name: "com.android.tethering.apex.certificate",
+ certificate: "com.android.tethering.apex",
+}
diff --git a/packages/Tethering/apex/AndroidManifest.xml b/packages/Tethering/apex/AndroidManifest.xml
new file mode 100644
index 000000000000..7769b799b6f9
--- /dev/null
+++ b/packages/Tethering/apex/AndroidManifest.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.tethering.apex">
+ <!-- APEX does not have classes.dex -->
+ <application android:hasCode="false" />
+ <!-- b/145383354: Current minSdk is locked to Q for development cycle, lock it to next version
+ before ship. -->
+ <uses-sdk
+ android:minSdkVersion="29"
+ android:targetSdkVersion="29"
+ />
+</manifest>
diff --git a/packages/Tethering/apex/com.android.tethering.apex.avbpubkey b/packages/Tethering/apex/com.android.tethering.apex.avbpubkey
new file mode 100644
index 000000000000..9c8711161547
--- /dev/null
+++ b/packages/Tethering/apex/com.android.tethering.apex.avbpubkey
Binary files differ
diff --git a/packages/Tethering/apex/com.android.tethering.apex.pem b/packages/Tethering/apex/com.android.tethering.apex.pem
new file mode 100644
index 000000000000..a8cd12e92e8d
--- /dev/null
+++ b/packages/Tethering/apex/com.android.tethering.apex.pem
@@ -0,0 +1,51 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIJKQIBAAKCAgEAwloHpMmwszNBEgUVion141BTvF/oJ5g5DlQIYBtmht4tSpc3
+6elWXd+dhMzFxf/RkxSNRsU+dhD11cPKGp9nUYQQGrHEf3xEKwAHJKRMq26TkJ3o
+1TwOO70TaRKKA4ThNiM3VFDX2vy1ijArhZDIBTGVJCUl9HOHiO+ZJG5DKCx3KXbO
+QWz3c+Lbprr1L76dwIsl5kuoAFwgG0J+9BZhHEzIG1lVpGG7RRLxc8eDIxNN/oKT
+gPYBcOxFYqOECKGBBvElf6MxdRv6xG7gooALY2/HDMYUjAJSOosfwzeymugCzMhK
+e+6CSTAaEfUzuVZvMc2qnd1ly7zpLo9x+TOdH5LEVZpSwqmu2n5bqrUnSEAJUvMz
+SSw0YbsLWJZuTiTV7lecSITgqsmwuZyDexDmUkDQChzrTixsQV6S8vsh/FanjWoi
+zBlPneX8Q7/LME3hxHyLbrabxX0zWiyj8iM9h/8Y4mpO/MjEmmavglTAP4J8zrKD
+FBsntCoch9I49IpYBuO6NfKw1h7AUpLf8gARAjFjRxiJVcSgGY/Wt4/pBzJ57T5g
+xPvqxfpPQP0OA2CT8LqqzZIR8jXs8/TquvwLkkY2kRRPXx+azd5oU2A0uonrUY31
+Bc1obfmWPuEMz9bO/i06ETHuWPd4RiUNaB8qEmjYuKJfhv72YNcRwhrAYJECAwEA
+AQKCAgAaQn3b5yCH5fn5zFQPxvpBP35A6ph8mRXEeNg03B7rRCPMe0gjw9JWlrs6
+0Uw7p4gSnmlEUaxR2ZLN0kmBdV5JZlWitbg+HXU8diGA8u4lD6jCloN6JEYsDi0M
+OmQJe6/OV83HB7FStmh1BnMq9dgA06U6IAbT07RRbUY85OUQDYoAQTw3HNkGgHV7
+PrGYROIdvO9fAYPuoIP6Cu8KXee7Iii7gUOQFWBvQdL7+M4gNCCKrevuNc8WCeaK
+IFvbqq67WGPfrhYlo6UrW2vgqPpg8h5r/GuUS0/+9wNQpjrssUKHltxxiFV0PBqZ
+qI7XkPUvPoG6GMsDT0AWeW1F5ZJqEGPN67Xek0BCD0cpUli+nHD0yWGVHtkpHU2D
+qUOZdB2COfBuXRdW1LsYNPg8YjTCPsmGhISLTwiTNcZJeTxoK1y0CcVW9d7Af2aD
+lYzCegscQlXkSZiFj9s90Vd3KdD2XKrH/ADxzsOxQJ89ka004efdQa5/MKs9aChG
+/5XrwBEfN4O92OjY7KqXUAwB7CcVzNymOjD6r07LM24zbkRpwwXlkP0wmjsHBXkh
+8p0ISmY9QRdvhBgYmFmoPWZncM0zym9LI8atBs4CijQ7JjuOQ8HgHg+Se2eppWfe
+t8r6TVkDB8JeNAMxjX9q0G7icf3JjlIrgERZfyXLmpduR9NdkQKCAQEA5rp2fSKh
+RwihHNtJhNktFJuLR9OA++vyfjqhWnB8CrLPo3//LGWW/+WBr8EwXi/76hQpeKlf
+u8SmkTtxIHlTP2Brh2koh1Qf8HKzPHGjZeDFOoVPKHPqe3nV+cv3srd1mS0Eq3BA
+ZFQq+l61f2iiTZKxDroCahNEa8VMzirW6nKb5xhyMPHXgncCUdphHbwAGatas6be
+RUFg4ChH8BwX6jYw7leRUy2K6OqEl0fckT4Laitlb/ezKtwmD4PPE95q5hH0v3SO
+wetHWafiNrOXPn2wQqBrI2y+AfbTjNmQiaIPgcFKAQ7V3n+c3XfGZ9Xfv4L8m/wo
+RZ4ika1zur021QKCAQEA16OUBPA7BnWd+RJFri2kJBG5JZElaV9chO2ZHcXUbFR9
+HIPkWN19bJbki8Ca0w8FUQuS/M7JeeFjoZ194NlczbR899GVmb0X2AUKXilMacs3
+IONxIDczx3KFtsge8ewXRAjQvgE7M3NpmmJfPLPog7spMCbUIxbc3jzjiZgB/J1s
+WytlUTUY/Zy4V1wujkoydgK2KcHcEWG2oIy7EP0RwnL1NhTksXOtBH6+MoRMAT+H
+fcBK6yfJBNBRQzJ0PdkCCLdQPN1VtwRlWjPXZ3ey4fWvZ399wSLUkM2V1jB4GcOZ
++DAgtwFKs9+HfOdV42GgFWFcjP+bkM3bcdrQFnmYzQKCAQAQnf1KpePXqddwrJpu
+5vVINquhUKpJeoTMcoyMZu2IF7i8nctS9z4Yz/63GcLSBcKu6STTe99ZNqCIdS+A
+lzxXpCoaZoh0tqpWNuyRvd12yOlrfY5l63NH0U6H3xjH1k6x6XwcnMkGcMlnnsqT
+koWd8KKv3NWvrhOPb3ZIou03lWmFC02uGLzcuJWCL6gu7AtVzfGKXspDUqIXgs8r
+i9ptE9oSUFw3EWCfxcQm4RYRn9ZSny1/EufkflZ/Z47Sb4Jjb4ehAlQFw1wwKNcx
++V07MvIu2j7dHkfQ/GXgDwtJ3lIfljwuN1NP4wD5Mlcnw0+KC3UGBvMfkHQM6eEb
+4eTBAoIBAQDWfZsqHlpX3n431XkB+9wdFJP5ThrMaVJ51mxLNRBKgO/BgV+NFSNA
+9AZ5DCf0cCh1qPGYDYhSd2LGywT+trac1j7Hse0AcxpYgQsDBkk/oic/y3wm80HJ
+zZw7Z2uAb7nkrnATzt24G8CbE+ZvVvScs3oQr06raH5hgGdD4bN4No4lUVECKbKl
+8VFbdBHK7vqqb6AKgQ4JLAygPduE1nTn2bkXBklESS98HSXK0dVYGH0JFFBw/63v
+39Y05ObC7iwbx1tEb1RnKzQ1OQO1o1aHc/35ENNhXOfa8ONtneCYn/ty50xjPCG2
+MU1vbBv+hIjbO3D3vvhaXKk+4svAz0qxAoIBAQC84FJEjKHJHx17jLeoTuDfuxwX
+6bOQrI3nHbtnFRvPrMryWRDtHLv89Zma3o68/n4vTn5+AnvgYMZifOYlTlIPxinH
+tlE+qCD8KBXUlZdrc+5GGM18lp5tF3Ro4LireH+OhiOAWawaSzDIDYdiR6Kz9NU+
+SjcHKjDObeM6iMEukoaRsufMedpUSrnbzMraAJgBZGay1NZs/o8Icl3OySYPZWEK
+MJxVBMXU9QcUp2GEioYd/eNuP9rwyjq/EIUDJbP2vESAe6+FdGbIgvyYTV/gnKaH
+GcvyMNVZbCMp/wCYNonjlu+18m2w+pVs2uuZLqORkrKYhisK83TKxh4YOWJh
+-----END RSA PRIVATE KEY-----
diff --git a/packages/Tethering/apex/com.android.tethering.apex.pk8 b/packages/Tethering/apex/com.android.tethering.apex.pk8
new file mode 100644
index 000000000000..56632462941f
--- /dev/null
+++ b/packages/Tethering/apex/com.android.tethering.apex.pk8
Binary files differ
diff --git a/packages/Tethering/apex/com.android.tethering.apex.x509.pem b/packages/Tethering/apex/com.android.tethering.apex.x509.pem
new file mode 100644
index 000000000000..a5e94011f7c5
--- /dev/null
+++ b/packages/Tethering/apex/com.android.tethering.apex.x509.pem
@@ -0,0 +1,36 @@
+-----BEGIN CERTIFICATE-----
+MIIGMzCCBBugAwIBAgIUXVtoDaXanhs7ma8VIICambMkj5UwDQYJKoZIhvcNAQEL
+BQAwgacxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQH
+DA1Nb3VudGFpbiBWaWV3MRAwDgYDVQQKDAdBbmRyb2lkMRAwDgYDVQQLDAdBbmRy
+b2lkMSMwIQYDVQQDDBpjb20uYW5kcm9pZC50ZXRoZXJpbmcuYXBleDEiMCAGCSqG
+SIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTAgFw0xOTExMjgwNjU4MTRaGA80
+NzU3MTAyNDA2NTgxNFowgacxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9y
+bmlhMRYwFAYDVQQHDA1Nb3VudGFpbiBWaWV3MRAwDgYDVQQKDAdBbmRyb2lkMRAw
+DgYDVQQLDAdBbmRyb2lkMSMwIQYDVQQDDBpjb20uYW5kcm9pZC50ZXRoZXJpbmcu
+YXBleDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTCCAiIwDQYJ
+KoZIhvcNAQEBBQADggIPADCCAgoCggIBANwzufMBdOj9XlNwiX+bXl/94G0DklWW
+nzob0jPlubCFfRqYkjCf2eOd28Mu/O1pOBcvobnrs9OTpGzcHkz2h58L5/0UMVTS
+tBugwCE49XF5FHawqVHNZE+s5tDmnp2cufhNc5HXHY4oZKh80/WVdbcKxiLjSY2T
+PgRAfB6E6XByKD3t1cSsc3liRVKADoJOVDvmF+xnyvSV/SN38bvTQk9aVs95mj0W
+yov6gzXBnqN7iQlvkhcijZBnFWxvoNbJ5KFy1abYOrm+ueXje4BcNhVOeRMb4E9N
+eo7+9k1GEI7TYG7laNNcp7UJ1IXCJzv/wBFKRg3f1HB3unKfx2rtKerDnVsr3o7V
+KProkgRNKNhhQ6opNguiH1YMzKpWMaC988n4AQPryPdIOmVIxIC5jJrixdxgzDXT
+qeiwFiXis291uyls08B03PQFlY9oWaY9P8s+4hIUjB6rLl+XZXsLDtDFxXeJ97NB
+8XZN1gBJoBoLknFs0C4LKpmJZB/EBao9tXV9dL/5lydRo6HzQDpjW8QX06CTUM6z
+Lr3LVelhqbsuZsV42yBKl+/LfrvNjBLEPdSevt2oMrlJW7m4iSNaMtDtJ2Oy8fA5
+WSIgLWuMbkaFDza3JzwiMzxbtbJHYiy6rY7aVywo3Vqwr1+KO3cq4eLQq62zUjRY
+e6KJwvgE2YmpAgMBAAGjUzBRMB0GA1UdDgQWBBQ8h1oF5JfKFmJCN8nfimbUK+IR
+wjAfBgNVHSMEGDAWgBQ8h1oF5JfKFmJCN8nfimbUK+IRwjAPBgNVHRMBAf8EBTAD
+AQH/MA0GCSqGSIb3DQEBCwUAA4ICAQAP5hIkAxSyt9hRafMKiFlmXcL277bgoxNd
+qGZYbdcCFjfvM2r0QQcM/K7x2ZslFe7mJSzcyMifpm4YQTEo2yYbzKItXQV+eV1K
+9RNksRGFG9umsdWaSHhfQmcmxtr2nu9rGAgxy5OQFtyXmJPUPEM2cb/YeILwYhuQ
+Ux3kaj/fxGltX1JBag7HnMzCTZK++fRo5nqFVOJQgJH8ZpuzGeM9kZvP1+b55046
+PhSnlqmZoKhG4i5POPvvZvaakh/lM3x/N7lIlSaQpCGf7jmldni4L0/GenULVKzH
+iN73aBfh4GEvE0HRcOoH3L7V6kc3WMMLve0chZBHpoVYbzUJEJOUL4yrmwEehqtf
+xm4vlYg3vqtcE3UnU/UGdMb16t77Nz88LlpBY5ierIt0jZMU0M81ppRhr1uiD2Lj
+091sEA0Bxcw/6Q8QNF2eR7SG7Qwipnms+lw6Vcxve+7DdTrdEA0k3XgpdXp8Ya+2
+PAp9SLVp1UHiGq3qD9Jvm34QmlUWAIUTHZs3DSgs1y3K5eyw/cnzTvUUOljc/n2y
+VF0FFZtJ1dVLrzQ80Ik7apEXpBqkgBGV04/L3QYk4C0/sP+1yk6zjeeeAvDtUcHS
+gLtjAfacQl/kwfVQWfrF7VByLcivApC6EUdvT3cURM5DfZRQ4RcKr1D61VYPnNRH
++/NVbMObwQ==
+-----END CERTIFICATE-----
diff --git a/packages/Tethering/apex/manifest.json b/packages/Tethering/apex/manifest.json
new file mode 100644
index 000000000000..3fb62f3405a3
--- /dev/null
+++ b/packages/Tethering/apex/manifest.json
@@ -0,0 +1,4 @@
+{
+ "name": "com.android.tethering.apex",
+ "version": 290000000
+}
diff --git a/packages/Tethering/common/TetheringLib/Android.bp b/packages/Tethering/common/TetheringLib/Android.bp
index 5b01b1e038c3..adc5a723a960 100644
--- a/packages/Tethering/common/TetheringLib/Android.bp
+++ b/packages/Tethering/common/TetheringLib/Android.bp
@@ -18,8 +18,12 @@
aidl_interface {
name: "tethering-aidl-interfaces",
local_include_dir: "src",
+ include_dirs: ["frameworks/base/core/java"], // For framework parcelables.
srcs: [
+ "src/android/net/ITetherInternalCallback.aidl",
"src/android/net/ITetheringConnector.aidl",
+ "src/android/net/TetheringConfigurationParcel.aidl",
+ "src/android/net/TetherStatesParcel.aidl",
],
backend: {
ndk: {
@@ -33,8 +37,15 @@ aidl_interface {
java_library {
name: "tethering-client",
- platform_apis: true,
+ sdk_version: "system_current",
static_libs: [
"tethering-aidl-interfaces-java",
],
}
+
+// This is temporary file group which would be removed after TetheringManager is built
+// into tethering-client. Will be done by aosp/1156906.
+filegroup {
+ name: "tethering-manager",
+ srcs: ["src/android/net/TetheringManager.java"],
+}
diff --git a/packages/Tethering/common/TetheringLib/src/android/net/ITetherInternalCallback.aidl b/packages/Tethering/common/TetheringLib/src/android/net/ITetherInternalCallback.aidl
new file mode 100644
index 000000000000..abb00e819f50
--- /dev/null
+++ b/packages/Tethering/common/TetheringLib/src/android/net/ITetherInternalCallback.aidl
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.net;
+
+import android.net.Network;
+import android.net.TetheringConfigurationParcel;
+import android.net.TetherStatesParcel;
+
+/**
+ * Callback class for receiving tethering changed events
+ * @hide
+ */
+oneway interface ITetherInternalCallback
+{
+ void onUpstreamChanged(in Network network);
+ void onConfigurationChanged(in TetheringConfigurationParcel config);
+ void onTetherStatesChanged(in TetherStatesParcel states);
+ void onCallbackCreated(in Network network, in TetheringConfigurationParcel config,
+ in TetherStatesParcel states);
+}
diff --git a/packages/Tethering/common/TetheringLib/src/android/net/ITetheringConnector.aidl b/packages/Tethering/common/TetheringLib/src/android/net/ITetheringConnector.aidl
index 443481e33f8d..bfe502fbeb11 100644
--- a/packages/Tethering/common/TetheringLib/src/android/net/ITetheringConnector.aidl
+++ b/packages/Tethering/common/TetheringLib/src/android/net/ITetheringConnector.aidl
@@ -15,6 +15,23 @@
*/
package android.net;
+import android.net.ITetherInternalCallback;
+import android.os.ResultReceiver;
+
/** @hide */
oneway interface ITetheringConnector {
+ void tether(String iface);
+
+ void untether(String iface);
+
+ void setUsbTethering(boolean enable);
+
+ void startTethering(int type, in ResultReceiver receiver, boolean showProvisioningUi);
+
+ void stopTethering(int type);
+
+ void requestLatestTetheringEntitlementResult(int type, in ResultReceiver receiver,
+ boolean showEntitlementUi);
+
+ void registerTetherInternalCallback(ITetherInternalCallback callback);
}
diff --git a/packages/Tethering/common/TetheringLib/src/android/net/TetherStatesParcel.aidl b/packages/Tethering/common/TetheringLib/src/android/net/TetherStatesParcel.aidl
new file mode 100644
index 000000000000..3d842b337428
--- /dev/null
+++ b/packages/Tethering/common/TetheringLib/src/android/net/TetherStatesParcel.aidl
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.net;
+
+/**
+ * Status details for tethering downstream interfaces.
+ * {@hide}
+ */
+parcelable TetherStatesParcel {
+ String[] availableList;
+ String[] tetheredList;
+ String[] localOnlyList;
+ String[] erroredIfaceList;
+ // List of Last error code corresponding to each errored iface in erroredIfaceList. */
+ // TODO: Improve this as b/143122247.
+ int[] lastErrorList;
+}
diff --git a/packages/Tethering/common/TetheringLib/src/android/net/TetheringConfigurationParcel.aidl b/packages/Tethering/common/TetheringLib/src/android/net/TetheringConfigurationParcel.aidl
new file mode 100644
index 000000000000..89f38132ffad
--- /dev/null
+++ b/packages/Tethering/common/TetheringLib/src/android/net/TetheringConfigurationParcel.aidl
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.net;
+
+/**
+ * Configuration details for tethering.
+ * @hide
+ */
+parcelable TetheringConfigurationParcel {
+ int subId;
+ String[] tetherableUsbRegexs;
+ String[] tetherableWifiRegexs;
+ String[] tetherableBluetoothRegexs;
+ boolean isDunRequired;
+ boolean chooseUpstreamAutomatically;
+ int[] preferredUpstreamIfaceTypes;
+ String[] legacyDhcpRanges;
+ String[] defaultIPv4DNS;
+ boolean enableLegacyDhcpServer;
+ String[] provisioningApp;
+ String provisioningAppNoUi;
+ int provisioningCheckPeriod;
+}
diff --git a/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java b/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java
new file mode 100644
index 000000000000..eb0d443f4bfc
--- /dev/null
+++ b/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java
@@ -0,0 +1,513 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.net;
+
+import static android.Manifest.permission.NETWORK_STACK;
+import static android.net.ConnectivityManager.TETHER_ERROR_NO_ERROR;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.net.util.SharedLog;
+import android.os.ConditionVariable;
+import android.os.IBinder;
+import android.os.RemoteCallbackList;
+import android.os.RemoteException;
+import android.os.ResultReceiver;
+import android.util.Slog;
+
+import com.android.internal.annotations.GuardedBy;
+
+import java.io.PrintWriter;
+import java.util.StringJoiner;
+
+/**
+ * Service used to communicate with the tethering, which is running in a separate module.
+ * @hide
+ */
+public class TetheringManager {
+ private static final String TAG = TetheringManager.class.getSimpleName();
+
+ private static TetheringManager sInstance;
+
+ @Nullable
+ private ITetheringConnector mConnector;
+ private TetherInternalCallback mCallback;
+ private Network mTetherUpstream;
+ private TetheringConfigurationParcel mTetheringConfiguration;
+ private TetherStatesParcel mTetherStatesParcel;
+
+ private final RemoteCallbackList<ITetheringEventCallback> mTetheringEventCallbacks =
+ new RemoteCallbackList<>();
+ @GuardedBy("mLog")
+ private final SharedLog mLog = new SharedLog(TAG);
+
+ private TetheringManager() { }
+
+ /**
+ * Get the TetheringManager singleton instance.
+ */
+ public static synchronized TetheringManager getInstance() {
+ if (sInstance == null) {
+ sInstance = new TetheringManager();
+ }
+ return sInstance;
+ }
+
+ private class TetheringConnection implements
+ ConnectivityModuleConnector.ModuleServiceCallback {
+ @Override
+ public void onModuleServiceConnected(@NonNull IBinder service) {
+ logi("Tethering service connected");
+ registerTetheringService(service);
+ }
+ }
+
+ private void registerTetheringService(@NonNull IBinder service) {
+ final ITetheringConnector connector = ITetheringConnector.Stub.asInterface(service);
+
+ log("Tethering service registered");
+
+ // Currently TetheringManager instance is only used by ConnectivityService and mConnector
+ // only expect to assign once when system server start and bind tethering service.
+ // STOPSHIP: Change mConnector to final before TetheringManager put into boot classpath.
+ mConnector = connector;
+ mCallback = new TetherInternalCallback();
+ try {
+ mConnector.registerTetherInternalCallback(mCallback);
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ }
+
+ private class TetherInternalCallback extends ITetherInternalCallback.Stub {
+ private final ConditionVariable mWaitForCallback = new ConditionVariable(false);
+ private static final int EVENT_CALLBACK_TIMEOUT_MS = 60_000;
+
+ @Override
+ public void onUpstreamChanged(Network network) {
+ mTetherUpstream = network;
+ reportUpstreamChanged(network);
+ }
+
+ @Override
+ public void onConfigurationChanged(TetheringConfigurationParcel config) {
+ mTetheringConfiguration = config;
+ }
+
+ @Override
+ public void onTetherStatesChanged(TetherStatesParcel states) {
+ mTetherStatesParcel = states;
+ }
+
+ @Override
+ public void onCallbackCreated(Network network, TetheringConfigurationParcel config,
+ TetherStatesParcel states) {
+ mTetherUpstream = network;
+ mTetheringConfiguration = config;
+ mTetherStatesParcel = states;
+ mWaitForCallback.open();
+ }
+
+ boolean awaitCallbackCreation() {
+ return mWaitForCallback.block(EVENT_CALLBACK_TIMEOUT_MS);
+ }
+ }
+
+ private void reportUpstreamChanged(Network network) {
+ final int length = mTetheringEventCallbacks.beginBroadcast();
+ try {
+ for (int i = 0; i < length; i++) {
+ try {
+ mTetheringEventCallbacks.getBroadcastItem(i).onUpstreamChanged(network);
+ } catch (RemoteException e) {
+ // Not really very much to do here.
+ }
+ }
+ } finally {
+ mTetheringEventCallbacks.finishBroadcast();
+ }
+ }
+
+ /**
+ * Start the tethering service. Should be called only once on device startup.
+ *
+ * <p>This method will start the tethering service either in the network stack process,
+ * or inside the system server on devices that do not support the tethering module.
+ *
+ * {@hide}
+ */
+ public void start() {
+ // Using MAINLINE_NETWORK_STACK permission after cutting off the dpendency of system server.
+ ConnectivityModuleConnector.getInstance().startModuleService(
+ ITetheringConnector.class.getName(), NETWORK_STACK,
+ new TetheringConnection());
+ log("Tethering service start requested");
+ }
+
+ /**
+ * Attempt to tether the named interface. This will setup a dhcp server
+ * on the interface, forward and NAT IP v4 packets and forward DNS requests
+ * to the best active upstream network interface. Note that if no upstream
+ * IP network interface is available, dhcp will still run and traffic will be
+ * allowed between the tethered devices and this device, though upstream net
+ * access will of course fail until an upstream network interface becomes
+ * active. Note: return value do not have any meaning. It is better to use
+ * #getTetherableIfaces() to ensure corresponding interface is available for
+ * tethering before calling #tether().
+ *
+ * @deprecated The only usages should be in PanService and Wifi P2P which
+ * need direct access.
+ *
+ * {@hide}
+ */
+ @Deprecated
+ public int tether(@NonNull String iface) {
+ try {
+ mConnector.tether(iface);
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ return TETHER_ERROR_NO_ERROR;
+ }
+
+ /**
+ * Stop tethering the named interface.
+ *
+ * @deprecated
+ * {@hide}
+ */
+ @Deprecated
+ public int untether(@NonNull String iface) {
+ try {
+ mConnector.untether(iface);
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ return TETHER_ERROR_NO_ERROR;
+ }
+
+ /**
+ * Attempt to both alter the mode of USB and Tethering of USB. WARNING: New client should not
+ * use this API anymore. All clients should use #startTethering or #stopTethering which
+ * encapsulate proper entitlement logic. If the API is used and an entitlement check is needed,
+ * downstream USB tethering will be enabled but will not have any upstream.
+ *
+ * @deprecated
+ * {@hide}
+ */
+ @Deprecated
+ public int setUsbTethering(boolean enable) {
+ try {
+ mConnector.setUsbTethering(enable);
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ return TETHER_ERROR_NO_ERROR;
+ }
+
+ /**
+ * Starts tethering and runs tether provisioning for the given type if needed. If provisioning
+ * fails, stopTethering will be called automatically.
+ *
+ * {@hide}
+ */
+ // TODO: improve the usage of ResultReceiver, b/145096122
+ public void startTethering(int type, @NonNull ResultReceiver receiver,
+ boolean showProvisioningUi) {
+ try {
+ mConnector.startTethering(type, receiver, showProvisioningUi);
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Stops tethering for the given type. Also cancels any provisioning rechecks for that type if
+ * applicable.
+ *
+ * {@hide}
+ */
+ public void stopTethering(int type) {
+ try {
+ mConnector.stopTethering(type);
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Request the latest value of the tethering entitlement check.
+ *
+ * Note: Allow privileged apps who have TETHER_PRIVILEGED permission to access. If it turns
+ * out some such apps are observed to abuse this API, change to per-UID limits on this API
+ * if it's really needed.
+ */
+ // TODO: improve the usage of ResultReceiver, b/145096122
+ public void requestLatestTetheringEntitlementResult(int type, @NonNull ResultReceiver receiver,
+ boolean showEntitlementUi) {
+ try {
+ mConnector.requestLatestTetheringEntitlementResult(type, receiver, showEntitlementUi);
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Register tethering event callback.
+ *
+ * {@hide}
+ */
+ public void registerTetheringEventCallback(@NonNull ITetheringEventCallback callback) {
+ mTetheringEventCallbacks.register(callback);
+ }
+
+ /**
+ * Unregister tethering event callback.
+ *
+ * {@hide}
+ */
+ public void unregisterTetheringEventCallback(@NonNull ITetheringEventCallback callback) {
+ mTetheringEventCallbacks.unregister(callback);
+ }
+
+ /**
+ * Get a more detailed error code after a Tethering or Untethering
+ * request asynchronously failed.
+ *
+ * {@hide}
+ */
+ public int getLastTetherError(@NonNull String iface) {
+ if (!mCallback.awaitCallbackCreation()) {
+ throw new NullPointerException("callback was not ready yet");
+ }
+ if (mTetherStatesParcel == null) return TETHER_ERROR_NO_ERROR;
+
+ int i = 0;
+ for (String errored : mTetherStatesParcel.erroredIfaceList) {
+ if (iface.equals(errored)) return mTetherStatesParcel.lastErrorList[i];
+
+ i++;
+ }
+ return TETHER_ERROR_NO_ERROR;
+ }
+
+ /**
+ * Get the list of regular expressions that define any tetherable
+ * USB network interfaces. If USB tethering is not supported by the
+ * device, this list should be empty.
+ *
+ * {@hide}
+ */
+ public @NonNull String[] getTetherableUsbRegexs() {
+ if (!mCallback.awaitCallbackCreation()) {
+ throw new NullPointerException("callback was not ready yet");
+ }
+ return mTetheringConfiguration.tetherableUsbRegexs;
+ }
+
+ /**
+ * Get the list of regular expressions that define any tetherable
+ * Wifi network interfaces. If Wifi tethering is not supported by the
+ * device, this list should be empty.
+ *
+ * {@hide}
+ */
+ public @NonNull String[] getTetherableWifiRegexs() {
+ if (!mCallback.awaitCallbackCreation()) {
+ throw new NullPointerException("callback was not ready yet");
+ }
+ return mTetheringConfiguration.tetherableWifiRegexs;
+ }
+
+ /**
+ * Get the list of regular expressions that define any tetherable
+ * Bluetooth network interfaces. If Bluetooth tethering is not supported by the
+ * device, this list should be empty.
+ *
+ * {@hide}
+ */
+ public @NonNull String[] getTetherableBluetoothRegexs() {
+ if (!mCallback.awaitCallbackCreation()) {
+ throw new NullPointerException("callback was not ready yet");
+ }
+ return mTetheringConfiguration.tetherableBluetoothRegexs;
+ }
+
+ /**
+ * Get the set of tetherable, available interfaces. This list is limited by
+ * device configuration and current interface existence.
+ *
+ * {@hide}
+ */
+ public @NonNull String[] getTetherableIfaces() {
+ if (!mCallback.awaitCallbackCreation()) {
+ throw new NullPointerException("callback was not ready yet");
+ }
+ if (mTetherStatesParcel == null) return new String[0];
+ return mTetherStatesParcel.availableList;
+ }
+
+ /**
+ * Get the set of tethered interfaces.
+ *
+ * {@hide}
+ */
+ public @NonNull String[] getTetheredIfaces() {
+ if (!mCallback.awaitCallbackCreation()) {
+ throw new NullPointerException("callback was not ready yet");
+ }
+ if (mTetherStatesParcel == null) return new String[0];
+ return mTetherStatesParcel.tetheredList;
+ }
+
+ /**
+ * Get the set of interface names which attempted to tether but
+ * failed.
+ *
+ * {@hide}
+ */
+ public @NonNull String[] getTetheringErroredIfaces() {
+ if (!mCallback.awaitCallbackCreation()) {
+ throw new NullPointerException("callback was not ready yet");
+ }
+ if (mTetherStatesParcel == null) return new String[0];
+ return mTetherStatesParcel.erroredIfaceList;
+ }
+
+ /**
+ * Get the set of tethered dhcp ranges.
+ *
+ * @deprecated This API just return the default value which is not used in DhcpServer.
+ * {@hide}
+ */
+ @Deprecated
+ public @NonNull String[] getTetheredDhcpRanges() {
+ if (!mCallback.awaitCallbackCreation()) {
+ throw new NullPointerException("callback was not ready yet");
+ }
+ return mTetheringConfiguration.legacyDhcpRanges;
+ }
+
+ /**
+ * Check if the device allows for tethering.
+ *
+ * {@hide}
+ */
+ public boolean hasTetherableConfiguration() {
+ if (!mCallback.awaitCallbackCreation()) {
+ throw new NullPointerException("callback was not ready yet");
+ }
+ final boolean hasDownstreamConfiguration =
+ (mTetheringConfiguration.tetherableUsbRegexs.length != 0)
+ || (mTetheringConfiguration.tetherableWifiRegexs.length != 0)
+ || (mTetheringConfiguration.tetherableBluetoothRegexs.length != 0);
+ final boolean hasUpstreamConfiguration =
+ (mTetheringConfiguration.preferredUpstreamIfaceTypes.length != 0)
+ || mTetheringConfiguration.chooseUpstreamAutomatically;
+
+ return hasDownstreamConfiguration && hasUpstreamConfiguration;
+ }
+
+ /**
+ * Log a message in the local log.
+ */
+ private void log(@NonNull String message) {
+ synchronized (mLog) {
+ mLog.log(message);
+ }
+ }
+
+ /**
+ * Log a condition that should never happen.
+ */
+ private void logWtf(@NonNull String message, @Nullable Throwable e) {
+ Slog.wtf(TAG, message);
+ synchronized (mLog) {
+ mLog.e(message, e);
+ }
+ }
+
+ /**
+ * Log a ERROR level message in the local and system logs.
+ */
+ private void loge(@NonNull String message, @Nullable Throwable e) {
+ synchronized (mLog) {
+ mLog.e(message, e);
+ }
+ }
+
+ /**
+ * Log a INFO level message in the local and system logs.
+ */
+ private void logi(@NonNull String message) {
+ synchronized (mLog) {
+ mLog.i(message);
+ }
+ }
+
+ /**
+ * Dump TetheringManager logs to the specified {@link PrintWriter}.
+ */
+ public void dump(@NonNull PrintWriter pw) {
+ // dump is thread-safe on SharedLog
+ mLog.dump(null, pw, null);
+
+ pw.print("subId: ");
+ pw.println(mTetheringConfiguration.subId);
+
+ dumpStringArray(pw, "tetherableUsbRegexs",
+ mTetheringConfiguration.tetherableUsbRegexs);
+ dumpStringArray(pw, "tetherableWifiRegexs",
+ mTetheringConfiguration.tetherableWifiRegexs);
+ dumpStringArray(pw, "tetherableBluetoothRegexs",
+ mTetheringConfiguration.tetherableBluetoothRegexs);
+
+ pw.print("isDunRequired: ");
+ pw.println(mTetheringConfiguration.isDunRequired);
+
+ pw.print("chooseUpstreamAutomatically: ");
+ pw.println(mTetheringConfiguration.chooseUpstreamAutomatically);
+
+ dumpStringArray(pw, "legacyDhcpRanges", mTetheringConfiguration.legacyDhcpRanges);
+ dumpStringArray(pw, "defaultIPv4DNS", mTetheringConfiguration.defaultIPv4DNS);
+
+ dumpStringArray(pw, "provisioningApp", mTetheringConfiguration.provisioningApp);
+ pw.print("provisioningAppNoUi: ");
+ pw.println(mTetheringConfiguration.provisioningAppNoUi);
+
+ pw.print("enableLegacyDhcpServer: ");
+ pw.println(mTetheringConfiguration.enableLegacyDhcpServer);
+
+ pw.println();
+ }
+
+ private static void dumpStringArray(@NonNull PrintWriter pw, @NonNull String label,
+ @Nullable String[] values) {
+ pw.print(label);
+ pw.print(": ");
+
+ if (values != null) {
+ final StringJoiner sj = new StringJoiner(", ", "[", "]");
+ for (String value : values) sj.add(value);
+
+ pw.print(sj.toString());
+ } else {
+ pw.print("null");
+ }
+
+ pw.println();
+ }
+}
diff --git a/packages/Tethering/jni/com_android_server_connectivity_tethering_OffloadHardwareInterface.cpp b/packages/Tethering/jni/com_android_server_connectivity_tethering_OffloadHardwareInterface.cpp
index 3eaf48845a2f..663154a49048 100644
--- a/packages/Tethering/jni/com_android_server_connectivity_tethering_OffloadHardwareInterface.cpp
+++ b/packages/Tethering/jni/com_android_server_connectivity_tethering_OffloadHardwareInterface.cpp
@@ -145,4 +145,18 @@ int register_android_server_connectivity_tethering_OffloadHardwareInterface(JNIE
gMethods, NELEM(gMethods));
}
+extern "C" jint JNI_OnLoad(JavaVM* vm, void*) {
+ JNIEnv *env;
+ if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
+ ALOGE("ERROR: GetEnv failed");
+ return JNI_ERR;
+ }
+
+ if (register_android_server_connectivity_tethering_OffloadHardwareInterface(env) < 0) {
+ return JNI_ERR;
+ }
+
+ return JNI_VERSION_1_6;
+}
+
}; // namespace android
diff --git a/packages/Tethering/src/android/net/util/BaseNetdUnsolicitedEventListener.java b/packages/Tethering/src/android/net/util/BaseNetdUnsolicitedEventListener.java
new file mode 100644
index 000000000000..3218c0b387bb
--- /dev/null
+++ b/packages/Tethering/src/android/net/util/BaseNetdUnsolicitedEventListener.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.net.util;
+
+import android.net.INetdUnsolicitedEventListener;
+
+import androidx.annotation.NonNull;
+
+/**
+ * Base {@link INetdUnsolicitedEventListener} that provides no-op implementations which can be
+ * overridden.
+ */
+public class BaseNetdUnsolicitedEventListener extends INetdUnsolicitedEventListener.Stub {
+
+ @Override
+ public void onInterfaceClassActivityChanged(boolean isActive, int timerLabel, long timestampNs,
+ int uid) { }
+
+ @Override
+ public void onQuotaLimitReached(@NonNull String alertName, @NonNull String ifName) { }
+
+ @Override
+ public void onInterfaceDnsServerInfo(@NonNull String ifName, long lifetimeS,
+ @NonNull String[] servers) { }
+
+ @Override
+ public void onInterfaceAddressUpdated(@NonNull String addr, String ifName, int flags,
+ int scope) { }
+
+ @Override
+ public void onInterfaceAddressRemoved(@NonNull String addr, @NonNull String ifName, int flags,
+ int scope) { }
+
+ @Override
+ public void onInterfaceAdded(@NonNull String ifName) { }
+
+ @Override
+ public void onInterfaceRemoved(@NonNull String ifName) { }
+
+ @Override
+ public void onInterfaceChanged(@NonNull String ifName, boolean up) { }
+
+ @Override
+ public void onInterfaceLinkStateChanged(@NonNull String ifName, boolean up) { }
+
+ @Override
+ public void onRouteChanged(boolean updated, @NonNull String route, @NonNull String gateway,
+ @NonNull String ifName) { }
+
+ @Override
+ public void onStrictCleartextDetected(int uid, @NonNull String hex) { }
+
+ @Override
+ public int getInterfaceVersion() {
+ return INetdUnsolicitedEventListener.VERSION;
+ }
+}
diff --git a/services/net/java/android/net/util/VersionedBroadcastListener.java b/packages/Tethering/src/android/net/util/VersionedBroadcastListener.java
index 107c40495f9e..e2804abd752b 100644
--- a/services/net/java/android/net/util/VersionedBroadcastListener.java
+++ b/packages/Tethering/src/android/net/util/VersionedBroadcastListener.java
@@ -39,10 +39,6 @@ import java.util.function.Consumer;
public class VersionedBroadcastListener {
private static final boolean DBG = false;
- public interface IntentCallback {
- public void run(Intent intent);
- }
-
private final String mTag;
private final Context mContext;
private final Handler mHandler;
@@ -61,6 +57,7 @@ public class VersionedBroadcastListener {
mGenerationNumber = new AtomicInteger(0);
}
+ /** Start listening to intent broadcast. */
public void startListening() {
if (DBG) Log.d(mTag, "startListening");
if (mReceiver != null) return;
@@ -69,6 +66,7 @@ public class VersionedBroadcastListener {
mContext.registerReceiver(mReceiver, mFilter, null, mHandler);
}
+ /** Stop listening to intent broadcast. */
public void stopListening() {
if (DBG) Log.d(mTag, "stopListening");
if (mReceiver == null) return;
@@ -85,8 +83,7 @@ public class VersionedBroadcastListener {
// Used to verify this receiver is still current.
public final int generationNumber;
- public Receiver(
- String tag, AtomicInteger atomicGenerationNumber, Consumer<Intent> callback) {
+ Receiver(String tag, AtomicInteger atomicGenerationNumber, Consumer<Intent> callback) {
this.tag = tag;
this.atomicGenerationNumber = atomicGenerationNumber;
this.callback = callback;
@@ -98,8 +95,8 @@ public class VersionedBroadcastListener {
final int currentGenerationNumber = atomicGenerationNumber.get();
if (DBG) {
- Log.d(tag, "receiver generationNumber=" + generationNumber +
- ", current generationNumber=" + currentGenerationNumber);
+ Log.d(tag, "receiver generationNumber=" + generationNumber
+ + ", current generationNumber=" + currentGenerationNumber);
}
if (generationNumber != currentGenerationNumber) return;
diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/EntitlementManager.java b/packages/Tethering/src/com/android/server/connectivity/tethering/EntitlementManager.java
index 6b0f1de7ce85..ba5d08dce4ca 100644
--- a/packages/Tethering/src/com/android/server/connectivity/tethering/EntitlementManager.java
+++ b/packages/Tethering/src/com/android/server/connectivity/tethering/EntitlementManager.java
@@ -47,6 +47,7 @@ import android.os.Parcel;
import android.os.PersistableBundle;
import android.os.ResultReceiver;
import android.os.SystemClock;
+import android.os.SystemProperties;
import android.os.UserHandle;
import android.provider.Settings;
import android.telephony.CarrierConfigManager;
@@ -55,7 +56,6 @@ import android.util.SparseIntArray;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.StateMachine;
-import com.android.server.connectivity.MockableSystemProperties;
import java.io.PrintWriter;
@@ -94,7 +94,6 @@ public class EntitlementManager {
private final ArraySet<Integer> mCurrentTethers;
private final Context mContext;
private final int mPermissionChangeMessageCode;
- private final MockableSystemProperties mSystemProperties;
private final SharedLog mLog;
private final SparseIntArray mEntitlementCacheValue;
private final EntitlementHandler mHandler;
@@ -110,12 +109,12 @@ public class EntitlementManager {
private TetheringConfigurationFetcher mFetcher;
public EntitlementManager(Context ctx, StateMachine tetherMasterSM, SharedLog log,
- int permissionChangeMessageCode, MockableSystemProperties systemProperties) {
+ int permissionChangeMessageCode) {
+
mContext = ctx;
mLog = log.forSubComponent(TAG);
mCurrentTethers = new ArraySet<Integer>();
mCellularPermitted = new SparseIntArray();
- mSystemProperties = systemProperties;
mEntitlementCacheValue = new SparseIntArray();
mTetherMasterSM = tetherMasterSM;
mPermissionChangeMessageCode = permissionChangeMessageCode;
@@ -287,7 +286,7 @@ public class EntitlementManager {
*/
@VisibleForTesting
protected boolean isTetherProvisioningRequired(final TetheringConfiguration config) {
- if (mSystemProperties.getBoolean(DISABLE_PROVISIONING_SYSPROP_KEY, false)
+ if (SystemProperties.getBoolean(DISABLE_PROVISIONING_SYSPROP_KEY, false)
|| config.provisioningApp.length == 0) {
return false;
}
@@ -526,8 +525,8 @@ public class EntitlementManager {
handleMaybeRunProvisioning(config);
break;
case EVENT_GET_ENTITLEMENT_VALUE:
- handleGetLatestTetheringEntitlementValue(msg.arg1, (ResultReceiver) msg.obj,
- toBool(msg.arg2));
+ handleRequestLatestTetheringEntitlementValue(msg.arg1,
+ (ResultReceiver) msg.obj, toBool(msg.arg2));
break;
default:
mLog.log("Unknown event: " + msg.what);
@@ -651,15 +650,15 @@ public class EntitlementManager {
}
/** Get the last value of the tethering entitlement check. */
- public void getLatestTetheringEntitlementResult(int downstream, ResultReceiver receiver,
+ public void requestLatestTetheringEntitlementResult(int downstream, ResultReceiver receiver,
boolean showEntitlementUi) {
mHandler.sendMessage(mHandler.obtainMessage(EVENT_GET_ENTITLEMENT_VALUE,
downstream, encodeBool(showEntitlementUi), receiver));
}
- private void handleGetLatestTetheringEntitlementValue(int downstream, ResultReceiver receiver,
- boolean showEntitlementUi) {
+ private void handleRequestLatestTetheringEntitlementValue(int downstream,
+ ResultReceiver receiver, boolean showEntitlementUi) {
final TetheringConfiguration config = mFetcher.fetchTetheringConfiguration();
if (!isTetherProvisioningRequired(config)) {
receiver.send(TETHER_ERROR_NO_ERROR, null);
diff --git a/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringCoordinator.java b/packages/Tethering/src/com/android/server/connectivity/tethering/IPv6TetheringCoordinator.java
index 81863439c017..edfe3cad9039 100644
--- a/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringCoordinator.java
+++ b/packages/Tethering/src/com/android/server/connectivity/tethering/IPv6TetheringCoordinator.java
@@ -82,6 +82,7 @@ public class IPv6TetheringCoordinator {
mNextSubnetId = 0;
}
+ /** Add active downstream to ipv6 tethering candidate list. */
public void addActiveDownstream(IpServer downstream, int mode) {
if (findDownstream(downstream) == null) {
// Adding a new downstream appends it to the list. Adding a
@@ -97,6 +98,7 @@ public class IPv6TetheringCoordinator {
}
}
+ /** Remove downstream from ipv6 tethering candidate list. */
public void removeActiveDownstream(IpServer downstream) {
stopIPv6TetheringOn(downstream);
if (mActiveDownstreams.remove(findDownstream(downstream))) {
@@ -112,6 +114,11 @@ public class IPv6TetheringCoordinator {
}
}
+ /**
+ * Call when upstream NetworkState may be changed.
+ * If upstream has ipv6 for tethering, update this new NetworkState
+ * to IpServer. Otherwise stop ipv6 tethering on downstream interfaces.
+ */
public void updateUpstreamNetworkState(NetworkState ns) {
if (VDBG) {
Log.d(TAG, "updateUpstreamNetworkState: " + toDebugString(ns));
@@ -122,8 +129,8 @@ public class IPv6TetheringCoordinator {
return;
}
- if (mUpstreamNetworkState != null &&
- !ns.network.equals(mUpstreamNetworkState.network)) {
+ if (mUpstreamNetworkState != null
+ && !ns.network.equals(mUpstreamNetworkState.network)) {
stopIPv6TetheringOnAllInterfaces();
}
@@ -221,8 +228,8 @@ public class IPv6TetheringCoordinator {
for (RouteInfo routeInfo : lp.getRoutes()) {
final IpPrefix destination = routeInfo.getDestination();
- if ((destination.getAddress() instanceof Inet6Address) &&
- (destination.getPrefixLength() <= 64)) {
+ if ((destination.getAddress() instanceof Inet6Address)
+ && (destination.getPrefixLength() <= 64)) {
v6only.addRoute(routeInfo);
}
}
@@ -242,12 +249,12 @@ public class IPv6TetheringCoordinator {
// TODO: Delete this and switch to LinkAddress#isGlobalPreferred once we
// announce our own IPv6 address as DNS server.
private static boolean isIPv6GlobalAddress(InetAddress ip) {
- return (ip instanceof Inet6Address) &&
- !ip.isAnyLocalAddress() &&
- !ip.isLoopbackAddress() &&
- !ip.isLinkLocalAddress() &&
- !ip.isSiteLocalAddress() &&
- !ip.isMulticastAddress();
+ return (ip instanceof Inet6Address)
+ && !ip.isAnyLocalAddress()
+ && !ip.isLoopbackAddress()
+ && !ip.isLinkLocalAddress()
+ && !ip.isSiteLocalAddress()
+ && !ip.isMulticastAddress();
}
private static LinkProperties getUniqueLocalConfig(byte[] ulp, short subnetId) {
diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/OffloadHardwareInterface.java b/packages/Tethering/src/com/android/server/connectivity/tethering/OffloadHardwareInterface.java
index 01339a4a2c33..00a677338b1b 100644
--- a/packages/Tethering/src/com/android/server/connectivity/tethering/OffloadHardwareInterface.java
+++ b/packages/Tethering/src/com/android/server/connectivity/tethering/OffloadHardwareInterface.java
@@ -107,6 +107,8 @@ public class OffloadHardwareInterface {
public OffloadHardwareInterface(Handler h, SharedLog log) {
mHandler = h;
mLog = log.forSubComponent(TAG);
+
+ System.loadLibrary("tetheroffloadjni");
}
/** Get default value indicating whether offload is supported. */
diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java
index acedc3635730..f1228129cd92 100644
--- a/services/core/java/com/android/server/connectivity/Tethering.java
+++ b/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.connectivity;
+package com.android.server.connectivity.tethering;
import static android.hardware.usb.UsbManager.USB_CONFIGURED;
import static android.hardware.usb.UsbManager.USB_CONNECTED;
@@ -47,8 +47,6 @@ import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLED;
import static android.telephony.CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED;
import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
-import static com.android.server.ConnectivityService.SHORT_ARG;
-
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
@@ -62,9 +60,10 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.Resources;
import android.hardware.usb.UsbManager;
+import android.net.INetd;
import android.net.INetworkPolicyManager;
import android.net.INetworkStatsService;
-import android.net.ITetheringEventCallback;
+import android.net.ITetherInternalCallback;
import android.net.IpPrefix;
import android.net.LinkAddress;
import android.net.LinkProperties;
@@ -72,7 +71,10 @@ import android.net.Network;
import android.net.NetworkInfo;
import android.net.NetworkState;
import android.net.NetworkUtils;
+import android.net.TetherStatesParcel;
+import android.net.TetheringConfigurationParcel;
import android.net.ip.IpServer;
+import android.net.util.BaseNetdUnsolicitedEventListener;
import android.net.util.InterfaceSet;
import android.net.util.PrefixUtils;
import android.net.util.SharedLog;
@@ -87,13 +89,10 @@ import android.os.Handler;
import android.os.INetworkManagementService;
import android.os.Looper;
import android.os.Message;
-import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.UserHandle;
import android.os.UserManager;
-import android.os.UserManagerInternal;
-import android.os.UserManagerInternal.UserRestrictionsListener;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
@@ -110,15 +109,6 @@ import com.android.internal.util.MessageUtils;
import com.android.internal.util.Protocol;
import com.android.internal.util.State;
import com.android.internal.util.StateMachine;
-import com.android.server.LocalServices;
-import com.android.server.connectivity.tethering.EntitlementManager;
-import com.android.server.connectivity.tethering.IPv6TetheringCoordinator;
-import com.android.server.connectivity.tethering.OffloadController;
-import com.android.server.connectivity.tethering.TetheringConfiguration;
-import com.android.server.connectivity.tethering.TetheringDependencies;
-import com.android.server.connectivity.tethering.TetheringInterfaceUtils;
-import com.android.server.connectivity.tethering.UpstreamNetworkMonitor;
-import com.android.server.net.BaseNetworkObserver;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -127,32 +117,32 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
+import java.util.Iterator;
import java.util.Set;
/**
- * @hide
*
* This class holds much of the business logic to allow Android devices
* to act as IP gateways via USB, BT, and WiFi interfaces.
*/
-public class Tethering extends BaseNetworkObserver {
+public class Tethering {
- private final static String TAG = Tethering.class.getSimpleName();
- private final static boolean DBG = false;
- private final static boolean VDBG = false;
+ private static final String TAG = Tethering.class.getSimpleName();
+ private static final boolean DBG = false;
+ private static final boolean VDBG = false;
- private static final Class[] messageClasses = {
+ private static final Class[] sMessageClasses = {
Tethering.class, TetherMasterSM.class, IpServer.class
};
private static final SparseArray<String> sMagicDecoderRing =
- MessageUtils.findMessageNames(messageClasses);
+ MessageUtils.findMessageNames(sMessageClasses);
private static class TetherState {
public final IpServer ipServer;
public int lastState;
public int lastError;
- public TetherState(IpServer ipServer) {
+ TetherState(IpServer ipServer) {
this.ipServer = ipServer;
// Assume all state machines start out available and with no errors.
lastState = IpServer.STATE_AVAILABLE;
@@ -177,6 +167,7 @@ public class Tethering extends BaseNetworkObserver {
private final Context mContext;
private final ArrayMap<String, TetherState> mTetherStates;
private final BroadcastReceiver mStateReceiver;
+ // Stopship: replace mNMService before production.
private final INetworkManagementService mNMService;
private final INetworkStatsService mStatsService;
private final INetworkPolicyManager mPolicyManager;
@@ -191,10 +182,13 @@ public class Tethering extends BaseNetworkObserver {
private final TetheringDependencies mDeps;
private final EntitlementManager mEntitlementMgr;
private final Handler mHandler;
- private final RemoteCallbackList<ITetheringEventCallback> mTetheringEventCallbacks =
- new RemoteCallbackList<>();
private final PhoneStateListener mPhoneStateListener;
+ private final INetd mNetd;
+ private final NetdCallback mNetdCallback;
+ private final UserRestrictionActionListener mTetheringRestriction;
private int mActiveDataSubId = INVALID_SUBSCRIPTION_ID;
+ // All the usage of mTetherInternalCallback should run in the same thread.
+ private ITetherInternalCallback mTetherInternalCallback = null;
private volatile TetheringConfiguration mConfig;
private InterfaceSet mCurrentUpstreamIfaceSet;
@@ -205,18 +199,17 @@ public class Tethering extends BaseNetworkObserver {
// True iff. WiFi tethering should be started when soft AP is ready.
private boolean mWifiTetherRequested;
private Network mTetherUpstream;
+ private TetherStatesParcel mTetherStatesParcel;
- public Tethering(Context context, INetworkManagementService nmService,
- INetworkStatsService statsService, INetworkPolicyManager policyManager,
- Looper looper, MockableSystemProperties systemProperties,
- TetheringDependencies deps) {
- mLog.mark("constructed");
- mContext = context;
- mNMService = nmService;
- mStatsService = statsService;
- mPolicyManager = policyManager;
- mLooper = looper;
+ public Tethering(TetheringDependencies deps) {
+ mLog.mark("Tethering.constructed");
mDeps = deps;
+ mContext = mDeps.getContext();
+ mNMService = mDeps.getINetworkManagementService();
+ mStatsService = mDeps.getINetworkStatsService();
+ mPolicyManager = mDeps.getINetworkPolicyManager();
+ mNetd = mDeps.getINetd(mContext);
+ mLooper = mDeps.getTetheringLooper();
mPublicSync = new Object();
@@ -239,7 +232,7 @@ public class Tethering extends BaseNetworkObserver {
// EntitlementManager will send EVENT_UPSTREAM_PERMISSION_CHANGED when cellular upstream
// permission is changed according to entitlement check result.
mEntitlementMgr = mDeps.getEntitlementManager(mContext, mTetherMasterSM, mLog,
- TetherMasterSM.EVENT_UPSTREAM_PERMISSION_CHANGED, systemProperties);
+ TetherMasterSM.EVENT_UPSTREAM_PERMISSION_CHANGED);
mEntitlementMgr.setOnUiEntitlementFailedListener((int downstream) -> {
mLog.log("OBSERVED UiEnitlementFailed");
stopTethering(downstream);
@@ -278,10 +271,22 @@ public class Tethering extends BaseNetworkObserver {
mStateReceiver = new StateReceiver();
+ mNetdCallback = new NetdCallback();
+ try {
+ mNetd.registerUnsolicitedEventListener(mNetdCallback);
+ } catch (RemoteException e) {
+ mLog.e("Unable to register netd UnsolicitedEventListener");
+ }
+
+ final UserManager userManager = (UserManager) mContext.getSystemService(
+ Context.USER_SERVICE);
+ mTetheringRestriction = new UserRestrictionActionListener(userManager, this);
+
// Load tethering configuration.
updateConfiguration();
startStateMachineUpdaters(mHandler);
+ startTrackDefaultNetwork();
}
private void startStateMachineUpdaters(Handler handler) {
@@ -295,6 +300,7 @@ public class Tethering extends BaseNetworkObserver {
filter.addAction(WifiManager.WIFI_AP_STATE_CHANGED_ACTION);
filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
filter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
+ filter.addAction(UserManager.ACTION_USER_RESTRICTIONS_CHANGED);
mContext.registerReceiver(mStateReceiver, filter, null, handler);
filter = new IntentFilter();
@@ -303,11 +309,6 @@ public class Tethering extends BaseNetworkObserver {
filter.addDataScheme("file");
mContext.registerReceiver(mStateReceiver, filter, null, handler);
- final UserManagerInternal umi = LocalServices.getService(UserManagerInternal.class);
- // This check is useful only for some unit tests; example: ConnectivityServiceTest.
- if (umi != null) {
- umi.addUserRestrictionsListener(new TetheringUserRestrictionListener(this));
- }
}
private WifiManager getWifiManager() {
@@ -318,6 +319,7 @@ public class Tethering extends BaseNetworkObserver {
private void updateConfiguration() {
mConfig = mDeps.generateTetheringConfiguration(mContext, mLog, mActiveDataSubId);
mUpstreamNetworkMonitor.updateMobileRequiresDun(mConfig.isDunRequired);
+ reportConfigurationChanged(mConfig.toStableParcelable());
}
private void maybeDunSettingChanged() {
@@ -327,10 +329,31 @@ public class Tethering extends BaseNetworkObserver {
updateConfiguration();
}
- @Override
- public void interfaceStatusChanged(String iface, boolean up) {
+ private class NetdCallback extends BaseNetdUnsolicitedEventListener {
+ @Override
+ public void onInterfaceChanged(String ifName, boolean up) {
+ mHandler.post(() -> interfaceStatusChanged(ifName, up));
+ }
+
+ @Override
+ public void onInterfaceLinkStateChanged(String ifName, boolean up) {
+ mHandler.post(() -> interfaceLinkStateChanged(ifName, up));
+ }
+
+ @Override
+ public void onInterfaceAdded(String ifName) {
+ mHandler.post(() -> interfaceAdded(ifName));
+ }
+
+ @Override
+ public void onInterfaceRemoved(String ifName) {
+ mHandler.post(() -> interfaceRemoved(ifName));
+ }
+ }
+
+ void interfaceStatusChanged(String iface, boolean up) {
// Never called directly: only called from interfaceLinkStateChanged.
- // See NetlinkHandler.cpp:71.
+ // See NetlinkHandler.cpp: notifyInterfaceChanged.
if (VDBG) Log.d(TAG, "interfaceStatusChanged " + iface + ", " + up);
synchronized (mPublicSync) {
if (up) {
@@ -349,8 +372,7 @@ public class Tethering extends BaseNetworkObserver {
}
}
- @Override
- public void interfaceLinkStateChanged(String iface, boolean up) {
+ void interfaceLinkStateChanged(String iface, boolean up) {
interfaceStatusChanged(iface, up);
}
@@ -369,28 +391,27 @@ public class Tethering extends BaseNetworkObserver {
return TETHERING_INVALID;
}
- @Override
- public void interfaceAdded(String iface) {
+ void interfaceAdded(String iface) {
if (VDBG) Log.d(TAG, "interfaceAdded " + iface);
synchronized (mPublicSync) {
maybeTrackNewInterfaceLocked(iface);
}
}
- @Override
- public void interfaceRemoved(String iface) {
+
+ void interfaceRemoved(String iface) {
if (VDBG) Log.d(TAG, "interfaceRemoved " + iface);
synchronized (mPublicSync) {
stopTrackingInterfaceLocked(iface);
}
}
- public void startTethering(int type, ResultReceiver receiver, boolean showProvisioningUi) {
+ void startTethering(int type, ResultReceiver receiver, boolean showProvisioningUi) {
mEntitlementMgr.startProvisioningIfNeeded(type, showProvisioningUi);
enableTetheringInternal(type, true /* enabled */, receiver);
}
- public void stopTethering(int type) {
+ void stopTethering(int type) {
enableTetheringInternal(type, false /* disabled */, null);
mEntitlementMgr.stopProvisioningIfNeeded(type);
}
@@ -434,8 +455,8 @@ public class Tethering extends BaseNetworkObserver {
mLog.e("setWifiTethering: failed to get WifiManager!");
return TETHER_ERROR_SERVICE_UNAVAIL;
}
- if ((enable && mgr.startSoftAp(null /* use existing wifi config */)) ||
- (!enable && mgr.stopSoftAp())) {
+ if ((enable && mgr.startSoftAp(null /* use existing wifi config */))
+ || (!enable && mgr.stopSoftAp())) {
mWifiTetherRequested = enable;
return TETHER_ERROR_NO_ERROR;
}
@@ -450,8 +471,8 @@ public class Tethering extends BaseNetworkObserver {
private void setBluetoothTethering(final boolean enable, final ResultReceiver receiver) {
final BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
if (adapter == null || !adapter.isEnabled()) {
- Log.w(TAG, "Tried to enable bluetooth tethering with null or disabled adapter. null: " +
- (adapter == null));
+ Log.w(TAG, "Tried to enable bluetooth tethering with null or disabled adapter. null: "
+ + (adapter == null));
sendTetherResult(receiver, TETHER_ERROR_SERVICE_UNAVAIL);
return;
}
@@ -487,7 +508,7 @@ public class Tethering extends BaseNetworkObserver {
}, BluetoothProfile.PAN);
}
- public int tether(String iface) {
+ int tether(String iface) {
return tether(iface, IpServer.STATE_TETHERED);
}
@@ -515,7 +536,7 @@ public class Tethering extends BaseNetworkObserver {
}
}
- public int untether(String iface) {
+ int untether(String iface) {
if (DBG) Log.d(TAG, "Untethering " + iface);
synchronized (mPublicSync) {
TetherState tetherState = mTetherStates.get(iface);
@@ -532,19 +553,19 @@ public class Tethering extends BaseNetworkObserver {
}
}
- public void untetherAll() {
+ void untetherAll() {
stopTethering(TETHERING_WIFI);
stopTethering(TETHERING_WIFI_P2P);
stopTethering(TETHERING_USB);
stopTethering(TETHERING_BLUETOOTH);
}
- public int getLastTetherError(String iface) {
+ int getLastTetherError(String iface) {
synchronized (mPublicSync) {
TetherState tetherState = mTetherStates.get(iface);
if (tetherState == null) {
- Log.e(TAG, "Tried to getLastTetherError on an unknown iface :" + iface +
- ", ignoring");
+ Log.e(TAG, "Tried to getLastTetherError on an unknown iface :" + iface
+ + ", ignoring");
return TETHER_ERROR_UNKNOWN_IFACE;
}
return tetherState.lastError;
@@ -559,12 +580,14 @@ public class Tethering extends BaseNetworkObserver {
final ArrayList<String> tetherList = new ArrayList<>();
final ArrayList<String> localOnlyList = new ArrayList<>();
final ArrayList<String> erroredList = new ArrayList<>();
+ final ArrayList<Integer> lastErrorList = new ArrayList<>();
boolean wifiTethered = false;
boolean usbTethered = false;
boolean bluetoothTethered = false;
final TetheringConfiguration cfg = mConfig;
+ final TetherStatesParcel mTetherStatesParcel = new TetherStatesParcel();
synchronized (mPublicSync) {
for (int i = 0; i < mTetherStates.size(); i++) {
@@ -572,6 +595,7 @@ public class Tethering extends BaseNetworkObserver {
String iface = mTetherStates.keyAt(i);
if (tetherState.lastError != TETHER_ERROR_NO_ERROR) {
erroredList.add(iface);
+ lastErrorList.add(tetherState.lastError);
} else if (tetherState.lastState == IpServer.STATE_AVAILABLE) {
availableList.add(iface);
} else if (tetherState.lastState == IpServer.STATE_LOCAL_ONLY) {
@@ -588,9 +612,21 @@ public class Tethering extends BaseNetworkObserver {
}
}
}
+
+ mTetherStatesParcel.availableList = availableList.toArray(new String[0]);
+ mTetherStatesParcel.tetheredList = tetherList.toArray(new String[0]);
+ mTetherStatesParcel.localOnlyList = localOnlyList.toArray(new String[0]);
+ mTetherStatesParcel.erroredIfaceList = erroredList.toArray(new String[0]);
+ mTetherStatesParcel.lastErrorList = new int[lastErrorList.size()];
+ Iterator<Integer> iterator = lastErrorList.iterator();
+ for (int i = 0; i < lastErrorList.size(); i++) {
+ mTetherStatesParcel.lastErrorList[i] = iterator.next().intValue();
+ }
+ reportTetherStateChanged(mTetherStatesParcel);
+
final Intent bcast = new Intent(ACTION_TETHER_STATE_CHANGED);
- bcast.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING |
- Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+ bcast.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING
+ | Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
bcast.putStringArrayListExtra(EXTRA_AVAILABLE_TETHER, availableList);
bcast.putStringArrayListExtra(EXTRA_ACTIVE_LOCAL_ONLY, localOnlyList);
bcast.putStringArrayListExtra(EXTRA_ACTIVE_TETHER, tetherList);
@@ -638,16 +674,16 @@ public class Tethering extends BaseNetworkObserver {
}
int icon = 0;
switch(id) {
- case SystemMessage.NOTE_TETHER_USB:
- icon = com.android.internal.R.drawable.stat_sys_tether_usb;
- break;
- case SystemMessage.NOTE_TETHER_BLUETOOTH:
- icon = com.android.internal.R.drawable.stat_sys_tether_bluetooth;
- break;
- case SystemMessage.NOTE_TETHER_GENERAL:
- default:
- icon = com.android.internal.R.drawable.stat_sys_tether_general;
- break;
+ case SystemMessage.NOTE_TETHER_USB:
+ icon = com.android.internal.R.drawable.stat_sys_tether_usb;
+ break;
+ case SystemMessage.NOTE_TETHER_BLUETOOTH:
+ icon = com.android.internal.R.drawable.stat_sys_tether_bluetooth;
+ break;
+ case SystemMessage.NOTE_TETHER_GENERAL:
+ default:
+ icon = com.android.internal.R.drawable.stat_sys_tether_general;
+ break;
}
if (mLastNotificationId != 0) {
@@ -679,8 +715,8 @@ public class Tethering extends BaseNetworkObserver {
}
if (mTetheredNotificationBuilder == null) {
- mTetheredNotificationBuilder =
- new Notification.Builder(mContext, SystemNotificationChannels.NETWORK_STATUS);
+ mTetheredNotificationBuilder = new Notification.Builder(mContext,
+ SystemNotificationChannels.NETWORK_STATUS);
mTetheredNotificationBuilder.setWhen(0)
.setOngoing(true)
.setColor(mContext.getColor(
@@ -701,7 +737,7 @@ public class Tethering extends BaseNetworkObserver {
@VisibleForTesting
protected void clearTetheredNotification() {
NotificationManager notificationManager =
- (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
+ (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
if (notificationManager != null && mLastNotificationId != 0) {
notificationManager.cancelAsUser(null, mLastNotificationId,
UserHandle.ALL);
@@ -726,14 +762,17 @@ public class Tethering extends BaseNetworkObserver {
} else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED)) {
mLog.log("OBSERVED configuration changed");
updateConfiguration();
+ } else if (action.equals(UserManager.ACTION_USER_RESTRICTIONS_CHANGED)) {
+ mLog.log("OBSERVED user restrictions changed");
+ handleUserRestrictionAction();
}
}
private void handleConnectivityAction(Intent intent) {
final NetworkInfo networkInfo =
(NetworkInfo) intent.getParcelableExtra(EXTRA_NETWORK_INFO);
- if (networkInfo == null ||
- networkInfo.getDetailedState() == NetworkInfo.DetailedState.FAILED) {
+ if (networkInfo == null
+ || networkInfo.getDetailedState() == NetworkInfo.DetailedState.FAILED) {
return;
}
@@ -832,25 +871,35 @@ public class Tethering extends BaseNetworkObserver {
}
}
}
+
+ private void handleUserRestrictionAction() {
+ mTetheringRestriction.onUserRestrictionsChanged();
+ }
}
@VisibleForTesting
- protected static class TetheringUserRestrictionListener implements UserRestrictionsListener {
+ protected static class UserRestrictionActionListener {
+ private final UserManager mUserManager;
private final Tethering mWrapper;
+ public boolean mDisallowTethering;
- public TetheringUserRestrictionListener(Tethering wrapper) {
+ public UserRestrictionActionListener(UserManager um, Tethering wrapper) {
+ mUserManager = um;
mWrapper = wrapper;
+ mDisallowTethering = false;
}
- public void onUserRestrictionsChanged(int userId,
- Bundle newRestrictions,
- Bundle prevRestrictions) {
+ public void onUserRestrictionsChanged() {
+ // getUserRestrictions gets restriction for this process' user, which is the primary
+ // user. This is fine because DISALLOW_CONFIG_TETHERING can only be set on the primary
+ // user. See UserManager.DISALLOW_CONFIG_TETHERING.
+ final Bundle restrictions = mUserManager.getUserRestrictions();
final boolean newlyDisallowed =
- newRestrictions.getBoolean(UserManager.DISALLOW_CONFIG_TETHERING);
- final boolean previouslyDisallowed =
- prevRestrictions.getBoolean(UserManager.DISALLOW_CONFIG_TETHERING);
- final boolean tetheringDisallowedChanged = (newlyDisallowed != previouslyDisallowed);
+ restrictions.getBoolean(UserManager.DISALLOW_CONFIG_TETHERING);
+ final boolean prevDisallowed = mDisallowTethering;
+ mDisallowTethering = newlyDisallowed;
+ final boolean tetheringDisallowedChanged = (newlyDisallowed != prevDisallowed);
if (!tetheringDisallowedChanged) {
return;
}
@@ -888,8 +937,8 @@ public class Tethering extends BaseNetworkObserver {
}
}
- mLog.log("Error disabling Wi-Fi IP serving; " +
- (TextUtils.isEmpty(ifname) ? "no interface name specified"
+ mLog.log("Error disabling Wi-Fi IP serving; "
+ + (TextUtils.isEmpty(ifname) ? "no interface name specified"
: "specified interface: " + ifname));
}
@@ -928,8 +977,8 @@ public class Tethering extends BaseNetworkObserver {
changeInterfaceState(ifname, ipServingMode);
} else {
mLog.e(String.format(
- "Cannot enable IP serving in mode %s on missing interface name",
- ipServingMode));
+ "Cannot enable IP serving in mode %s on missing interface name",
+ ipServingMode));
}
}
@@ -989,11 +1038,11 @@ public class Tethering extends BaseNetworkObserver {
}
}
- public TetheringConfiguration getTetheringConfiguration() {
+ TetheringConfiguration getTetheringConfiguration() {
return mConfig;
}
- public boolean hasTetherableConfiguration() {
+ boolean hasTetherableConfiguration() {
final TetheringConfiguration cfg = mConfig;
final boolean hasDownstreamConfiguration =
(cfg.tetherableUsbRegexs.length != 0)
@@ -1007,19 +1056,19 @@ public class Tethering extends BaseNetworkObserver {
// TODO - update callers to use getTetheringConfiguration(),
// which has only final members.
- public String[] getTetherableUsbRegexs() {
+ String[] getTetherableUsbRegexs() {
return copy(mConfig.tetherableUsbRegexs);
}
- public String[] getTetherableWifiRegexs() {
+ String[] getTetherableWifiRegexs() {
return copy(mConfig.tetherableWifiRegexs);
}
- public String[] getTetherableBluetoothRegexs() {
+ String[] getTetherableBluetoothRegexs() {
return copy(mConfig.tetherableBluetoothRegexs);
}
- public int setUsbTethering(boolean enable) {
+ int setUsbTethering(boolean enable) {
if (VDBG) Log.d(TAG, "setUsbTethering(" + enable + ")");
UsbManager usbManager = (UsbManager) mContext.getSystemService(Context.USB_SERVICE);
if (usbManager == null) {
@@ -1035,7 +1084,7 @@ public class Tethering extends BaseNetworkObserver {
}
// TODO review API - figure out how to delete these entirely.
- public String[] getTetheredIfaces() {
+ String[] getTetheredIfaces() {
ArrayList<String> list = new ArrayList<String>();
synchronized (mPublicSync) {
for (int i = 0; i < mTetherStates.size(); i++) {
@@ -1048,7 +1097,7 @@ public class Tethering extends BaseNetworkObserver {
return list.toArray(new String[list.size()]);
}
- public String[] getTetherableIfaces() {
+ String[] getTetherableIfaces() {
ArrayList<String> list = new ArrayList<String>();
synchronized (mPublicSync) {
for (int i = 0; i < mTetherStates.size(); i++) {
@@ -1061,13 +1110,13 @@ public class Tethering extends BaseNetworkObserver {
return list.toArray(new String[list.size()]);
}
- public String[] getTetheredDhcpRanges() {
+ String[] getTetheredDhcpRanges() {
// TODO: this is only valid for the old DHCP server. Latest search suggests it is only used
// by WifiP2pServiceImpl to start dnsmasq: remove/deprecate after migrating callers.
return mConfig.legacyDhcpRanges;
}
- public String[] getErroredIfaces() {
+ String[] getErroredIfaces() {
ArrayList<String> list = new ArrayList<String>();
synchronized (mPublicSync) {
for (int i = 0; i < mTetherStates.size(); i++) {
@@ -1518,8 +1567,8 @@ public class Tethering extends BaseNetworkObserver {
}
if (DBG) {
- Log.d(TAG, "TetherModeAlive still has " + mNotifyList.size() +
- " live requests:");
+ Log.d(TAG, "TetherModeAlive still has " + mNotifyList.size()
+ + " live requests:");
for (IpServer o : mNotifyList) {
Log.d(TAG, " " + o);
}
@@ -1588,7 +1637,7 @@ public class Tethering extends BaseNetworkObserver {
transitionTo(mInitialState);
break;
default:
- retValue = false;
+ retValue = false;
}
return retValue;
}
@@ -1625,7 +1674,7 @@ public class Tethering extends BaseNetworkObserver {
notify(IpServer.CMD_START_TETHERING_ERROR);
try {
mNMService.setIpForwardingEnabled(false);
- } catch (Exception e) {}
+ } catch (Exception e) { }
}
}
@@ -1636,7 +1685,7 @@ public class Tethering extends BaseNetworkObserver {
notify(IpServer.CMD_STOP_TETHERING_ERROR);
try {
mNMService.setIpForwardingEnabled(false);
- } catch (Exception e) {}
+ } catch (Exception e) { }
}
}
@@ -1647,10 +1696,10 @@ public class Tethering extends BaseNetworkObserver {
notify(IpServer.CMD_SET_DNS_FORWARDERS_ERROR);
try {
mNMService.stopTethering();
- } catch (Exception e) {}
+ } catch (Exception e) { }
try {
mNMService.setIpForwardingEnabled(false);
- } catch (Exception e) {}
+ } catch (Exception e) { }
}
}
@@ -1731,55 +1780,66 @@ public class Tethering extends BaseNetworkObserver {
}
}
- public void systemReady() {
+ private void startTrackDefaultNetwork() {
mUpstreamNetworkMonitor.startTrackDefaultNetwork(mDeps.getDefaultNetworkRequest(),
mEntitlementMgr);
}
/** Get the latest value of the tethering entitlement check. */
- public void getLatestTetheringEntitlementResult(int type, ResultReceiver receiver,
+ void requestLatestTetheringEntitlementResult(int type, ResultReceiver receiver,
boolean showEntitlementUi) {
if (receiver != null) {
- mEntitlementMgr.getLatestTetheringEntitlementResult(type, receiver, showEntitlementUi);
+ mEntitlementMgr.requestLatestTetheringEntitlementResult(type, receiver,
+ showEntitlementUi);
}
}
/** Register tethering event callback */
- public void registerTetheringEventCallback(ITetheringEventCallback callback) {
+ void registerTetherInternalCallback(ITetherInternalCallback callback) {
mHandler.post(() -> {
+ mTetherInternalCallback = callback;
try {
- callback.onUpstreamChanged(mTetherUpstream);
+ mTetherInternalCallback.onCallbackCreated(mTetherUpstream,
+ mConfig.toStableParcelable(), mTetherStatesParcel);
} catch (RemoteException e) {
// Not really very much to do here.
}
- mTetheringEventCallbacks.register(callback);
});
}
- /** Unregister tethering event callback */
- public void unregisterTetheringEventCallback(ITetheringEventCallback callback) {
- mHandler.post(() -> {
- mTetheringEventCallbacks.unregister(callback);
- });
+ private void reportUpstreamChanged(Network network) {
+ // Don't need to synchronized mTetherInternalCallback because all the usage of this variable
+ // should run at the same thread.
+ if (mTetherInternalCallback == null) return;
+
+ try {
+ mTetherInternalCallback.onUpstreamChanged(network);
+ } catch (RemoteException e) {
+ // Not really very much to do here.
+ }
}
- private void reportUpstreamChanged(Network network) {
- final int length = mTetheringEventCallbacks.beginBroadcast();
+ private void reportConfigurationChanged(TetheringConfigurationParcel config) {
+ if (mTetherInternalCallback == null) return;
+
try {
- for (int i = 0; i < length; i++) {
- try {
- mTetheringEventCallbacks.getBroadcastItem(i).onUpstreamChanged(network);
- } catch (RemoteException e) {
- // Not really very much to do here.
- }
- }
- } finally {
- mTetheringEventCallbacks.finishBroadcast();
+ mTetherInternalCallback.onConfigurationChanged(config);
+ } catch (RemoteException e) {
+ // Not really very much to do here.
+ }
+ }
+
+ private void reportTetherStateChanged(TetherStatesParcel states) {
+ if (mTetherInternalCallback == null) return;
+
+ try {
+ mTetherInternalCallback.onTetherStatesChanged(states);
+ } catch (RemoteException e) {
+ // Not really very much to do here.
}
}
- @Override
- public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
+ void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
// Binder.java closes the resource for us.
@SuppressWarnings("resource")
final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " ");
@@ -1838,7 +1898,7 @@ public class Tethering extends BaseNetworkObserver {
pw.println("Log:");
pw.increaseIndent();
- if (argsContain(args, SHORT_ARG)) {
+ if (argsContain(args, "--short")) {
pw.println("<log removed for brevity>");
} else {
mLog.dump(fd, pw, args);
diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringConfiguration.java b/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringConfiguration.java
index ca9b1681bacc..0ab4d634e84d 100644
--- a/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringConfiguration.java
+++ b/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringConfiguration.java
@@ -38,6 +38,7 @@ import android.content.ContentResolver;
import android.content.Context;
import android.content.res.Resources;
import android.net.ConnectivityManager;
+import android.net.TetheringConfigurationParcel;
import android.net.util.SharedLog;
import android.provider.Settings;
import android.telephony.SubscriptionManager;
@@ -384,4 +385,32 @@ public class TetheringConfiguration {
}
return false;
}
+
+ /**
+ * Convert this TetheringConfiguration to a TetheringConfigurationParcel.
+ */
+ public TetheringConfigurationParcel toStableParcelable() {
+ final TetheringConfigurationParcel parcel = new TetheringConfigurationParcel();
+ parcel.subId = subId;
+ parcel.tetherableUsbRegexs = tetherableUsbRegexs;
+ parcel.tetherableWifiRegexs = tetherableWifiRegexs;
+ parcel.tetherableBluetoothRegexs = tetherableBluetoothRegexs;
+ parcel.isDunRequired = isDunRequired;
+ parcel.chooseUpstreamAutomatically = chooseUpstreamAutomatically;
+
+ int[] preferredTypes = new int[preferredUpstreamIfaceTypes.size()];
+ int index = 0;
+ for (Integer type : preferredUpstreamIfaceTypes) {
+ preferredTypes[index++] = type;
+ }
+ parcel.preferredUpstreamIfaceTypes = preferredTypes;
+
+ parcel.legacyDhcpRanges = legacyDhcpRanges;
+ parcel.defaultIPv4DNS = defaultIPv4DNS;
+ parcel.enableLegacyDhcpServer = enableLegacyDhcpServer;
+ parcel.provisioningApp = provisioningApp;
+ parcel.provisioningAppNoUi = provisioningAppNoUi;
+ parcel.provisioningCheckPeriod = provisioningCheckPeriod;
+ return parcel;
+ }
}
diff --git a/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java b/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringDependencies.java
index 4ad7ac4bead0..0ba84127d8da 100644
--- a/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java
+++ b/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringDependencies.java
@@ -17,13 +17,19 @@
package com.android.server.connectivity.tethering;
import android.content.Context;
+import android.net.INetd;
+import android.net.INetworkPolicyManager;
+import android.net.INetworkStatsService;
import android.net.NetworkRequest;
import android.net.ip.IpServer;
import android.net.util.SharedLog;
import android.os.Handler;
+import android.os.IBinder;
+import android.os.INetworkManagementService;
+import android.os.Looper;
+import android.os.ServiceManager;
import com.android.internal.util.StateMachine;
-import com.android.server.connectivity.MockableSystemProperties;
import java.util.ArrayList;
@@ -82,8 +88,8 @@ public class TetheringDependencies {
* Get a reference to the EntitlementManager to be used by tethering.
*/
public EntitlementManager getEntitlementManager(Context ctx, StateMachine target,
- SharedLog log, int what, MockableSystemProperties systemProperties) {
- return new EntitlementManager(ctx, target, log, what, systemProperties);
+ SharedLog log, int what) {
+ return new EntitlementManager(ctx, target, log, what);
}
/**
@@ -93,4 +99,53 @@ public class TetheringDependencies {
int subId) {
return new TetheringConfiguration(ctx, log, subId);
}
+
+ /**
+ * Get a reference to INetworkManagementService to registerTetheringStatsProvider from
+ * OffloadController. Note: This should be removed soon by Usage refactor work in R
+ * development cycle.
+ */
+ public INetworkManagementService getINetworkManagementService() {
+ return INetworkManagementService.Stub.asInterface(
+ ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE));
+ }
+
+ /**
+ * Get a reference to INetworkStatsService to force update tethering usage.
+ * Note: This should be removed in R development cycle.
+ */
+ public INetworkStatsService getINetworkStatsService() {
+ return INetworkStatsService.Stub.asInterface(
+ ServiceManager.getService(Context.NETWORK_STATS_SERVICE));
+ }
+
+ /**
+ * Get a reference to INetworkPolicyManager to be used by tethering.
+ */
+ public INetworkPolicyManager getINetworkPolicyManager() {
+ return INetworkPolicyManager.Stub.asInterface(
+ ServiceManager.getService(Context.NETWORK_POLICY_SERVICE));
+ }
+
+ /**
+ * Get a reference to INetd to be used by tethering.
+ */
+ public INetd getINetd(Context context) {
+ return INetd.Stub.asInterface(
+ (IBinder) context.getSystemService(Context.NETD_SERVICE));
+ }
+
+ /**
+ * Get tethering thread looper.
+ */
+ public Looper getTetheringLooper() {
+ return null;
+ }
+
+ /**
+ * Get Context of TetheringSerice.
+ */
+ public Context getContext() {
+ return null;
+ }
}
diff --git a/services/core/java/com/android/server/connectivity/tethering/TetheringInterfaceUtils.java b/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringInterfaceUtils.java
index 0ef3805ff7c0..0ef3805ff7c0 100644
--- a/services/core/java/com/android/server/connectivity/tethering/TetheringInterfaceUtils.java
+++ b/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringInterfaceUtils.java
diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringService.java b/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringService.java
new file mode 100644
index 000000000000..456f2f7f27f5
--- /dev/null
+++ b/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringService.java
@@ -0,0 +1,178 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.connectivity.tethering;
+
+import android.app.Service;
+import android.content.Context;
+import android.content.Intent;
+import android.net.ConnectivityManager;
+import android.net.ITetherInternalCallback;
+import android.net.ITetheringConnector;
+import android.net.NetworkRequest;
+import android.net.util.SharedLog;
+import android.os.HandlerThread;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.ResultReceiver;
+import android.os.SystemProperties;
+import android.provider.Settings;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
+/**
+ * Android service used to manage tethering.
+ *
+ * <p>The service returns a binder for the system server to communicate with the tethering.
+ */
+public class TetheringService extends Service {
+ private static final String TAG = TetheringService.class.getSimpleName();
+
+ private final SharedLog mLog = new SharedLog(TAG);
+ private TetheringConnector mConnector;
+ private Context mContext;
+ private TetheringDependencies mDeps;
+ private Tethering mTethering;
+
+ @Override
+ public void onCreate() {
+ mLog.mark("onCreate");
+ mDeps = getTetheringDependencies();
+ mContext = mDeps.getContext();
+ mTethering = makeTethering(mDeps);
+ }
+
+ /**
+ * Make a reference to Tethering object.
+ */
+ @VisibleForTesting
+ public Tethering makeTethering(TetheringDependencies deps) {
+ return new Tethering(deps);
+ }
+
+ /**
+ * Create a binder connector for the system server to communicate with the tethering.
+ */
+ private synchronized IBinder makeConnector() {
+ if (mConnector == null) {
+ mConnector = new TetheringConnector(mTethering);
+ }
+ return mConnector;
+ }
+
+ @NonNull
+ @Override
+ public IBinder onBind(Intent intent) {
+ mLog.mark("onBind");
+ return makeConnector();
+ }
+
+ private static class TetheringConnector extends ITetheringConnector.Stub {
+ private final Tethering mService;
+
+ TetheringConnector(Tethering tether) {
+ mService = tether;
+ }
+
+ @Override
+ public void tether(String iface) {
+ mService.tether(iface);
+ }
+
+ @Override
+ public void untether(String iface) {
+ mService.untether(iface);
+ }
+
+ @Override
+ public void setUsbTethering(boolean enable) {
+ mService.setUsbTethering(enable);
+ }
+
+ @Override
+ public void startTethering(int type, ResultReceiver receiver, boolean showProvisioningUi) {
+ mService.startTethering(type, receiver, showProvisioningUi);
+ }
+
+ @Override
+ public void stopTethering(int type) {
+ mService.stopTethering(type);
+ }
+
+ @Override
+ public void requestLatestTetheringEntitlementResult(int type, ResultReceiver receiver,
+ boolean showEntitlementUi) {
+ mService.requestLatestTetheringEntitlementResult(type, receiver, showEntitlementUi);
+ }
+
+ @Override
+ public void registerTetherInternalCallback(ITetherInternalCallback callback) {
+ mService.registerTetherInternalCallback(callback);
+ }
+ }
+
+ @Override
+ protected void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter writer,
+ @Nullable String[] args) {
+ mTethering.dump(fd, writer, args);
+ }
+
+ /**
+ * An injection method for testing.
+ */
+ @VisibleForTesting
+ public TetheringDependencies getTetheringDependencies() {
+ if (mDeps == null) {
+ mDeps = new TetheringDependencies() {
+ @Override
+ public NetworkRequest getDefaultNetworkRequest() {
+ ConnectivityManager cm = (ConnectivityManager) mContext.getSystemService(
+ Context.CONNECTIVITY_SERVICE);
+ return cm.getDefaultRequest();
+ }
+
+ @Override
+ public Looper getTetheringLooper() {
+ final HandlerThread tetherThread = new HandlerThread("android.tethering");
+ tetherThread.start();
+ return tetherThread.getLooper();
+ }
+
+ @Override
+ public boolean isTetheringSupported() {
+ int defaultVal =
+ SystemProperties.get("ro.tether.denied").equals("true") ? 0 : 1;
+ boolean tetherSupported = Settings.Global.getInt(mContext.getContentResolver(),
+ Settings.Global.TETHER_SUPPORTED, defaultVal) != 0;
+ return tetherSupported;
+ }
+
+ @Override
+ public Context getContext() {
+ return TetheringService.this;
+ }
+ };
+ }
+
+ return mDeps;
+ }
+}
diff --git a/packages/Tethering/tests/unit/Android.bp b/packages/Tethering/tests/unit/Android.bp
index 363be18a73bc..5b018df21aaf 100644
--- a/packages/Tethering/tests/unit/Android.bp
+++ b/packages/Tethering/tests/unit/Android.bp
@@ -18,7 +18,6 @@ android_test {
name: "TetheringTests",
certificate: "platform",
srcs: [
- ":servicescore-tethering-src",
"src/**/*.java",
],
test_suites: ["device-tests"],
@@ -41,17 +40,3 @@ android_test {
"libstaticjvmtiagent",
],
}
-
-// This group would be removed when tethering migration is done.
-filegroup {
- name: "tethering-tests-src",
- srcs: [
- "src/com/android/server/connectivity/tethering/EntitlementManagerTest.java",
- "src/com/android/server/connectivity/tethering/OffloadControllerTest.java",
- "src/com/android/server/connectivity/tethering/TetheringConfigurationTest.java",
- "src/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java",
- "src/android/net/dhcp/DhcpServingParamsParcelExtTest.java",
- "src/android/net/ip/IpServerTest.java",
- "src/android/net/util/InterfaceSetTest.java",
- ],
-}
diff --git a/tests/net/java/android/net/util/VersionedBroadcastListenerTest.java b/packages/Tethering/tests/unit/src/android/net/util/VersionedBroadcastListenerTest.java
index 0d27d5bf0a11..5a9b6e380ea9 100644
--- a/tests/net/java/android/net/util/VersionedBroadcastListenerTest.java
+++ b/packages/Tethering/tests/unit/src/android/net/util/VersionedBroadcastListenerTest.java
@@ -51,7 +51,9 @@ public class VersionedBroadcastListenerTest {
private VersionedBroadcastListener mListener;
private int mCallbackCount;
- private void doCallback() { mCallbackCount++; }
+ private void doCallback() {
+ mCallbackCount++;
+ }
private class MockContext extends BroadcastInterceptingContext {
MockContext(Context base) {
@@ -96,7 +98,7 @@ public class VersionedBroadcastListenerTest {
mListener.startListening();
for (int i = 0; i < 5; i++) {
sendBroadcast();
- assertEquals(i+1, mCallbackCount);
+ assertEquals(i + 1, mCallbackCount);
}
mListener.stopListening();
}
diff --git a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/EntitlementManagerTest.java b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/EntitlementManagerTest.java
index 5217e26a40ef..99cf9e90d912 100644
--- a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/EntitlementManagerTest.java
+++ b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/EntitlementManagerTest.java
@@ -24,6 +24,9 @@ import static android.net.ConnectivityManager.TETHER_ERROR_NO_ERROR;
import static android.net.ConnectivityManager.TETHER_ERROR_PROVISION_FAILED;
import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
@@ -44,6 +47,7 @@ import android.os.Bundle;
import android.os.Message;
import android.os.PersistableBundle;
import android.os.ResultReceiver;
+import android.os.SystemProperties;
import android.os.test.TestLooper;
import android.provider.Settings;
import android.telephony.CarrierConfigManager;
@@ -57,7 +61,6 @@ import com.android.internal.util.State;
import com.android.internal.util.StateMachine;
import com.android.internal.util.test.BroadcastInterceptingContext;
import com.android.internal.util.test.FakeSettingsProvider;
-import com.android.server.connectivity.MockableSystemProperties;
import org.junit.After;
import org.junit.Before;
@@ -65,6 +68,8 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import org.mockito.MockitoSession;
+import org.mockito.quality.Strictness;
import java.util.ArrayList;
import java.util.concurrent.CountDownLatch;
@@ -80,7 +85,6 @@ public final class EntitlementManagerTest {
@Mock private CarrierConfigManager mCarrierConfigManager;
@Mock private Context mContext;
- @Mock private MockableSystemProperties mSystemProperties;
@Mock private Resources mResources;
@Mock private SharedLog mLog;
@Mock private EntitlementManager.OnUiEntitlementFailedListener mEntitlementFailedListener;
@@ -95,6 +99,7 @@ public final class EntitlementManagerTest {
private TestStateMachine mSM;
private WrappedEntitlementManager mEnMgr;
private TetheringConfiguration mConfig;
+ private MockitoSession mMockingSession;
private class MockContext extends BroadcastInterceptingContext {
MockContext(Context base) {
@@ -118,8 +123,8 @@ public final class EntitlementManagerTest {
public int silentProvisionCount = 0;
public WrappedEntitlementManager(Context ctx, StateMachine target,
- SharedLog log, int what, MockableSystemProperties systemProperties) {
- super(ctx, target, log, what, systemProperties);
+ SharedLog log, int what) {
+ super(ctx, target, log, what);
}
public void reset() {
@@ -144,6 +149,15 @@ public final class EntitlementManagerTest {
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
+ mMockingSession = mockitoSession()
+ .initMocks(this)
+ .spyStatic(SystemProperties.class)
+ .strictness(Strictness.WARN)
+ .startMocking();
+ // Don't disable tethering provisioning unless requested.
+ doReturn(false).when(
+ () -> SystemProperties.getBoolean(
+ eq(EntitlementManager.DISABLE_PROVISIONING_SYSPROP_KEY), anyBoolean()));
when(mResources.getStringArray(R.array.config_tether_dhcp_range))
.thenReturn(new String[0]);
@@ -161,8 +175,7 @@ public final class EntitlementManagerTest {
mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
mMockContext = new MockContext(mContext);
mSM = new TestStateMachine();
- mEnMgr = new WrappedEntitlementManager(mMockContext, mSM, mLog, EVENT_EM_UPDATE,
- mSystemProperties);
+ mEnMgr = new WrappedEntitlementManager(mMockContext, mSM, mLog, EVENT_EM_UPDATE);
mEnMgr.setOnUiEntitlementFailedListener(mEntitlementFailedListener);
mConfig = new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID);
mEnMgr.setTetheringConfigurationFetcher(() -> {
@@ -176,6 +189,7 @@ public final class EntitlementManagerTest {
mSM.quit();
mSM = null;
}
+ mMockingSession.finishMocking();
}
private void setupForRequiredProvisioning() {
@@ -184,9 +198,6 @@ public final class EntitlementManagerTest {
.thenReturn(PROVISIONING_APP_NAME);
when(mResources.getString(R.string.config_mobile_hotspot_provision_app_no_ui))
.thenReturn(PROVISIONING_NO_UI_APP_NAME);
- // Don't disable tethering provisioning unless requested.
- when(mSystemProperties.getBoolean(eq(EntitlementManager.DISABLE_PROVISIONING_SYSPROP_KEY),
- anyBoolean())).thenReturn(false);
// Act like the CarrierConfigManager is present and ready unless told otherwise.
when(mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE))
.thenReturn(mCarrierConfigManager);
@@ -244,7 +255,7 @@ public final class EntitlementManagerTest {
}
@Test
- public void testGetLastEntitlementCacheValue() throws Exception {
+ public void testRequestLastEntitlementCacheValue() throws Exception {
final CountDownLatch mCallbacklatch = new CountDownLatch(1);
// 1. Entitlement check is not required.
mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR;
@@ -255,7 +266,7 @@ public final class EntitlementManagerTest {
mCallbacklatch.countDown();
}
};
- mEnMgr.getLatestTetheringEntitlementResult(TETHERING_WIFI, receiver, true);
+ mEnMgr.requestLatestTetheringEntitlementResult(TETHERING_WIFI, receiver, true);
mLooper.dispatchAll();
callbackTimeoutHelper(mCallbacklatch);
assertEquals(0, mEnMgr.uiProvisionCount);
@@ -270,7 +281,7 @@ public final class EntitlementManagerTest {
mCallbacklatch.countDown();
}
};
- mEnMgr.getLatestTetheringEntitlementResult(TETHERING_WIFI, receiver, false);
+ mEnMgr.requestLatestTetheringEntitlementResult(TETHERING_WIFI, receiver, false);
mLooper.dispatchAll();
callbackTimeoutHelper(mCallbacklatch);
assertEquals(0, mEnMgr.uiProvisionCount);
@@ -284,7 +295,7 @@ public final class EntitlementManagerTest {
mCallbacklatch.countDown();
}
};
- mEnMgr.getLatestTetheringEntitlementResult(TETHERING_WIFI, receiver, true);
+ mEnMgr.requestLatestTetheringEntitlementResult(TETHERING_WIFI, receiver, true);
mLooper.dispatchAll();
callbackTimeoutHelper(mCallbacklatch);
assertEquals(1, mEnMgr.uiProvisionCount);
@@ -298,7 +309,7 @@ public final class EntitlementManagerTest {
mCallbacklatch.countDown();
}
};
- mEnMgr.getLatestTetheringEntitlementResult(TETHERING_WIFI, receiver, false);
+ mEnMgr.requestLatestTetheringEntitlementResult(TETHERING_WIFI, receiver, false);
mLooper.dispatchAll();
callbackTimeoutHelper(mCallbacklatch);
assertEquals(0, mEnMgr.uiProvisionCount);
@@ -312,7 +323,7 @@ public final class EntitlementManagerTest {
mCallbacklatch.countDown();
}
};
- mEnMgr.getLatestTetheringEntitlementResult(TETHERING_WIFI, receiver, true);
+ mEnMgr.requestLatestTetheringEntitlementResult(TETHERING_WIFI, receiver, true);
mLooper.dispatchAll();
callbackTimeoutHelper(mCallbacklatch);
assertEquals(1, mEnMgr.uiProvisionCount);
@@ -326,7 +337,7 @@ public final class EntitlementManagerTest {
mCallbacklatch.countDown();
}
};
- mEnMgr.getLatestTetheringEntitlementResult(TETHERING_WIFI, receiver, true);
+ mEnMgr.requestLatestTetheringEntitlementResult(TETHERING_WIFI, receiver, true);
mLooper.dispatchAll();
callbackTimeoutHelper(mCallbacklatch);
assertEquals(0, mEnMgr.uiProvisionCount);
@@ -339,7 +350,7 @@ public final class EntitlementManagerTest {
mCallbacklatch.countDown();
}
};
- mEnMgr.getLatestTetheringEntitlementResult(TETHERING_USB, receiver, false);
+ mEnMgr.requestLatestTetheringEntitlementResult(TETHERING_USB, receiver, false);
mLooper.dispatchAll();
callbackTimeoutHelper(mCallbacklatch);
assertEquals(0, mEnMgr.uiProvisionCount);
diff --git a/tests/net/java/com/android/server/connectivity/TetheringTest.java b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java
index 9e5717b4bd64..0273ed358673 100644
--- a/tests/net/java/com/android/server/connectivity/TetheringTest.java
+++ b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.connectivity;
+package com.android.server.connectivity.tethering;
import static android.hardware.usb.UsbManager.USB_CONFIGURED;
import static android.hardware.usb.UsbManager.USB_CONNECTED;
@@ -39,7 +39,9 @@ import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLED;
import static android.provider.Settings.Global.TETHER_ENABLE_LEGACY_DHCP_SERVER;
import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.argThat;
@@ -70,7 +72,7 @@ import android.hardware.usb.UsbManager;
import android.net.INetd;
import android.net.INetworkPolicyManager;
import android.net.INetworkStatsService;
-import android.net.ITetheringEventCallback;
+import android.net.ITetherInternalCallback;
import android.net.InterfaceConfiguration;
import android.net.IpPrefix;
import android.net.LinkAddress;
@@ -82,6 +84,8 @@ import android.net.NetworkInfo;
import android.net.NetworkState;
import android.net.NetworkUtils;
import android.net.RouteInfo;
+import android.net.TetherStatesParcel;
+import android.net.TetheringConfigurationParcel;
import android.net.dhcp.DhcpServerCallbacks;
import android.net.dhcp.DhcpServingParamsParcel;
import android.net.dhcp.IDhcpServer;
@@ -98,6 +102,7 @@ import android.net.wifi.p2p.WifiP2pManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.INetworkManagementService;
+import android.os.Looper;
import android.os.PersistableBundle;
import android.os.RemoteException;
import android.os.UserHandle;
@@ -109,6 +114,7 @@ import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import android.test.mock.MockContentResolver;
+import androidx.annotation.NonNull;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
@@ -116,11 +122,6 @@ import com.android.internal.util.ArrayUtils;
import com.android.internal.util.StateMachine;
import com.android.internal.util.test.BroadcastInterceptingContext;
import com.android.internal.util.test.FakeSettingsProvider;
-import com.android.server.connectivity.tethering.IPv6TetheringCoordinator;
-import com.android.server.connectivity.tethering.OffloadHardwareInterface;
-import com.android.server.connectivity.tethering.TetheringConfiguration;
-import com.android.server.connectivity.tethering.TetheringDependencies;
-import com.android.server.connectivity.tethering.UpstreamNetworkMonitor;
import org.junit.After;
import org.junit.Before;
@@ -154,7 +155,6 @@ public class TetheringTest {
@Mock private INetworkManagementService mNMService;
@Mock private INetworkStatsService mStatsService;
@Mock private INetworkPolicyManager mPolicyManager;
- @Mock private MockableSystemProperties mSystemProperties;
@Mock private OffloadHardwareInterface mOffloadHardwareInterface;
@Mock private Resources mResources;
@Mock private TelephonyManager mTelephonyManager;
@@ -166,6 +166,7 @@ public class TetheringTest {
@Mock private RouterAdvertisementDaemon mRouterAdvertisementDaemon;
@Mock private IDhcpServer mDhcpServer;
@Mock private INetd mNetd;
+ @Mock private UserManager mUserManager;
private final MockIpServerDependencies mIpServerDependencies =
spy(new MockIpServerDependencies());
@@ -184,28 +185,37 @@ public class TetheringTest {
private Tethering mTethering;
private PhoneStateListener mPhoneStateListener;
- private class MockContext extends BroadcastInterceptingContext {
- MockContext(Context base) {
+ private class TestContext extends BroadcastInterceptingContext {
+ TestContext(Context base) {
super(base);
}
@Override
- public ApplicationInfo getApplicationInfo() { return mApplicationInfo; }
+ public ApplicationInfo getApplicationInfo() {
+ return mApplicationInfo;
+ }
@Override
- public ContentResolver getContentResolver() { return mContentResolver; }
+ public ContentResolver getContentResolver() {
+ return mContentResolver;
+ }
@Override
- public String getPackageName() { return "TetheringTest"; }
+ public String getPackageName() {
+ return "TetheringTest";
+ }
@Override
- public Resources getResources() { return mResources; }
+ public Resources getResources() {
+ return mResources;
+ }
@Override
public Object getSystemService(String name) {
if (Context.WIFI_SERVICE.equals(name)) return mWifiManager;
if (Context.USB_SERVICE.equals(name)) return mUsbManager;
if (Context.TELEPHONY_SERVICE.equals(name)) return mTelephonyManager;
+ if (Context.USER_SERVICE.equals(name)) return mUserManager;
return super.getSystemService(name);
}
@@ -266,14 +276,14 @@ public class TetheringTest {
}
public class MockTetheringDependencies extends TetheringDependencies {
- StateMachine upstreamNetworkMonitorMasterSM;
- ArrayList<IpServer> ipv6CoordinatorNotifyList;
- int isTetheringSupportedCalls;
+ StateMachine mUpstreamNetworkMonitorMasterSM;
+ ArrayList<IpServer> mIpv6CoordinatorNotifyList;
+ int mIsTetheringSupportedCalls;
public void reset() {
- upstreamNetworkMonitorMasterSM = null;
- ipv6CoordinatorNotifyList = null;
- isTetheringSupportedCalls = 0;
+ mUpstreamNetworkMonitorMasterSM = null;
+ mIpv6CoordinatorNotifyList = null;
+ mIsTetheringSupportedCalls = 0;
}
@Override
@@ -284,14 +294,14 @@ public class TetheringTest {
@Override
public UpstreamNetworkMonitor getUpstreamNetworkMonitor(Context ctx,
StateMachine target, SharedLog log, int what) {
- upstreamNetworkMonitorMasterSM = target;
+ mUpstreamNetworkMonitorMasterSM = target;
return mUpstreamNetworkMonitor;
}
@Override
public IPv6TetheringCoordinator getIPv6TetheringCoordinator(
ArrayList<IpServer> notifyList, SharedLog log) {
- ipv6CoordinatorNotifyList = notifyList;
+ mIpv6CoordinatorNotifyList = notifyList;
return mIPv6TetheringCoordinator;
}
@@ -302,7 +312,7 @@ public class TetheringTest {
@Override
public boolean isTetheringSupported() {
- isTetheringSupportedCalls++;
+ mIsTetheringSupportedCalls++;
return true;
}
@@ -311,6 +321,36 @@ public class TetheringTest {
int subId) {
return new MockTetheringConfiguration(ctx, log, subId);
}
+
+ @Override
+ public INetworkManagementService getINetworkManagementService() {
+ return mNMService;
+ }
+
+ @Override
+ public INetworkStatsService getINetworkStatsService() {
+ return mStatsService;
+ }
+
+ @Override
+ public INetworkPolicyManager getINetworkPolicyManager() {
+ return mPolicyManager;
+ }
+
+ @Override
+ public INetd getINetd(Context context) {
+ return mNetd;
+ }
+
+ @Override
+ public Looper getTetheringLooper() {
+ return mLooper.getLooper();
+ }
+
+ @Override
+ public Context getContext() {
+ return mServiceContext;
+ }
}
private static NetworkState buildMobileUpstreamState(boolean withIPv4, boolean withIPv6,
@@ -345,7 +385,7 @@ public class TetheringTest {
final NetworkCapabilities capabilities = new NetworkCapabilities()
- .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);;
+ .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
return new NetworkState(info, prop, capabilities, new Network(100), null, "netid");
}
@@ -390,7 +430,7 @@ public class TetheringTest {
when(mRouterAdvertisementDaemon.start())
.thenReturn(true);
- mServiceContext = new MockContext(mContext);
+ mServiceContext = new TestContext(mContext);
mContentResolver = new MockContentResolver(mServiceContext);
mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
Settings.Global.putInt(mContentResolver, TETHER_ENABLE_LEGACY_DHCP_SERVER, 0);
@@ -403,9 +443,9 @@ public class TetheringTest {
};
mServiceContext.registerReceiver(mBroadcastReceiver,
new IntentFilter(ACTION_TETHER_STATE_CHANGED));
- mTetheringDependencies.reset();
mTethering = makeTethering();
verify(mNMService).registerTetheringStatsProvider(any(), anyString());
+ verify(mNetd).registerUnsolicitedEventListener(any());
final ArgumentCaptor<PhoneStateListener> phoneListenerCaptor =
ArgumentCaptor.forClass(PhoneStateListener.class);
verify(mTelephonyManager).listen(phoneListenerCaptor.capture(),
@@ -414,9 +454,8 @@ public class TetheringTest {
}
private Tethering makeTethering() {
- return new Tethering(mServiceContext, mNMService, mStatsService, mPolicyManager,
- mLooper.getLooper(), mSystemProperties,
- mTetheringDependencies);
+ mTetheringDependencies.reset();
+ return new Tethering(mTetheringDependencies);
}
@After
@@ -507,7 +546,7 @@ public class TetheringTest {
// it creates a IpServer and sends out a broadcast indicating that the
// interface is "available".
if (emulateInterfaceStatusChanged) {
- assertEquals(1, mTetheringDependencies.isTetheringSupportedCalls);
+ assertEquals(1, mTetheringDependencies.mIsTetheringSupportedCalls);
verifyTetheringBroadcast(TEST_WLAN_IFNAME, EXTRA_AVAILABLE_TETHER);
verify(mWifiManager).updateInterfaceIpState(
TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_UNSPECIFIED);
@@ -584,7 +623,7 @@ public class TetheringTest {
verify(mUpstreamNetworkMonitor, times(1)).startObserveAllNetworks();
// This will be called twice, one is on entering IpServer.STATE_AVAILABLE,
// and another one is on IpServer.STATE_TETHERED/IpServer.STATE_LOCAL_ONLY.
- assertEquals(2, mTetheringDependencies.isTetheringSupportedCalls);
+ assertEquals(2, mTetheringDependencies.mIsTetheringSupportedCalls);
// Emulate externally-visible WifiManager effects, when hotspot mode
// is being torn down.
@@ -617,8 +656,7 @@ public class TetheringTest {
argThat(sm -> sm.linkProperties().getInterfaceName().equals(TEST_USB_IFNAME)),
eq(IpServer.STATE_TETHERED));
- for (IpServer ipSrv :
- mTetheringDependencies.ipv6CoordinatorNotifyList) {
+ for (IpServer ipSrv : mTetheringDependencies.mIpv6CoordinatorNotifyList) {
NetworkState ipv6OnlyState = buildMobileUpstreamState(false, true, false);
ipSrv.sendMessage(IpServer.CMD_IPV6_TETHER_UPDATE, 0, 0,
upstreamState.linkProperties.isIpv6Provisioned()
@@ -650,7 +688,7 @@ public class TetheringTest {
@Test
public void workingMobileUsbTethering_IPv4LegacyDhcp() {
Settings.Global.putInt(mContentResolver, TETHER_ENABLE_LEGACY_DHCP_SERVER, 1);
- mTethering = makeTethering();
+ sendConfigurationChanged();
final NetworkState upstreamState = buildMobileIPv4UpstreamState();
runUsbTethering(upstreamState);
sendIPv6TetherUpdates(upstreamState);
@@ -719,7 +757,7 @@ public class TetheringTest {
.thenReturn(upstreamState);
// Upstream LinkProperties changed: UpstreamNetworkMonitor sends EVENT_ON_LINKPROPERTIES.
- mTetheringDependencies.upstreamNetworkMonitorMasterSM.sendMessage(
+ mTetheringDependencies.mUpstreamNetworkMonitorMasterSM.sendMessage(
Tethering.TetherMasterSM.EVENT_UPSTREAM_CALLBACK,
UpstreamNetworkMonitor.EVENT_ON_LINKPROPERTIES,
0,
@@ -784,7 +822,7 @@ public class TetheringTest {
sendWifiApStateChanged(WIFI_AP_STATE_ENABLED);
mLooper.dispatchAll();
- assertEquals(1, mTetheringDependencies.isTetheringSupportedCalls);
+ assertEquals(1, mTetheringDependencies.mIsTetheringSupportedCalls);
verifyTetheringBroadcast(TEST_WLAN_IFNAME, EXTRA_AVAILABLE_TETHER);
verify(mWifiManager).updateInterfaceIpState(
TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_UNSPECIFIED);
@@ -828,7 +866,7 @@ public class TetheringTest {
verify(mUpstreamNetworkMonitor, times(1)).registerMobileNetworkRequest();
// This will be called twice, one is on entering IpServer.STATE_AVAILABLE,
// and another one is on IpServer.STATE_TETHERED/IpServer.STATE_LOCAL_ONLY.
- assertEquals(2, mTetheringDependencies.isTetheringSupportedCalls);
+ assertEquals(2, mTetheringDependencies.mIsTetheringSupportedCalls);
/////
// We do not currently emulate any upstream being found.
@@ -901,7 +939,7 @@ public class TetheringTest {
TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_TETHERED);
// There are 3 state change event:
// AVAILABLE -> STATE_TETHERED -> STATE_AVAILABLE.
- assertEquals(3, mTetheringDependencies.isTetheringSupportedCalls);
+ assertEquals(3, mTetheringDependencies.mIsTetheringSupportedCalls);
verifyTetheringBroadcast(TEST_WLAN_IFNAME, EXTRA_AVAILABLE_TETHER);
// This is called, but will throw.
verify(mNMService, times(1)).setIpForwardingEnabled(true);
@@ -918,26 +956,26 @@ public class TetheringTest {
verifyNoMoreInteractions(mNMService);
}
- private void userRestrictionsListenerBehaviour(
- boolean currentDisallow, boolean nextDisallow, String[] activeTetheringIfacesList,
- int expectedInteractionsWithShowNotification) throws Exception {
- final int userId = 0;
- final Bundle currRestrictions = new Bundle();
+ private void runUserRestrictionsChange(
+ boolean currentDisallow, boolean nextDisallow, String[] activeTetheringIfacesList,
+ int expectedInteractionsWithShowNotification) throws Exception {
final Bundle newRestrictions = new Bundle();
- Tethering tethering = mock(Tethering.class);
- Tethering.TetheringUserRestrictionListener turl =
- new Tethering.TetheringUserRestrictionListener(tethering);
-
- currRestrictions.putBoolean(UserManager.DISALLOW_CONFIG_TETHERING, currentDisallow);
newRestrictions.putBoolean(UserManager.DISALLOW_CONFIG_TETHERING, nextDisallow);
- when(tethering.getTetheredIfaces()).thenReturn(activeTetheringIfacesList);
+ final Tethering mockTethering = mock(Tethering.class);
+ when(mockTethering.getTetheredIfaces()).thenReturn(activeTetheringIfacesList);
+ when(mUserManager.getUserRestrictions()).thenReturn(newRestrictions);
- turl.onUserRestrictionsChanged(userId, newRestrictions, currRestrictions);
+ final Tethering.UserRestrictionActionListener ural =
+ new Tethering.UserRestrictionActionListener(mUserManager, mockTethering);
+ ural.mDisallowTethering = currentDisallow;
- verify(tethering, times(expectedInteractionsWithShowNotification))
+ ural.onUserRestrictionsChanged();
+
+ verify(mockTethering, times(expectedInteractionsWithShowNotification))
.showTetheredNotification(anyInt(), eq(false));
- verify(tethering, times(expectedInteractionsWithShowNotification)).untetherAll();
+ verify(mockTethering, times(expectedInteractionsWithShowNotification))
+ .untetherAll();
}
@Test
@@ -947,7 +985,7 @@ public class TetheringTest {
final boolean nextDisallow = true;
final int expectedInteractionsWithShowNotification = 0;
- userRestrictionsListenerBehaviour(currDisallow, nextDisallow, emptyActiveIfacesList,
+ runUserRestrictionsChange(currDisallow, nextDisallow, emptyActiveIfacesList,
expectedInteractionsWithShowNotification);
}
@@ -958,7 +996,7 @@ public class TetheringTest {
final boolean nextDisallow = true;
final int expectedInteractionsWithShowNotification = 1;
- userRestrictionsListenerBehaviour(currDisallow, nextDisallow, nonEmptyActiveIfacesList,
+ runUserRestrictionsChange(currDisallow, nextDisallow, nonEmptyActiveIfacesList,
expectedInteractionsWithShowNotification);
}
@@ -969,7 +1007,7 @@ public class TetheringTest {
final boolean nextDisallow = false;
final int expectedInteractionsWithShowNotification = 0;
- userRestrictionsListenerBehaviour(currDisallow, nextDisallow, nonEmptyActiveIfacesList,
+ runUserRestrictionsChange(currDisallow, nextDisallow, nonEmptyActiveIfacesList,
expectedInteractionsWithShowNotification);
}
@@ -980,7 +1018,7 @@ public class TetheringTest {
final boolean nextDisallow = false;
final int expectedInteractionsWithShowNotification = 0;
- userRestrictionsListenerBehaviour(currDisallow, nextDisallow, nonEmptyActiveIfacesList,
+ runUserRestrictionsChange(currDisallow, nextDisallow, nonEmptyActiveIfacesList,
expectedInteractionsWithShowNotification);
}
@@ -991,27 +1029,59 @@ public class TetheringTest {
boolean currDisallow = true;
boolean nextDisallow = true;
- userRestrictionsListenerBehaviour(currDisallow, nextDisallow, nonEmptyActiveIfacesList,
+ runUserRestrictionsChange(currDisallow, nextDisallow, nonEmptyActiveIfacesList,
expectedInteractionsWithShowNotification);
currDisallow = false;
nextDisallow = false;
- userRestrictionsListenerBehaviour(currDisallow, nextDisallow, nonEmptyActiveIfacesList,
+ runUserRestrictionsChange(currDisallow, nextDisallow, nonEmptyActiveIfacesList,
expectedInteractionsWithShowNotification);
}
- private class TestTetheringEventCallback extends ITetheringEventCallback.Stub {
+ private class TestTetherInternalCallback extends ITetherInternalCallback.Stub {
private final ArrayList<Network> mActualUpstreams = new ArrayList<>();
-
+ private final ArrayList<TetheringConfigurationParcel> mTetheringConfigs =
+ new ArrayList<>();
+ private final ArrayList<TetherStatesParcel> mTetherStates = new ArrayList<>();
+
+ // This function will remove the recorded callbacks, so it must be called once for
+ // each callback. If this is called after multiple callback, the order matters.
+ // onCallbackCreated counts as the first call to expectUpstreamChanged with
+ // @see onCallbackCreated.
public void expectUpstreamChanged(Network... networks) {
+ if (networks == null) {
+ assertNoUpstreamChangeCallback();
+ return;
+ }
+
final ArrayList<Network> expectedUpstreams =
new ArrayList<Network>(Arrays.asList(networks));
for (Network upstream : expectedUpstreams) {
// throws OOB if no expectations
assertEquals(mActualUpstreams.remove(0), upstream);
}
- assertNoCallback();
+ assertNoUpstreamChangeCallback();
+ }
+
+ // This function will remove the recorded callbacks, so it must be called once
+ // for each callback. If this is called after multiple callback, the order matters.
+ // onCallbackCreated counts as the first call to onConfigurationChanged with
+ // @see onCallbackCreated.
+ public void expectConfigurationChanged(TetheringConfigurationParcel... tetherConfigs) {
+ final ArrayList<TetheringConfigurationParcel> expectedTetherConfig =
+ new ArrayList<TetheringConfigurationParcel>(Arrays.asList(tetherConfigs));
+ for (TetheringConfigurationParcel config : expectedTetherConfig) {
+ // throws OOB if no expectations
+ final TetheringConfigurationParcel actualConfig = mTetheringConfigs.remove(0);
+ assertTetherConfigParcelEqual(actualConfig, config);
+ }
+ assertNoConfigChangeCallback();
+ }
+
+ public TetherStatesParcel pollTetherStatesChanged() {
+ assertStateChangeCallback();
+ return mTetherStates.remove(0);
}
@Override
@@ -1019,48 +1089,93 @@ public class TetheringTest {
mActualUpstreams.add(network);
}
- public void assertNoCallback() {
+ @Override
+ public void onConfigurationChanged(TetheringConfigurationParcel config) {
+ mTetheringConfigs.add(config);
+ }
+
+ @Override
+ public void onTetherStatesChanged(TetherStatesParcel states) {
+ mTetherStates.add(states);
+ }
+
+ @Override
+ public void onCallbackCreated(Network network, TetheringConfigurationParcel config,
+ TetherStatesParcel states) {
+ mActualUpstreams.add(network);
+ mTetheringConfigs.add(config);
+ mTetherStates.add(states);
+ }
+
+ public void assertNoUpstreamChangeCallback() {
assertTrue(mActualUpstreams.isEmpty());
}
+
+ public void assertNoConfigChangeCallback() {
+ assertTrue(mTetheringConfigs.isEmpty());
+ }
+
+ public void assertStateChangeCallback() {
+ assertFalse(mTetherStates.isEmpty());
+ }
+
+ private void assertTetherConfigParcelEqual(@NonNull TetheringConfigurationParcel actual,
+ @NonNull TetheringConfigurationParcel expect) {
+ assertEquals(actual.subId, expect.subId);
+ assertArrayEquals(actual.tetherableUsbRegexs, expect.tetherableUsbRegexs);
+ assertArrayEquals(actual.tetherableWifiRegexs, expect.tetherableWifiRegexs);
+ assertArrayEquals(actual.tetherableBluetoothRegexs, expect.tetherableBluetoothRegexs);
+ assertEquals(actual.isDunRequired, expect.isDunRequired);
+ assertEquals(actual.chooseUpstreamAutomatically, expect.chooseUpstreamAutomatically);
+ assertArrayEquals(actual.preferredUpstreamIfaceTypes,
+ expect.preferredUpstreamIfaceTypes);
+ assertArrayEquals(actual.legacyDhcpRanges, expect.legacyDhcpRanges);
+ assertArrayEquals(actual.defaultIPv4DNS, expect.defaultIPv4DNS);
+ assertEquals(actual.enableLegacyDhcpServer, expect.enableLegacyDhcpServer);
+ assertArrayEquals(actual.provisioningApp, expect.provisioningApp);
+ assertEquals(actual.provisioningAppNoUi, expect.provisioningAppNoUi);
+ assertEquals(actual.provisioningCheckPeriod, expect.provisioningCheckPeriod);
+ }
}
@Test
- public void testRegisterTetheringEventCallback() throws Exception {
- TestTetheringEventCallback callback1 = new TestTetheringEventCallback();
- TestTetheringEventCallback callback2 = new TestTetheringEventCallback();
+ public void testRegisterTetherInternalCallback() throws Exception {
+ TestTetherInternalCallback callback = new TestTetherInternalCallback();
- // 1. Register one callback and run usb tethering.
- mTethering.registerTetheringEventCallback(callback1);
+ // 1. Register one callback before running any tethering.
+ mTethering.registerTetherInternalCallback(callback);
mLooper.dispatchAll();
- callback1.expectUpstreamChanged(new Network[] {null});
+ callback.expectUpstreamChanged(new Network[] {null});
+ callback.expectConfigurationChanged(
+ mTethering.getTetheringConfiguration().toStableParcelable());
+ TetherStatesParcel tetherState = callback.pollTetherStatesChanged();
+ assertEquals(tetherState, null);
+ // 2. Enable wifi tethering
NetworkState upstreamState = buildMobileDualStackUpstreamState();
- runUsbTethering(upstreamState);
- callback1.expectUpstreamChanged(upstreamState.network);
- // 2. Register second callback.
- mTethering.registerTetheringEventCallback(callback2);
- mLooper.dispatchAll();
- callback2.expectUpstreamChanged(upstreamState.network);
- // 3. Disable usb tethering.
- mTethering.stopTethering(TETHERING_USB);
- mLooper.dispatchAll();
- sendUsbBroadcast(false, false, false);
- mLooper.dispatchAll();
- callback1.expectUpstreamChanged(new Network[] {null});
- callback2.expectUpstreamChanged(new Network[] {null});
- // 4. Unregister first callback and run hotspot.
- mTethering.unregisterTetheringEventCallback(callback1);
- mLooper.dispatchAll();
when(mUpstreamNetworkMonitor.getCurrentPreferredUpstream()).thenReturn(upstreamState);
when(mUpstreamNetworkMonitor.selectPreferredUpstreamType(any()))
.thenReturn(upstreamState);
when(mWifiManager.startSoftAp(any(WifiConfiguration.class))).thenReturn(true);
- mTethering.startTethering(TETHERING_WIFI, null, false);
- mLooper.dispatchAll();
mTethering.interfaceStatusChanged(TEST_WLAN_IFNAME, true);
+ mLooper.dispatchAll();
+ tetherState = callback.pollTetherStatesChanged();
+ assertArrayEquals(tetherState.availableList, new String[] {TEST_WLAN_IFNAME});
+
+ mTethering.startTethering(TETHERING_WIFI, null, false);
sendWifiApStateChanged(WIFI_AP_STATE_ENABLED, TEST_WLAN_IFNAME, IFACE_IP_MODE_TETHERED);
mLooper.dispatchAll();
- callback1.assertNoCallback();
- callback2.expectUpstreamChanged(upstreamState.network);
+ tetherState = callback.pollTetherStatesChanged();
+ assertArrayEquals(tetherState.tetheredList, new String[] {TEST_WLAN_IFNAME});
+ callback.expectUpstreamChanged(upstreamState.network);
+
+ // 3. Disable wifi tethering.
+ mTethering.stopTethering(TETHERING_WIFI);
+ sendWifiApStateChanged(WifiManager.WIFI_AP_STATE_DISABLED);
+ mLooper.dispatchAll();
+ tetherState = callback.pollTetherStatesChanged();
+ assertArrayEquals(tetherState.availableList, new String[] {TEST_WLAN_IFNAME});
+ mLooper.dispatchAll();
+ callback.expectUpstreamChanged(new Network[] {null});
}
@Test
@@ -1091,7 +1206,7 @@ public class TetheringTest {
verify(mUpstreamNetworkMonitor, times(1)).startObserveAllNetworks();
// This will be called twice, one is on entering IpServer.STATE_AVAILABLE,
// and another one is on IpServer.STATE_TETHERED/IpServer.STATE_LOCAL_ONLY.
- assertEquals(2, mTetheringDependencies.isTetheringSupportedCalls);
+ assertEquals(2, mTetheringDependencies.mIsTetheringSupportedCalls);
assertEquals(TETHER_ERROR_NO_ERROR, mTethering.getLastTetherError(TEST_P2P_IFNAME));
diff --git a/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java b/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java
index 1c2c640daa7b..8a4a1c666c3c 100644
--- a/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java
+++ b/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java
@@ -153,6 +153,7 @@ public class WallpaperBackupAgent extends BackupAgent {
Slog.v(TAG, "lockGen=" + lockGeneration + " : lockChanged=" + lockChanged);
Slog.v(TAG, "sysEligble=" + sysEligible);
Slog.v(TAG, "lockEligible=" + lockEligible);
+ Slog.v(TAG, "hasLockWallpaper=" + hasLockWallpaper);
}
// only back up the wallpapers if we've been told they're eligible
@@ -174,6 +175,17 @@ public class WallpaperBackupAgent extends BackupAgent {
prefs.edit().putInt(SYSTEM_GENERATION, sysGeneration).apply();
}
+ // If there's no lock wallpaper, then we have nothing to add to the backup.
+ if (lockGeneration == -1) {
+ if (lockChanged && lockImageStage.exists()) {
+ if (DEBUG) Slog.v(TAG, "Removed lock wallpaper; deleting");
+ lockImageStage.delete();
+ }
+ if (DEBUG) Slog.v(TAG, "No lock paper set, add nothing to backup");
+ prefs.edit().putInt(LOCK_GENERATION, lockGeneration).apply();
+ return;
+ }
+
// Don't try to store the lock image if we overran our quota last time
if (lockEligible && hasLockWallpaper && mLockWallpaperFile.exists() && !mQuotaExceeded) {
if (lockChanged || !lockImageStage.exists()) {
diff --git a/packages/WallpaperBackup/test/src/com/android/wallpaperbackup/tests/WallpaperBackupAgentTest.java b/packages/WallpaperBackup/test/src/com/android/wallpaperbackup/tests/WallpaperBackupAgentTest.java
index 46a7dfeed233..255fdef36cd7 100644
--- a/packages/WallpaperBackup/test/src/com/android/wallpaperbackup/tests/WallpaperBackupAgentTest.java
+++ b/packages/WallpaperBackup/test/src/com/android/wallpaperbackup/tests/WallpaperBackupAgentTest.java
@@ -19,8 +19,13 @@ package com.android.wallpaperbackup.tests;
import static android.app.WallpaperManager.FLAG_LOCK;
import static android.app.WallpaperManager.FLAG_SYSTEM;
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -40,6 +45,7 @@ import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.junit.runner.RunWith;
+import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -53,78 +59,109 @@ public class WallpaperBackupAgentTest {
private static final String SYSTEM_GENERATION = "system_gen";
private static final String LOCK_GENERATION = "lock_gen";
+ private static final int TEST_SYSTEM_WALLPAPER_ID = 1;
+ private static final int TEST_LOCK_WALLPAPER_ID = 2;
+
@Mock private FullBackupDataOutput mOutput;
@Mock private WallpaperManager mWallpaperManager;
@Mock private SharedPreferences mSharedPreferences;
+ @Mock private SharedPreferences.Editor mSharedPreferenceEditor;
@Rule public TemporaryFolder mTemporaryFolder = new TemporaryFolder();
private ContextWithServiceOverrides mContext;
+ private IsolatedWallpaperBackupAgent mWallpaperBackupAgent;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
+ when(mSharedPreferences.edit()).thenReturn(mSharedPreferenceEditor);
+ when(mSharedPreferenceEditor.putInt(anyString(), anyInt()))
+ .thenReturn(mSharedPreferenceEditor);
+ doNothing().when(mSharedPreferenceEditor).apply();
+
mContext = new ContextWithServiceOverrides(ApplicationProvider.getApplicationContext());
mContext.injectSystemService(WallpaperManager.class, mWallpaperManager);
mContext.setSharedPreferencesOverride(mSharedPreferences);
+
+ mWallpaperBackupAgent = new IsolatedWallpaperBackupAgent(mTemporaryFolder.getRoot());
+ mWallpaperBackupAgent.attach(mContext);
+ mWallpaperBackupAgent.onCreate();
}
@Test
public void testOnFullBackup_withNoChanges_onlyBacksUpEmptyFile() throws IOException {
- WallpaperBackupAgent wallpaperBackupAgent = new WallpaperBackupAgent();
- initialiseAgent(wallpaperBackupAgent);
-
- when(mWallpaperManager.getWallpaperIdForUser(eq(FLAG_SYSTEM), eq(UserHandle.USER_SYSTEM)))
- .thenReturn(1);
- when(mWallpaperManager.getWallpaperIdForUser(eq(FLAG_LOCK), eq(UserHandle.USER_SYSTEM)))
- .thenReturn(1);
- when(mSharedPreferences.getInt(eq(SYSTEM_GENERATION), eq(-1))).thenReturn(1);
- when(mSharedPreferences.getInt(eq(LOCK_GENERATION), eq(-1))).thenReturn(1);
+ mockBackedUpState();
+ mockCurrentWallpapers(TEST_SYSTEM_WALLPAPER_ID, TEST_LOCK_WALLPAPER_ID);
- wallpaperBackupAgent.onFullBackup(mOutput);
+ mWallpaperBackupAgent.onFullBackup(mOutput);
- verify(mOutput); // Backup of empty file only
+ assertThat(mWallpaperBackupAgent.mBackedUpFiles.size()).isEqualTo(1);
+ assertThat(mWallpaperBackupAgent.mBackedUpFiles.get(0).getName()).isEqualTo("empty");
}
@Test
public void testOnFullBackup_withOnlyChangedSystem_updatesTheSharedPreferences()
throws IOException {
- // Create a system wallpaper file
- mTemporaryFolder.newFile("wallpaper_orig");
- // Create stageing file to simulate he wallpaper being ready to back up
- new File(mContext.getFilesDir(), "wallpaper-stage").createNewFile();
+ mockSystemWallpaperReadyToBackUp();
+ mockUnbackedUpState();
+ mockCurrentWallpapers(TEST_SYSTEM_WALLPAPER_ID, TEST_LOCK_WALLPAPER_ID);
- WallpaperBackupAgent wallpaperBackupAgent =
- new IsolatedWallpaperBackupAgent(mTemporaryFolder.getRoot());
- initialiseAgent(wallpaperBackupAgent);
+ mWallpaperBackupAgent.onFullBackup(mOutput);
- SharedPreferences.Editor preferenceEditor = mock(SharedPreferences.Editor.class);
+ verify(mSharedPreferenceEditor).putInt(eq(SYSTEM_GENERATION), eq(TEST_SYSTEM_WALLPAPER_ID));
+ }
+ @Test
+ public void testOnFullBackup_withLockChangedToMatchSystem_updatesTheSharedPreferences()
+ throws IOException {
+ mockBackedUpState();
+ mockSystemWallpaperReadyToBackUp();
+ mockCurrentWallpapers(TEST_SYSTEM_WALLPAPER_ID, -1);
+
+ mWallpaperBackupAgent.onFullBackup(mOutput);
+
+ InOrder inOrder = inOrder(mSharedPreferenceEditor);
+ inOrder.verify(mSharedPreferenceEditor)
+ .putInt(eq(SYSTEM_GENERATION), eq(TEST_SYSTEM_WALLPAPER_ID));
+ inOrder.verify(mSharedPreferenceEditor).apply();
+ inOrder.verify(mSharedPreferenceEditor).putInt(eq(LOCK_GENERATION), eq(-1));
+ inOrder.verify(mSharedPreferenceEditor).apply();
+ }
+
+ private void mockUnbackedUpState() {
+ mockCurrentWallpapers(TEST_SYSTEM_WALLPAPER_ID, TEST_LOCK_WALLPAPER_ID);
+ when(mSharedPreferences.getInt(eq(SYSTEM_GENERATION), eq(-1))).thenReturn(-1);
+ when(mSharedPreferences.getInt(eq(LOCK_GENERATION), eq(-1))).thenReturn(-1);
+ }
+
+ private void mockBackedUpState() {
+ when(mSharedPreferences.getInt(eq(SYSTEM_GENERATION), eq(-1)))
+ .thenReturn(TEST_SYSTEM_WALLPAPER_ID);
+ when(mSharedPreferences.getInt(eq(LOCK_GENERATION), eq(-1)))
+ .thenReturn(TEST_LOCK_WALLPAPER_ID);
+ }
+
+ private void mockCurrentWallpapers(int systemWallpaperId, int lockWallpaperId) {
when(mWallpaperManager.getWallpaperIdForUser(eq(FLAG_SYSTEM), eq(UserHandle.USER_SYSTEM)))
- .thenReturn(2);
+ .thenReturn(systemWallpaperId);
when(mWallpaperManager.getWallpaperIdForUser(eq(FLAG_LOCK), eq(UserHandle.USER_SYSTEM)))
- .thenReturn(1);
+ .thenReturn(lockWallpaperId);
when(mWallpaperManager.isWallpaperBackupEligible(eq(FLAG_SYSTEM))).thenReturn(true);
when(mWallpaperManager.isWallpaperBackupEligible(eq(FLAG_LOCK))).thenReturn(true);
- when(mSharedPreferences.getInt(eq(SYSTEM_GENERATION), eq(-1))).thenReturn(1);
- when(mSharedPreferences.getInt(eq(LOCK_GENERATION), eq(-1))).thenReturn(1);
- when(mSharedPreferences.edit()).thenReturn(preferenceEditor);
- when(preferenceEditor.putInt(eq(SYSTEM_GENERATION), eq(2))).thenReturn(preferenceEditor);
-
- wallpaperBackupAgent.onFullBackup(mOutput);
-
- verify(preferenceEditor).putInt(eq(SYSTEM_GENERATION), eq(2));
}
- private void initialiseAgent(WallpaperBackupAgent agent) {
- agent.attach(mContext);
- agent.onCreate();
+ private void mockSystemWallpaperReadyToBackUp() throws IOException {
+ // Create a system wallpaper file
+ mTemporaryFolder.newFile("wallpaper_orig");
+ // Create staging file to simulate he wallpaper being ready to back up
+ new File(mContext.getFilesDir(), "wallpaper-stage").createNewFile();
}
- private static class IsolatedWallpaperBackupAgent extends WallpaperBackupAgent {
+ private class IsolatedWallpaperBackupAgent extends WallpaperBackupAgent {
File mWallpaperBaseDirectory;
- List<File> mBackedUpFiles = new ArrayList();
+ List<File> mBackedUpFiles = new ArrayList<>();
IsolatedWallpaperBackupAgent(File wallpaperBaseDirectory) {
mWallpaperBaseDirectory = wallpaperBaseDirectory;
@@ -139,5 +176,10 @@ public class WallpaperBackupAgentTest {
protected void backupFile(File file, FullBackupDataOutput data) {
mBackedUpFiles.add(file);
}
+
+ @Override
+ public SharedPreferences getSharedPreferences(File file, int mode) {
+ return mSharedPreferences;
+ }
}
}
diff --git a/services/Android.bp b/services/Android.bp
index 35dc44e0ac65..041631b74380 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -28,7 +28,6 @@ filegroup {
":services.usage-sources",
":services.usb-sources",
":services.voiceinteraction-sources",
- ":services.wifi-sources",
],
visibility: ["//visibility:private"],
}
@@ -68,7 +67,6 @@ java_library {
"services.usage",
"services.usb",
"services.voiceinteraction",
- "services.wifi",
"android.hidl.base-V1.0-java",
],
diff --git a/services/autofill/java/com/android/server/autofill/ui/FillUi.java b/services/autofill/java/com/android/server/autofill/ui/FillUi.java
index 70fb535bed57..57961423061f 100644
--- a/services/autofill/java/com/android/server/autofill/ui/FillUi.java
+++ b/services/autofill/java/com/android/server/autofill/ui/FillUi.java
@@ -383,7 +383,7 @@ final class FillUi {
}
child.setOnClickListener((v) -> {
if (sVerbose) {
- Slog.v(TAG, "Applying " + id + " after " + v + " was clicked");
+ Slog.v(TAG, " Cancelling session after " + v + " clicked");
}
mCallback.cancelSession();
});
diff --git a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
index d7114a0b9a62..8eea04759cdb 100644
--- a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
+++ b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
@@ -291,10 +291,17 @@ final class SaveUi {
}
final TextView noButton = view.findViewById(R.id.autofill_save_no);
- if (info.getNegativeActionStyle() == SaveInfo.NEGATIVE_BUTTON_STYLE_REJECT) {
- noButton.setText(R.string.save_password_notnow);
- } else {
- noButton.setText(R.string.autofill_save_no);
+ final int negativeActionStyle = info.getNegativeActionStyle();
+ switch (negativeActionStyle) {
+ case SaveInfo.NEGATIVE_BUTTON_STYLE_REJECT:
+ noButton.setText(R.string.autofill_save_notnow);
+ break;
+ case SaveInfo.NEGATIVE_BUTTON_STYLE_NEVER:
+ noButton.setText(R.string.autofill_save_never);
+ break;
+ case SaveInfo.NEGATIVE_BUTTON_STYLE_CANCEL:
+ default:
+ noButton.setText(R.string.autofill_save_no);
}
noButton.setOnClickListener((v) -> mListener.onCancel(info.getNegativeActionListener()));
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index 222a6f210448..e8c5299f47a3 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -67,6 +67,7 @@ import java.io.File;
import java.io.FileDescriptor;
import java.io.IOException;
import java.io.PrintWriter;
+import java.util.List;
import java.util.Set;
/**
@@ -1510,6 +1511,26 @@ public class BackupManagerService extends IBackupManager.Stub {
}
/**
+ * Excludes keys from KV restore for a given package. The corresponding data will be excluded
+ * from the data set available the backup agent during restore. However, final list of keys
+ * that have been excluded will be passed to the agent to make it aware of the exclusions.
+ */
+ public void excludeKeysFromRestore(String packageName, List<String> keys) {
+ int userId = Binder.getCallingUserHandle().getIdentifier();
+ if (!isUserReadyForBackup(userId)) {
+ Slog.w(TAG, "Returning from excludeKeysFromRestore as backup for user" + userId +
+ " is not initialized yet");
+ return;
+ }
+ UserBackupManagerService userBackupManagerService =
+ getServiceForUserIfCallerHasPermission(userId, "excludeKeysFromRestore()");
+
+ if (userBackupManagerService != null) {
+ userBackupManagerService.excludeKeysFromRestore(packageName, keys);
+ }
+ }
+
+ /**
* Returns the {@link UserBackupManagerService} instance for the specified user {@code userId}.
* If the user is not registered with the service (either the user is locked or not eligible for
* the backup service) then return {@code null}.
diff --git a/services/backup/java/com/android/server/backup/DataChangedJournal.java b/services/backup/java/com/android/server/backup/DataChangedJournal.java
index 498185c9a645..e75eb731a73e 100644
--- a/services/backup/java/com/android/server/backup/DataChangedJournal.java
+++ b/services/backup/java/com/android/server/backup/DataChangedJournal.java
@@ -17,6 +17,7 @@
package com.android.server.backup;
import android.annotation.Nullable;
+import android.util.Slog;
import java.io.BufferedInputStream;
import java.io.DataInputStream;
@@ -36,6 +37,7 @@ import java.util.function.Consumer;
* reboot.
*/
public class DataChangedJournal {
+ private static final String TAG = "DataChangedJournal";
private static final String FILE_NAME_PREFIX = "journal";
/**
@@ -139,7 +141,12 @@ public class DataChangedJournal {
*/
static ArrayList<DataChangedJournal> listJournals(File journalDirectory) {
ArrayList<DataChangedJournal> journals = new ArrayList<>();
- for (File file : journalDirectory.listFiles()) {
+ File[] journalFiles = journalDirectory.listFiles();
+ if (journalFiles == null) {
+ Slog.w(TAG, "Failed to read journal files");
+ return journals;
+ }
+ for (File file : journalFiles) {
journals.add(new DataChangedJournal(file));
}
return journals;
diff --git a/services/backup/java/com/android/server/backup/UserBackupManagerService.java b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
index 77888db416a5..56b345bb1324 100644
--- a/services/backup/java/com/android/server/backup/UserBackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
@@ -158,6 +158,7 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
+import java.util.Map;
import java.util.Queue;
import java.util.Random;
import java.util.Set;
@@ -332,6 +333,8 @@ public class UserBackupManagerService {
// locking around the pending-backup management
private final Object mQueueLock = new Object();
+ private final UserBackupPreferences mBackupPreferences;
+
// The thread performing the sequence of queued backups binds to each app's agent
// in succession. Bind notifications are asynchronously delivered through the
// Activity Manager; use this lock object to signal when a requested binding has
@@ -632,6 +635,8 @@ public class UserBackupManagerService {
// the pending backup set
mBackupHandler.postDelayed(this::parseLeftoverJournals, INITIALIZATION_DELAY_MILLIS);
+ mBackupPreferences = new UserBackupPreferences(mContext, mBaseStateDir);
+
// Power management
mWakelock = new BackupWakeLock(
mPowerManager.newWakeLock(
@@ -1097,6 +1102,14 @@ public class UserBackupManagerService {
}
}
+ public Map<String, Set<String>> getExcludedRestoreKeys(String... packages) {
+ return mBackupPreferences.getExcludedRestoreKeysForPackages(packages);
+ }
+
+ public Map<String, Set<String>> getAllExcludedRestoreKeys() {
+ return mBackupPreferences.getAllExcludedRestoreKeys();
+ }
+
/** Used for generating random salts or passwords. */
public byte[] randomBytes(int bits) {
byte[] array = new byte[bits / 8];
@@ -2746,6 +2759,14 @@ public class UserBackupManagerService {
}
}
+ /**
+ * Excludes keys from KV restore for a given package. The keys won't be part of the data passed
+ * to the backup agent during restore.
+ */
+ public void excludeKeysFromRestore(String packageName, List<String> keys) {
+ mBackupPreferences.addExcludedKeys(packageName, keys);
+ }
+
private boolean startConfirmationUi(int token, String action) {
try {
Intent confIntent = new Intent(action);
@@ -3341,7 +3362,8 @@ public class UserBackupManagerService {
restoreSet,
packageName,
token,
- listener);
+ listener,
+ getExcludedRestoreKeys(packageName));
mBackupHandler.sendMessage(msg);
} catch (Exception e) {
// Calling into the transport broke; back off and proceed with the installation.
diff --git a/services/backup/java/com/android/server/backup/UserBackupPreferences.java b/services/backup/java/com/android/server/backup/UserBackupPreferences.java
new file mode 100644
index 000000000000..41b9719d273b
--- /dev/null
+++ b/services/backup/java/com/android/server/backup/UserBackupPreferences.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.backup;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+
+import java.io.File;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/** Manages the persisted backup preferences per user. */
+public class UserBackupPreferences {
+ private static final String PREFERENCES_FILE = "backup_preferences";
+
+ private final SharedPreferences mPreferences;
+ private final SharedPreferences.Editor mEditor;
+
+ UserBackupPreferences(Context conext, File storageDir) {
+ File excludedKeysFile = new File(storageDir, PREFERENCES_FILE);
+ mPreferences = conext.getSharedPreferences(excludedKeysFile, Context.MODE_PRIVATE);
+ mEditor = mPreferences.edit();
+ }
+
+ void addExcludedKeys(String packageName, List<String> keys) {
+ Set<String> existingKeys =
+ new HashSet<>(mPreferences.getStringSet(packageName, Collections.emptySet()));
+ existingKeys.addAll(keys);
+ mEditor.putStringSet(packageName, existingKeys);
+ mEditor.commit();
+ }
+
+ Map<String, Set<String>> getExcludedRestoreKeysForPackages(String... packages) {
+ Map<String, Set<String>> excludedKeys = new HashMap<>();
+ for (String packageName : packages) {
+ excludedKeys.put(packageName,
+ mPreferences.getStringSet(packageName, Collections.emptySet()));
+ }
+ return excludedKeys;
+ }
+
+ Map<String, Set<String>> getAllExcludedRestoreKeys() {
+ return (Map<String, Set<String>>) mPreferences.getAll();
+ }
+}
diff --git a/services/backup/java/com/android/server/backup/internal/BackupHandler.java b/services/backup/java/com/android/server/backup/internal/BackupHandler.java
index 059b1b9379af..8c48b8455da4 100644
--- a/services/backup/java/com/android/server/backup/internal/BackupHandler.java
+++ b/services/backup/java/com/android/server/backup/internal/BackupHandler.java
@@ -279,7 +279,8 @@ public class BackupHandler extends Handler {
params.pmToken,
params.isSystemRestore,
params.filterSet,
- params.listener);
+ params.listener,
+ params.excludedKeys);
synchronized (backupManagerService.getPendingRestores()) {
if (backupManagerService.isRestoreInProgress()) {
diff --git a/services/backup/java/com/android/server/backup/params/RestoreParams.java b/services/backup/java/com/android/server/backup/params/RestoreParams.java
index c9a6b6038a93..09b7e3535e2e 100644
--- a/services/backup/java/com/android/server/backup/params/RestoreParams.java
+++ b/services/backup/java/com/android/server/backup/params/RestoreParams.java
@@ -24,6 +24,9 @@ import android.content.pm.PackageInfo;
import com.android.server.backup.internal.OnTaskFinishedListener;
import com.android.server.backup.transport.TransportClient;
+import java.util.Map;
+import java.util.Set;
+
public class RestoreParams {
public final TransportClient transportClient;
public final IRestoreObserver observer;
@@ -34,6 +37,7 @@ public class RestoreParams {
public final boolean isSystemRestore;
@Nullable public final String[] filterSet;
public final OnTaskFinishedListener listener;
+ public final Map<String, Set<String>> excludedKeys;
/**
* No kill after restore.
@@ -44,7 +48,8 @@ public class RestoreParams {
IBackupManagerMonitor monitor,
long token,
PackageInfo packageInfo,
- OnTaskFinishedListener listener) {
+ OnTaskFinishedListener listener,
+ Map<String, Set<String>> excludedKeys) {
return new RestoreParams(
transportClient,
observer,
@@ -54,7 +59,8 @@ public class RestoreParams {
/* pmToken */ 0,
/* isSystemRestore */ false,
/* filterSet */ null,
- listener);
+ listener,
+ excludedKeys);
}
/**
@@ -67,7 +73,8 @@ public class RestoreParams {
long token,
String packageName,
int pmToken,
- OnTaskFinishedListener listener) {
+ OnTaskFinishedListener listener,
+ Map<String, Set<String>> excludedKeys) {
String[] filterSet = {packageName};
return new RestoreParams(
transportClient,
@@ -78,7 +85,8 @@ public class RestoreParams {
pmToken,
/* isSystemRestore */ false,
filterSet,
- listener);
+ listener,
+ excludedKeys);
}
/**
@@ -89,7 +97,8 @@ public class RestoreParams {
IRestoreObserver observer,
IBackupManagerMonitor monitor,
long token,
- OnTaskFinishedListener listener) {
+ OnTaskFinishedListener listener,
+ Map<String, Set<String>> excludedKeys) {
return new RestoreParams(
transportClient,
observer,
@@ -99,7 +108,8 @@ public class RestoreParams {
/* pmToken */ 0,
/* isSystemRestore */ true,
/* filterSet */ null,
- listener);
+ listener,
+ excludedKeys);
}
/**
@@ -112,7 +122,8 @@ public class RestoreParams {
long token,
String[] filterSet,
boolean isSystemRestore,
- OnTaskFinishedListener listener) {
+ OnTaskFinishedListener listener,
+ Map<String, Set<String>> excludedKeys) {
return new RestoreParams(
transportClient,
observer,
@@ -122,7 +133,8 @@ public class RestoreParams {
/* pmToken */ 0,
isSystemRestore,
filterSet,
- listener);
+ listener,
+ excludedKeys);
}
private RestoreParams(
@@ -134,7 +146,8 @@ public class RestoreParams {
int pmToken,
boolean isSystemRestore,
@Nullable String[] filterSet,
- OnTaskFinishedListener listener) {
+ OnTaskFinishedListener listener,
+ Map<String, Set<String>> excludedKeys) {
this.transportClient = transportClient;
this.observer = observer;
this.monitor = monitor;
@@ -144,5 +157,6 @@ public class RestoreParams {
this.isSystemRestore = isSystemRestore;
this.filterSet = filterSet;
this.listener = listener;
+ this.excludedKeys = excludedKeys;
}
}
diff --git a/services/backup/java/com/android/server/backup/restore/ActiveRestoreSession.java b/services/backup/java/com/android/server/backup/restore/ActiveRestoreSession.java
index 5a57cdc39402..c0f76c39e04f 100644
--- a/services/backup/java/com/android/server/backup/restore/ActiveRestoreSession.java
+++ b/services/backup/java/com/android/server/backup/restore/ActiveRestoreSession.java
@@ -178,7 +178,8 @@ public class ActiveRestoreSession extends IRestoreSession.Stub {
observer,
monitor,
token,
- listener),
+ listener,
+ mBackupManagerService.getAllExcludedRestoreKeys()),
"RestoreSession.restoreAll()");
} finally {
Binder.restoreCallingIdentity(oldId);
@@ -271,7 +272,8 @@ public class ActiveRestoreSession extends IRestoreSession.Stub {
token,
packages,
/* isSystemRestore */ packages.length > 1,
- listener),
+ listener,
+ mBackupManagerService.getExcludedRestoreKeys(packages)),
"RestoreSession.restorePackages(" + packages.length + " packages)");
} finally {
Binder.restoreCallingIdentity(oldId);
@@ -363,7 +365,8 @@ public class ActiveRestoreSession extends IRestoreSession.Stub {
monitor,
token,
app,
- listener),
+ listener,
+ mBackupManagerService.getExcludedRestoreKeys(app.packageName)),
"RestoreSession.restorePackage(" + packageName + ")");
} finally {
Binder.restoreCallingIdentity(oldId);
diff --git a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
index 675a6ebaedfe..be597d7b40d6 100644
--- a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
+++ b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
@@ -52,6 +52,7 @@ import android.os.UserHandle;
import android.util.EventLog;
import android.util.Slog;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.backup.IBackupTransport;
import com.android.internal.util.Preconditions;
import com.android.server.AppWidgetBackupBridge;
@@ -77,6 +78,8 @@ import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
+import java.util.Map;
+import java.util.Set;
public class PerformUnifiedRestoreTask implements BackupRestoreTask {
@@ -151,6 +154,8 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask {
// When finished call listener
private final OnTaskFinishedListener mListener;
+ private final Map<String, Set<String>> mExcludedKeys;
+
// Key/value: bookkeeping about staged data and files for agent access
private File mBackupDataName;
private File mStageName;
@@ -161,6 +166,17 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask {
private final int mEphemeralOpToken;
private final BackupAgentTimeoutParameters mAgentTimeoutParameters;
+ @VisibleForTesting
+ PerformUnifiedRestoreTask(Map<String, Set<String>> excludedKeys) {
+ mExcludedKeys = excludedKeys;
+ mListener = null;
+ mAgentTimeoutParameters = null;
+ mTransportClient = null;
+ mTransportManager = null;
+ mEphemeralOpToken = 0;
+ mUserId = 0;
+ }
+
// This task can assume that the wakelock is properly held for it and doesn't have to worry
// about releasing it.
public PerformUnifiedRestoreTask(
@@ -173,7 +189,8 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask {
int pmToken,
boolean isFullSystemRestore,
@Nullable String[] filterSet,
- OnTaskFinishedListener listener) {
+ OnTaskFinishedListener listener,
+ Map<String, Set<String>> excludedKeys) {
this.backupManagerService = backupManagerService;
mUserId = backupManagerService.getUserId();
mTransportManager = backupManagerService.getTransportManager();
@@ -195,6 +212,8 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask {
backupManagerService.getAgentTimeoutParameters(),
"Timeout parameters cannot be null");
+ mExcludedKeys = excludedKeys;
+
if (targetPackage != null) {
// Single package restore
mAcceptSet = new ArrayList<>();
@@ -724,27 +743,7 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask {
BackupDataInput in = new BackupDataInput(stage.getFileDescriptor());
BackupDataOutput out = new BackupDataOutput(mBackupData.getFileDescriptor());
- byte[] buffer = new byte[8192]; // will grow when needed
- while (in.readNextHeader()) {
- final String key = in.getKey();
- final int size = in.getDataSize();
-
- // is this a special key?
- if (key.equals(KEY_WIDGET_STATE)) {
- if (DEBUG) {
- Slog.i(TAG, "Restoring widget state for " + packageName);
- }
- mWidgetData = new byte[size];
- in.readEntityData(mWidgetData, 0, size);
- } else {
- if (size > buffer.length) {
- buffer = new byte[size];
- }
- in.readEntityData(buffer, 0, size);
- out.writeEntityHeader(key, size);
- out.writeEntityData(buffer, size);
- }
- }
+ filterExcludedKeys(packageName, in, out);
mBackupData.close();
}
@@ -783,6 +782,39 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask {
}
}
+ @VisibleForTesting
+ void filterExcludedKeys(String packageName, BackupDataInput in, BackupDataOutput out)
+ throws Exception {
+ Set<String> excludedKeysForPackage = mExcludedKeys.get(packageName);
+
+ byte[] buffer = new byte[8192]; // will grow when needed
+ while (in.readNextHeader()) {
+ final String key = in.getKey();
+ final int size = in.getDataSize();
+
+ if (excludedKeysForPackage != null && excludedKeysForPackage.contains(key)) {
+ in.skipEntityData();
+ continue;
+ }
+
+ // is this a special key?
+ if (key.equals(KEY_WIDGET_STATE)) {
+ if (DEBUG) {
+ Slog.i(TAG, "Restoring widget state for " + packageName);
+ }
+ mWidgetData = new byte[size];
+ in.readEntityData(mWidgetData, 0, size);
+ } else {
+ if (size > buffer.length) {
+ buffer = new byte[size];
+ }
+ in.readEntityData(buffer, 0, size);
+ out.writeEntityHeader(key, size);
+ out.writeEntityData(buffer, size);
+ }
+ }
+ }
+
// state RESTORE_FULL : restore one package via streaming engine
private void restoreFull() {
// None of this can run on the work looper here, so we spin asynchronous
diff --git a/services/core/Android.bp b/services/core/Android.bp
index 594ac104ebd0..2eb2f334981c 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -83,9 +83,9 @@ java_library_static {
":storaged_aidl",
":vold_aidl",
":platform-compat-config",
- ":tethering-servicescore-srcs",
"java/com/android/server/EventLogTags.logtags",
"java/com/android/server/am/EventLogTags.logtags",
+ "java/com/android/server/wm/EventLogTags.logtags",
"java/com/android/server/policy/EventLogTags.logtags",
],
@@ -114,7 +114,6 @@ java_library_static {
"android.hardware.biometrics.face-V1.0-java",
"android.hardware.biometrics.fingerprint-V2.1-java",
"android.hardware.oemlock-V1.0-java",
- "android.hardware.tetheroffload.control-V1.0-java",
"android.hardware.configstore-V1.0-java",
"android.hardware.contexthub-V1.0-java",
"android.hidl.manager-V1.2-java",
@@ -163,11 +162,3 @@ prebuilt_etc {
name: "protolog.conf.json.gz",
src: ":services.core.json.gz",
}
-
-// TODO: this should be removed after tethering migration done.
-filegroup {
- name: "servicescore-tethering-src",
- srcs: [
- "java/com/android/server/connectivity/MockableSystemProperties.java",
- ],
-}
diff --git a/services/core/java/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java
index e67d736796b9..de6cca520e65 100644
--- a/services/core/java/android/content/pm/PackageManagerInternal.java
+++ b/services/core/java/android/content/pm/PackageManagerInternal.java
@@ -61,7 +61,6 @@ public abstract class PackageManagerInternal {
public static final int PACKAGE_INCIDENT_REPORT_APPROVER = 10;
public static final int PACKAGE_APP_PREDICTOR = 11;
public static final int PACKAGE_TELEPHONY = 12;
- public static final int PACKAGE_WIFI = 13;
@IntDef(value = {
PACKAGE_SYSTEM,
PACKAGE_SETUP_WIZARD,
@@ -76,7 +75,6 @@ public abstract class PackageManagerInternal {
PACKAGE_INCIDENT_REPORT_APPROVER,
PACKAGE_APP_PREDICTOR,
PACKAGE_TELEPHONY,
- PACKAGE_WIFI,
})
@Retention(RetentionPolicy.SOURCE)
public @interface KnownPackage {}
@@ -770,9 +768,10 @@ public abstract class PackageManagerInternal {
* @param userId user to uninstall apex package for. Must be
* {@link android.os.UserHandle#USER_ALL}, otherwise failure will be reported.
* @param intentSender a {@link IntentSender} to send result of an uninstall to.
+ * @param flags flags about the uninstall.
*/
public abstract void uninstallApex(String packageName, long versionCode, int userId,
- IntentSender intentSender);
+ IntentSender intentSender, int flags);
/**
* Get fingerprint of build that updated the runtime permissions for a user.
diff --git a/services/core/java/android/os/UserManagerInternal.java b/services/core/java/android/os/UserManagerInternal.java
index 9a7cb3f2eff2..a2e9341bae71 100644
--- a/services/core/java/android/os/UserManagerInternal.java
+++ b/services/core/java/android/os/UserManagerInternal.java
@@ -15,6 +15,7 @@
*/
package android.os;
+import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
@@ -22,13 +23,24 @@ import android.content.Context;
import android.content.pm.UserInfo;
import android.graphics.Bitmap;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
/**
* @hide Only for use within the system server.
*/
public abstract class UserManagerInternal {
- public static final int CAMERA_NOT_DISABLED = 0;
- public static final int CAMERA_DISABLED_LOCALLY = 1;
- public static final int CAMERA_DISABLED_GLOBALLY = 2;
+
+ public static final int OWNER_TYPE_DEVICE_OWNER = 0;
+ public static final int OWNER_TYPE_PROFILE_OWNER = 1;
+ public static final int OWNER_TYPE_PROFILE_OWNER_OF_ORGANIZATION_OWNED_DEVICE = 2;
+ public static final int OWNER_TYPE_NO_OWNER = 3;
+
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(value = {OWNER_TYPE_DEVICE_OWNER, OWNER_TYPE_PROFILE_OWNER,
+ OWNER_TYPE_PROFILE_OWNER_OF_ORGANIZATION_OWNED_DEVICE, OWNER_TYPE_NO_OWNER})
+ public @interface OwnerType {
+ }
public interface UserRestrictionsListener {
/**
@@ -47,13 +59,19 @@ public abstract class UserManagerInternal {
*
* @param userId target user id for the local restrictions.
* @param restrictions a bundle of user restrictions.
- * @param isDeviceOwner whether {@code userId} corresponds to device owner user id.
- * @param cameraRestrictionScope is camera disabled and if so what is the scope of restriction.
- * Should be one of {@link #CAMERA_NOT_DISABLED}, {@link #CAMERA_DISABLED_LOCALLY} or
- * {@link #CAMERA_DISABLED_GLOBALLY}
+ * @param restrictionOwnerType determines which admin {@code userId} corresponds to.
+ * The admin can be either
+ * {@link UserManagerInternal#OWNER_TYPE_DEVICE_OWNER},
+ * {@link UserManagerInternal#OWNER_TYPE_PROFILE_OWNER},
+ * {@link UserManagerInternal#OWNER_TYPE_PROFILE_OWNER_OF_ORGANIZATION_OWNED_DEVICE}
+ * or {@link UserManagerInternal#OWNER_TYPE_NO_OWNER}.
+ * If the admin is a DEVICE_OWNER or a PROFILE_OWNER_ORG_OWNED_DEVICE then
+ * a restriction may be applied globally depending on which restriction it is,
+ * otherwise it will be applied just on the current user.
+ * @see OwnerType
*/
public abstract void setDevicePolicyUserRestrictions(int userId, @Nullable Bundle restrictions,
- boolean isDeviceOwner, int cameraRestrictionScope);
+ @OwnerType int restrictionOwnerType);
/**
* Returns the "base" user restrictions.
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index bb7406a56772..a3a61720ac3d 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -108,6 +108,7 @@ import android.net.PrivateDnsConfigParcel;
import android.net.ProxyInfo;
import android.net.RouteInfo;
import android.net.SocketKeepalive;
+import android.net.TetheringManager;
import android.net.UidRange;
import android.net.Uri;
import android.net.VpnService;
@@ -187,9 +188,7 @@ import com.android.server.connectivity.NetworkNotificationManager;
import com.android.server.connectivity.NetworkNotificationManager.NotificationType;
import com.android.server.connectivity.PermissionMonitor;
import com.android.server.connectivity.ProxyTracker;
-import com.android.server.connectivity.Tethering;
import com.android.server.connectivity.Vpn;
-import com.android.server.connectivity.tethering.TetheringDependencies;
import com.android.server.net.BaseNetdEventCallback;
import com.android.server.net.BaseNetworkObserver;
import com.android.server.net.LockdownVpnTracker;
@@ -233,7 +232,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
private static final String DIAG_ARG = "--diag";
public static final String SHORT_ARG = "--short";
- private static final String TETHERING_ARG = "tethering";
private static final String NETWORK_ARG = "networks";
private static final String REQUEST_ARG = "requests";
@@ -280,7 +278,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
private MockableSystemProperties mSystemProperties;
- private Tethering mTethering;
+ private TetheringManager mTetheringManager;
@VisibleForTesting
protected final PermissionMonitor mPermissionMonitor;
@@ -869,15 +867,10 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
/**
- * @see Tethering
+ * Get a reference to the TetheringManager.
*/
- public Tethering makeTethering(@NonNull Context context,
- @NonNull INetworkManagementService nms,
- @NonNull INetworkStatsService statsService,
- @NonNull INetworkPolicyManager policyManager,
- @NonNull TetheringDependencies tetheringDeps) {
- return new Tethering(context, nms, statsService, policyManager,
- IoThread.get().getLooper(), getSystemProperties(), tetheringDeps);
+ public TetheringManager getTetheringManager() {
+ return TetheringManager.getInstance();
}
/**
@@ -932,6 +925,10 @@ public class ConnectivityService extends IConnectivityManager.Stub
return IIpConnectivityMetrics.Stub.asInterface(
ServiceManager.getService(IpConnectivityLog.SERVICE_NAME));
}
+
+ public IBatteryStats getBatteryStatsService() {
+ return BatteryStatsService.getService();
+ }
}
public ConnectivityService(Context context, INetworkManagementService netManager,
@@ -1075,8 +1072,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
- mTethering = deps.makeTethering(mContext, mNMS, mStatsService, mPolicyManager,
- makeTetheringDependencies());
+ mTetheringManager = mDeps.getTetheringManager();
mPermissionMonitor = new PermissionMonitor(mContext, mNetd);
@@ -1111,7 +1107,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
mHandler);
try {
- mNMS.registerObserver(mTethering);
mNMS.registerObserver(mDataActivityObserver);
} catch (RemoteException e) {
loge("Error registering observer :" + e);
@@ -1145,19 +1140,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
registerPrivateDnsSettingsCallbacks();
}
- private TetheringDependencies makeTetheringDependencies() {
- return new TetheringDependencies() {
- @Override
- public boolean isTetheringSupported() {
- return ConnectivityService.this.isTetheringSupported();
- }
- @Override
- public NetworkRequest getDefaultNetworkRequest() {
- return mDefaultRequest;
- }
- };
- }
-
private static NetworkCapabilities createDefaultNetworkCapabilitiesForUid(int uid) {
final NetworkCapabilities netCap = new NetworkCapabilities();
netCap.addCapability(NET_CAPABILITY_INTERNET);
@@ -1909,7 +1891,9 @@ public class ConnectivityService extends IConnectivityManager.Stub
// TODO: relocate this specific callback in Tethering.
if (restrictBackground) {
log("onRestrictBackgroundChanged(true): disabling tethering");
- mTethering.untetherAll();
+ mTetheringManager.stopTethering(ConnectivityManager.TETHERING_WIFI);
+ mTetheringManager.stopTethering(ConnectivityManager.TETHERING_USB);
+ mTetheringManager.stopTethering(ConnectivityManager.TETHERING_BLUETOOTH);
}
}
};
@@ -2164,7 +2148,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
opts.setMaxManifestReceiverApiLevel(Build.VERSION_CODES.M);
options = opts.toBundle();
}
- final IBatteryStats bs = BatteryStatsService.getService();
+ final IBatteryStats bs = mDeps.getBatteryStatsService();
try {
bs.noteConnectivityChanged(intent.getIntExtra(
ConnectivityManager.EXTRA_NETWORK_TYPE, ConnectivityManager.TYPE_NONE),
@@ -2193,7 +2177,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
mPermissionMonitor.startMonitoring();
mProxyTracker.loadGlobalProxy();
registerNetdEventCallback();
- mTethering.systemReady();
synchronized (this) {
mSystemReady = true;
@@ -2405,9 +2388,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
if (ArrayUtils.contains(args, DIAG_ARG)) {
dumpNetworkDiagnostics(pw);
return;
- } else if (ArrayUtils.contains(args, TETHERING_ARG)) {
- mTethering.dump(fd, pw, args);
- return;
} else if (ArrayUtils.contains(args, NETWORK_ARG)) {
dumpNetworks(pw);
return;
@@ -2469,10 +2449,13 @@ public class ConnectivityService extends IConnectivityManager.Stub
mLegacyTypeTracker.dump(pw);
pw.println();
- mTethering.dump(fd, pw, args);
+ mKeepaliveTracker.dump(pw);
pw.println();
- mKeepaliveTracker.dump(pw);
+ pw.println("TetheringManager logs:");
+ pw.increaseIndent();
+ TetheringManager.getInstance().dump(pw);
+ pw.decreaseIndent();
pw.println();
dumpAvoidBadWifiSettings(pw);
@@ -4004,7 +3987,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
public int tether(String iface, String callerPkg) {
ConnectivityManager.enforceTetherChangePermission(mContext, callerPkg);
if (isTetheringSupported()) {
- return mTethering.tether(iface);
+ return mTetheringManager.tether(iface);
} else {
return ConnectivityManager.TETHER_ERROR_UNSUPPORTED;
}
@@ -4016,7 +3999,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
ConnectivityManager.enforceTetherChangePermission(mContext, callerPkg);
if (isTetheringSupported()) {
- return mTethering.untether(iface);
+ return mTetheringManager.untether(iface);
} else {
return ConnectivityManager.TETHER_ERROR_UNSUPPORTED;
}
@@ -4028,7 +4011,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
enforceTetherAccessPermission();
if (isTetheringSupported()) {
- return mTethering.getLastTetherError(iface);
+ return mTetheringManager.getLastTetherError(iface);
} else {
return ConnectivityManager.TETHER_ERROR_UNSUPPORTED;
}
@@ -4039,7 +4022,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
public String[] getTetherableUsbRegexs() {
enforceTetherAccessPermission();
if (isTetheringSupported()) {
- return mTethering.getTetherableUsbRegexs();
+ return mTetheringManager.getTetherableUsbRegexs();
} else {
return new String[0];
}
@@ -4049,7 +4032,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
public String[] getTetherableWifiRegexs() {
enforceTetherAccessPermission();
if (isTetheringSupported()) {
- return mTethering.getTetherableWifiRegexs();
+ return mTetheringManager.getTetherableWifiRegexs();
} else {
return new String[0];
}
@@ -4059,7 +4042,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
public String[] getTetherableBluetoothRegexs() {
enforceTetherAccessPermission();
if (isTetheringSupported()) {
- return mTethering.getTetherableBluetoothRegexs();
+ return mTetheringManager.getTetherableBluetoothRegexs();
} else {
return new String[0];
}
@@ -4069,7 +4052,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
public int setUsbTethering(boolean enable, String callerPkg) {
ConnectivityManager.enforceTetherChangePermission(mContext, callerPkg);
if (isTetheringSupported()) {
- return mTethering.setUsbTethering(enable);
+ return mTetheringManager.setUsbTethering(enable);
} else {
return ConnectivityManager.TETHER_ERROR_UNSUPPORTED;
}
@@ -4080,25 +4063,25 @@ public class ConnectivityService extends IConnectivityManager.Stub
@Override
public String[] getTetherableIfaces() {
enforceTetherAccessPermission();
- return mTethering.getTetherableIfaces();
+ return mTetheringManager.getTetherableIfaces();
}
@Override
public String[] getTetheredIfaces() {
enforceTetherAccessPermission();
- return mTethering.getTetheredIfaces();
+ return mTetheringManager.getTetheredIfaces();
}
@Override
public String[] getTetheringErroredIfaces() {
enforceTetherAccessPermission();
- return mTethering.getErroredIfaces();
+ return mTetheringManager.getTetheringErroredIfaces();
}
@Override
public String[] getTetheredDhcpRanges() {
enforceConnectivityInternalPermission();
- return mTethering.getTetheredDhcpRanges();
+ return mTetheringManager.getTetheredDhcpRanges();
}
@Override
@@ -4126,7 +4109,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
Binder.restoreCallingIdentity(token);
}
- return tetherEnabledInSettings && adminUser && mTethering.hasTetherableConfiguration();
+ return tetherEnabledInSettings && adminUser
+ && mTetheringManager.hasTetherableConfiguration();
}
@Override
@@ -4137,13 +4121,13 @@ public class ConnectivityService extends IConnectivityManager.Stub
receiver.send(ConnectivityManager.TETHER_ERROR_UNSUPPORTED, null);
return;
}
- mTethering.startTethering(type, receiver, showProvisioningUi);
+ mTetheringManager.startTethering(type, receiver, showProvisioningUi);
}
@Override
public void stopTethering(int type, String callerPkg) {
ConnectivityManager.enforceTetherChangePermission(mContext, callerPkg);
- mTethering.stopTethering(type);
+ mTetheringManager.stopTethering(type);
}
/**
@@ -4157,7 +4141,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
public void getLatestTetheringEntitlementResult(int type, ResultReceiver receiver,
boolean showEntitlementUi, String callerPkg) {
ConnectivityManager.enforceTetherChangePermission(mContext, callerPkg);
- mTethering.getLatestTetheringEntitlementResult(type, receiver, showEntitlementUi);
+ mTetheringManager.requestLatestTetheringEntitlementResult(
+ type, receiver, showEntitlementUi);
}
/** Register tethering event callback. */
@@ -4165,7 +4150,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
public void registerTetheringEventCallback(ITetheringEventCallback callback,
String callerPkg) {
ConnectivityManager.enforceTetherChangePermission(mContext, callerPkg);
- mTethering.registerTetheringEventCallback(callback);
+ mTetheringManager.registerTetheringEventCallback(callback);
}
/** Unregister tethering event callback. */
@@ -4173,7 +4158,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
public void unregisterTetheringEventCallback(ITetheringEventCallback callback,
String callerPkg) {
ConnectivityManager.enforceTetherChangePermission(mContext, callerPkg);
- mTethering.unregisterTetheringEventCallback(callback);
+ mTetheringManager.unregisterTetheringEventCallback(callback);
}
// Called when we lose the default network and have no replacement yet.
@@ -5647,7 +5632,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
// are accurate.
networkAgent.clatd.fixupLinkProperties(oldLp, newLp);
- updateInterfaces(newLp, oldLp, netId, networkAgent.networkCapabilities);
+ updateInterfaces(newLp, oldLp, netId, networkAgent.networkCapabilities,
+ networkAgent.networkInfo.getType());
// update filtering rules, need to happen after the interface update so netd knows about the
// new interface (the interface name -> index map becomes initialized)
@@ -5726,21 +5712,26 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
- private void updateInterfaces(LinkProperties newLp, LinkProperties oldLp, int netId,
- NetworkCapabilities caps) {
- CompareResult<String> interfaceDiff = new CompareResult<>(
+ private void updateInterfaces(final @Nullable LinkProperties newLp,
+ final @Nullable LinkProperties oldLp, final int netId,
+ final @Nullable NetworkCapabilities caps, final int legacyType) {
+ final CompareResult<String> interfaceDiff = new CompareResult<>(
oldLp != null ? oldLp.getAllInterfaceNames() : null,
newLp != null ? newLp.getAllInterfaceNames() : null);
- for (String iface : interfaceDiff.added) {
- try {
- if (DBG) log("Adding iface " + iface + " to network " + netId);
- mNMS.addInterfaceToNetwork(iface, netId);
- wakeupModifyInterface(iface, caps, true);
- } catch (Exception e) {
- loge("Exception adding interface: " + e);
+ if (!interfaceDiff.added.isEmpty()) {
+ final IBatteryStats bs = mDeps.getBatteryStatsService();
+ for (final String iface : interfaceDiff.added) {
+ try {
+ if (DBG) log("Adding iface " + iface + " to network " + netId);
+ mNMS.addInterfaceToNetwork(iface, netId);
+ wakeupModifyInterface(iface, caps, true);
+ bs.noteNetworkInterfaceType(iface, legacyType);
+ } catch (Exception e) {
+ loge("Exception adding interface: " + e);
+ }
}
}
- for (String iface : interfaceDiff.removed) {
+ for (final String iface : interfaceDiff.removed) {
try {
if (DBG) log("Removing iface " + iface + " from network " + netId);
wakeupModifyInterface(iface, caps, false);
@@ -6476,77 +6467,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
// do this after the default net is switched, but
// before LegacyTypeTracker sends legacy broadcasts
for (NetworkRequestInfo nri : addedRequests) notifyNetworkAvailable(newNetwork, nri);
-
- // Linger any networks that are no longer needed. This should be done after sending the
- // available callback for newNetwork.
- for (NetworkAgentInfo nai : removedRequests) {
- updateLingerState(nai, now);
- }
- // Possibly unlinger newNetwork. Unlingering a network does not send any callbacks so it
- // does not need to be done in any particular order.
- updateLingerState(newNetwork, now);
-
- if (isNewDefault) {
- // Maintain the illusion: since the legacy API only
- // understands one network at a time, we must pretend
- // that the current default network disconnected before
- // the new one connected.
- if (oldDefaultNetwork != null) {
- mLegacyTypeTracker.remove(oldDefaultNetwork.networkInfo.getType(),
- oldDefaultNetwork, true);
- }
- mDefaultInetConditionPublished = newNetwork.lastValidated ? 100 : 0;
- mLegacyTypeTracker.add(newNetwork.networkInfo.getType(), newNetwork);
- notifyLockdownVpn(newNetwork);
- }
-
- if (reassignedRequests.containsValue(newNetwork) || newNetwork.isVPN()) {
- // Notify battery stats service about this network, both the normal
- // interface and any stacked links.
- // TODO: Avoid redoing this; this must only be done once when a network comes online.
- try {
- final IBatteryStats bs = BatteryStatsService.getService();
- final int type = newNetwork.networkInfo.getType();
-
- final String baseIface = newNetwork.linkProperties.getInterfaceName();
- bs.noteNetworkInterfaceType(baseIface, type);
- for (LinkProperties stacked : newNetwork.linkProperties.getStackedLinks()) {
- final String stackedIface = stacked.getInterfaceName();
- bs.noteNetworkInterfaceType(stackedIface, type);
- }
- } catch (RemoteException ignored) {
- }
-
- // This has to happen after the notifyNetworkCallbacks as that tickles each
- // ConnectivityManager instance so that legacy requests correctly bind dns
- // requests to this network. The legacy users are listening for this broadcast
- // and will generally do a dns request so they can ensureRouteToHost and if
- // they do that before the callbacks happen they'll use the default network.
- //
- // TODO: Is there still a race here? We send the broadcast
- // after sending the callback, but if the app can receive the
- // broadcast before the callback, it might still break.
- //
- // This *does* introduce a race where if the user uses the new api
- // (notification callbacks) and then uses the old api (getNetworkInfo(type))
- // they may get old info. Reverse this after the old startUsing api is removed.
- // This is on top of the multiple intent sequencing referenced in the todo above.
- for (int i = 0; i < newNetwork.numNetworkRequests(); i++) {
- NetworkRequest nr = newNetwork.requestAt(i);
- if (nr.legacyType != TYPE_NONE && nr.isRequest()) {
- // legacy type tracker filters out repeat adds
- mLegacyTypeTracker.add(nr.legacyType, newNetwork);
- }
- }
-
- // A VPN generally won't get added to the legacy tracker in the "for (nri)" loop above,
- // because usually there are no NetworkRequests it satisfies (e.g., mDefaultRequest
- // wants the NOT_VPN capability, so it will never be satisfied by a VPN). So, add the
- // newNetwork to the tracker explicitly (it's a no-op if it has already been added).
- if (newNetwork.isVPN()) {
- mLegacyTypeTracker.add(TYPE_VPN, newNetwork);
- }
- }
}
/**
@@ -6560,15 +6480,32 @@ public class ConnectivityService extends IConnectivityManager.Stub
// requests. Once the code has switched to a request-major iteration style, this can
// be optimized to only do the processing needed.
final long now = SystemClock.elapsedRealtime();
+ final NetworkAgentInfo oldDefaultNetwork = getDefaultNetwork();
+
final NetworkAgentInfo[] nais = mNetworkAgentInfos.values().toArray(
new NetworkAgentInfo[mNetworkAgentInfos.size()]);
// Rematch higher scoring networks first to prevent requests first matching a lower
// scoring network and then a higher scoring network, which could produce multiple
- // callbacks and inadvertently unlinger networks.
+ // callbacks.
Arrays.sort(nais);
- for (NetworkAgentInfo nai : nais) {
+ for (final NetworkAgentInfo nai : nais) {
rematchNetworkAndRequests(nai, now);
}
+
+ final NetworkAgentInfo newDefaultNetwork = getDefaultNetwork();
+
+ for (final NetworkAgentInfo nai : nais) {
+ // Rematching may have altered the linger state of some networks, so update all linger
+ // timers. updateLingerState reads the state from the network agent and does nothing
+ // if the state has not changed : the source of truth is controlled with
+ // NetworkAgentInfo#lingerRequest and NetworkAgentInfo#unlingerRequest, which have been
+ // called while rematching the individual networks above.
+ updateLingerState(nai, now);
+ }
+
+ updateLegacyTypeTrackerAndVpnLockdownForRematch(oldDefaultNetwork, newDefaultNetwork, nais);
+
+ // Tear down all unneeded networks.
for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) {
if (unneeded(nai, UnneededFor.TEARDOWN)) {
if (nai.getLingerExpiry() > 0) {
@@ -6588,6 +6525,70 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
}
+ private void updateLegacyTypeTrackerAndVpnLockdownForRematch(
+ @Nullable final NetworkAgentInfo oldDefaultNetwork,
+ @Nullable final NetworkAgentInfo newDefaultNetwork,
+ @NonNull final NetworkAgentInfo[] nais) {
+ if (oldDefaultNetwork != newDefaultNetwork) {
+ // Maintain the illusion : since the legacy API only understands one network at a time,
+ // if the default network changed, apps should see a disconnected broadcast for the
+ // old default network before they see a connected broadcast for the new one.
+ if (oldDefaultNetwork != null) {
+ mLegacyTypeTracker.remove(oldDefaultNetwork.networkInfo.getType(),
+ oldDefaultNetwork, true);
+ }
+ if (newDefaultNetwork != null) {
+ // The new default network can be newly null if and only if the old default
+ // network doesn't satisfy the default request any more because it lost a
+ // capability.
+ mDefaultInetConditionPublished = newDefaultNetwork.lastValidated ? 100 : 0;
+ mLegacyTypeTracker.add(newDefaultNetwork.networkInfo.getType(), newDefaultNetwork);
+ // If the legacy VPN is connected, notifyLockdownVpn may end up sending a broadcast
+ // to reflect the NetworkInfo of this new network. This broadcast has to be sent
+ // after the disconnect broadcasts above, but before the broadcasts sent by the
+ // legacy type tracker below.
+ // TODO : refactor this, it's too complex
+ notifyLockdownVpn(newDefaultNetwork);
+ }
+ }
+
+ // Now that all the callbacks have been sent, send the legacy network broadcasts
+ // as needed. This is necessary so that legacy requests correctly bind dns
+ // requests to this network. The legacy users are listening for this broadcast
+ // and will generally do a dns request so they can ensureRouteToHost and if
+ // they do that before the callbacks happen they'll use the default network.
+ //
+ // TODO: Is there still a race here? The legacy broadcast will be sent after sending
+ // callbacks, but if apps can receive the broadcast before the callback, they still might
+ // have an inconsistent view of networking.
+ //
+ // This *does* introduce a race where if the user uses the new api
+ // (notification callbacks) and then uses the old api (getNetworkInfo(type))
+ // they may get old info. Reverse this after the old startUsing api is removed.
+ // This is on top of the multiple intent sequencing referenced in the todo above.
+ for (NetworkAgentInfo nai : nais) {
+ addNetworkToLegacyTypeTracker(nai);
+ }
+ }
+
+ private void addNetworkToLegacyTypeTracker(@NonNull final NetworkAgentInfo nai) {
+ for (int i = 0; i < nai.numNetworkRequests(); i++) {
+ NetworkRequest nr = nai.requestAt(i);
+ if (nr.legacyType != TYPE_NONE && nr.isRequest()) {
+ // legacy type tracker filters out repeat adds
+ mLegacyTypeTracker.add(nr.legacyType, nai);
+ }
+ }
+
+ // A VPN generally won't get added to the legacy tracker in the "for (nri)" loop above,
+ // because usually there are no NetworkRequests it satisfies (e.g., mDefaultRequest
+ // wants the NOT_VPN capability, so it will never be satisfied by a VPN). So, add the
+ // newNetwork to the tracker explicitly (it's a no-op if it has already been added).
+ if (nai.isVPN()) {
+ mLegacyTypeTracker.add(TYPE_VPN, nai);
+ }
+ }
+
private void updateInetCondition(NetworkAgentInfo nai) {
// Don't bother updating until we've graduated to validated at least once.
if (!nai.everValidated) return;
diff --git a/services/core/java/com/android/server/EventLogTags.logtags b/services/core/java/com/android/server/EventLogTags.logtags
index bec08f45188f..b595eb15ee15 100644
--- a/services/core/java/com/android/server/EventLogTags.logtags
+++ b/services/core/java/com/android/server/EventLogTags.logtags
@@ -175,27 +175,6 @@ option java_package com.android.server
3121 pm_package_stats (manual_time|2|3),(quota_time|2|3),(manual_data|2|2),(quota_data|2|2),(manual_cache|2|2),(quota_cache|2|2)
# ---------------------------
-# WindowManagerService.java
-# ---------------------------
-# Out of memory for surfaces.
-31000 wm_no_surface_memory (Window|3),(PID|1|5),(Operation|3)
-# Task created.
-31001 wm_task_created (TaskId|1|5),(StackId|1|5)
-# Task moved to top (1) or bottom (0).
-31002 wm_task_moved (TaskId|1|5),(ToTop|1),(Index|1)
-# Task removed with source explanation.
-31003 wm_task_removed (TaskId|1|5),(Reason|3)
-# Stack created.
-31004 wm_stack_created (StackId|1|5)
-# Home stack moved to top (1) or bottom (0).
-31005 wm_home_stack_moved (ToTop|1)
-# Stack removed.
-31006 wm_stack_removed (StackId|1|5)
-# bootanim finished:
-31007 wm_boot_animation_done (time|2|3)
-
-
-# ---------------------------
# InputMethodManagerService.java
# ---------------------------
# Re-connecting to input method service because we haven't received its interface
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index 9ebe896e668b..5f562cf86d0f 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -146,8 +146,13 @@ public class LocationManagerService extends ILocationManager.Stub {
@Override
public void onBootPhase(int phase) {
- if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
- mService.systemRunning();
+ if (phase == PHASE_SYSTEM_SERVICES_READY) {
+ // the location service must be functioning after this boot phase
+ mService.onSystemReady();
+ } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
+ // some providers rely on third party code, so we wait to initialize
+ // providers until third party code is allowed to run
+ mService.onSystemThirdPartyAppsCanStart();
}
}
}
@@ -264,156 +269,159 @@ public class LocationManagerService extends ILocationManager.Stub {
userId -> mContext.getResources().getStringArray(
com.android.internal.R.array.config_locationExtraPackageNames));
- // most startup is deferred until systemRunning()
+ // most startup is deferred until systemReady()
}
- private void systemRunning() {
+ private void onSystemReady() {
synchronized (mLock) {
- initializeLocked();
- }
- }
-
- @GuardedBy("mLock")
- private void initializeLocked() {
- mPackageManager = mContext.getPackageManager();
- mAppOps = mContext.getSystemService(AppOpsManager.class);
- mPowerManager = mContext.getSystemService(PowerManager.class);
- mActivityManager = mContext.getSystemService(ActivityManager.class);
- mUserManager = mContext.getSystemService(UserManager.class);
-
- mSettingsStore = new LocationSettingsStore(mContext, mHandler);
-
- mLocationFudger = new LocationFudger(mContext, mHandler);
- mGeofenceManager = new GeofenceManager(mContext, mSettingsStore);
-
- PowerManagerInternal localPowerManager =
- LocalServices.getService(PowerManagerInternal.class);
-
- // prepare providers
- initializeProvidersLocked();
-
- // add listeners
- mAppOps.startWatchingMode(
- AppOpsManager.OP_COARSE_LOCATION,
- null,
- AppOpsManager.WATCH_FOREGROUND_CHANGES,
- new AppOpsManager.OnOpChangedInternalListener() {
- public void onOpChanged(int op, String packageName) {
- // onOpChanged invoked on ui thread, move to our thread to reduce risk of
- // blocking ui thread
+ mPackageManager = mContext.getPackageManager();
+ mAppOps = mContext.getSystemService(AppOpsManager.class);
+ mPowerManager = mContext.getSystemService(PowerManager.class);
+ mActivityManager = mContext.getSystemService(ActivityManager.class);
+ mUserManager = mContext.getSystemService(UserManager.class);
+
+ mSettingsStore = new LocationSettingsStore(mContext, mHandler);
+ mLocationFudger = new LocationFudger(mContext, mHandler);
+ mGeofenceManager = new GeofenceManager(mContext, mSettingsStore);
+
+ PowerManagerInternal localPowerManager =
+ LocalServices.getService(PowerManagerInternal.class);
+
+ // add listeners
+ mAppOps.startWatchingMode(
+ AppOpsManager.OP_COARSE_LOCATION,
+ null,
+ AppOpsManager.WATCH_FOREGROUND_CHANGES,
+ new AppOpsManager.OnOpChangedInternalListener() {
+ public void onOpChanged(int op, String packageName) {
+ // onOpChanged invoked on ui thread, move to our thread to reduce
+ // risk of
+ // blocking ui thread
+ mHandler.post(() -> {
+ synchronized (mLock) {
+ onAppOpChangedLocked();
+ }
+ });
+ }
+ });
+ mPackageManager.addOnPermissionsChangeListener(
+ uid -> {
+ // listener invoked on ui thread, move to our thread to reduce risk of
+ // blocking
+ // ui thread
mHandler.post(() -> {
synchronized (mLock) {
- onAppOpChangedLocked();
+ onPermissionsChangedLocked();
}
});
- }
- });
- mPackageManager.addOnPermissionsChangeListener(
- uid -> {
- // listener invoked on ui thread, move to our thread to reduce risk of blocking
- // ui thread
- mHandler.post(() -> {
- synchronized (mLock) {
- onPermissionsChangedLocked();
- }
- });
- });
- mActivityManager.addOnUidImportanceListener(
- (uid, importance) -> {
- // listener invoked on ui thread, move to our thread to reduce risk of blocking
- // ui thread
- mHandler.post(() -> {
- synchronized (mLock) {
- onUidImportanceChangedLocked(uid, importance);
- }
});
- },
- FOREGROUND_IMPORTANCE_CUTOFF);
-
- localPowerManager.registerLowPowerModeObserver(ServiceType.LOCATION,
- state -> {
- // listener invoked on ui thread, move to our thread to reduce risk of blocking
- // ui thread
- mHandler.post(() -> {
- synchronized (mLock) {
- onBatterySaverModeChangedLocked(state.locationMode);
- }
+ mActivityManager.addOnUidImportanceListener(
+ (uid, importance) -> {
+ // listener invoked on ui thread, move to our thread to reduce risk of
+ // blocking
+ // ui thread
+ mHandler.post(() -> {
+ synchronized (mLock) {
+ onUidImportanceChangedLocked(uid, importance);
+ }
+ });
+ },
+ FOREGROUND_IMPORTANCE_CUTOFF);
+
+ localPowerManager.registerLowPowerModeObserver(ServiceType.LOCATION,
+ state -> {
+ // listener invoked on ui thread, move to our thread to reduce risk of
+ // blocking
+ // ui thread
+ mHandler.post(() -> {
+ synchronized (mLock) {
+ onBatterySaverModeChangedLocked(state.locationMode);
+ }
+ });
});
- });
- mBatterySaverMode = mPowerManager.getLocationPowerSaveMode();
-
- mSettingsStore.addOnLocationEnabledChangedListener(() -> {
- synchronized (mLock) {
- onLocationModeChangedLocked(true);
- }
- });
- mSettingsStore.addOnLocationProvidersAllowedChangedListener(() -> {
- synchronized (mLock) {
- onProviderAllowedChangedLocked();
- }
- });
- mSettingsStore.addOnBackgroundThrottleIntervalChangedListener(() -> {
- synchronized (mLock) {
- onBackgroundThrottleIntervalChangedLocked();
- }
- });
- mSettingsStore.addOnBackgroundThrottlePackageWhitelistChangedListener(() -> {
- synchronized (mLock) {
- onBackgroundThrottleWhitelistChangedLocked();
- }
- });
- mSettingsStore.addOnIgnoreSettingsPackageWhitelistChangedListener(() -> {
- synchronized (mLock) {
- onIgnoreSettingsWhitelistChangedLocked();
- }
- });
+ mBatterySaverMode = mPowerManager.getLocationPowerSaveMode();
- new PackageMonitor() {
- @Override
- public void onPackageDisappeared(String packageName, int reason) {
+ mSettingsStore.addOnLocationEnabledChangedListener(() -> {
synchronized (mLock) {
- LocationManagerService.this.onPackageDisappearedLocked(packageName);
+ onLocationModeChangedLocked(true);
}
- }
- }.register(mContext, mHandler.getLooper(), true);
-
- IntentFilter intentFilter = new IntentFilter();
- intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
- intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_ADDED);
- intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_REMOVED);
- intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
- intentFilter.addAction(Intent.ACTION_SCREEN_ON);
-
- mContext.registerReceiverAsUser(new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- final String action = intent.getAction();
- if (action == null) {
- return;
+ });
+ mSettingsStore.addOnLocationProvidersAllowedChangedListener(() -> {
+ synchronized (mLock) {
+ onProviderAllowedChangedLocked();
+ }
+ });
+ mSettingsStore.addOnBackgroundThrottleIntervalChangedListener(() -> {
+ synchronized (mLock) {
+ onBackgroundThrottleIntervalChangedLocked();
+ }
+ });
+ mSettingsStore.addOnBackgroundThrottlePackageWhitelistChangedListener(() -> {
+ synchronized (mLock) {
+ onBackgroundThrottleWhitelistChangedLocked();
}
+ });
+ mSettingsStore.addOnIgnoreSettingsPackageWhitelistChangedListener(() -> {
synchronized (mLock) {
- switch (action) {
- case Intent.ACTION_USER_SWITCHED:
- onUserChangedLocked(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
- break;
- case Intent.ACTION_MANAGED_PROFILE_ADDED:
- case Intent.ACTION_MANAGED_PROFILE_REMOVED:
- onUserProfilesChangedLocked();
- break;
- case Intent.ACTION_SCREEN_ON:
- case Intent.ACTION_SCREEN_OFF:
- onScreenStateChangedLocked();
- break;
+ onIgnoreSettingsWhitelistChangedLocked();
+ }
+ });
+
+ new PackageMonitor() {
+ @Override
+ public void onPackageDisappeared(String packageName, int reason) {
+ synchronized (mLock) {
+ LocationManagerService.this.onPackageDisappearedLocked(packageName);
}
}
- }
- }, UserHandle.ALL, intentFilter, null, mHandler);
+ }.register(mContext, mHandler.getLooper(), true);
+
+ IntentFilter intentFilter = new IntentFilter();
+ intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
+ intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_ADDED);
+ intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_REMOVED);
+ intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
+ intentFilter.addAction(Intent.ACTION_SCREEN_ON);
+
+ mContext.registerReceiverAsUser(new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ final String action = intent.getAction();
+ if (action == null) {
+ return;
+ }
+ synchronized (mLock) {
+ switch (action) {
+ case Intent.ACTION_USER_SWITCHED:
+ onUserChangedLocked(
+ intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
+ break;
+ case Intent.ACTION_MANAGED_PROFILE_ADDED:
+ case Intent.ACTION_MANAGED_PROFILE_REMOVED:
+ onUserProfilesChangedLocked();
+ break;
+ case Intent.ACTION_SCREEN_ON:
+ case Intent.ACTION_SCREEN_OFF:
+ onScreenStateChangedLocked();
+ break;
+ }
+ }
+ }
+ }, UserHandle.ALL, intentFilter, null, mHandler);
- // switching the user from null to system here performs the bulk of the initialization work.
- // the user being changed will cause a reload of all user specific settings, which causes
- // provider initialization, and propagates changes until a steady state is reached
- mCurrentUserId = UserHandle.USER_NULL;
- onUserChangedLocked(ActivityManager.getCurrentUser());
+ // switching the user from null to system here performs the bulk of the initialization
+ // work. the user being changed will cause a reload of all user specific settings, which
+ // causes initialization, and propagates changes until a steady state is reached
+ mCurrentUserId = UserHandle.USER_NULL;
+ onUserChangedLocked(ActivityManager.getCurrentUser());
+ }
+ }
+
+ private void onSystemThirdPartyAppsCanStart() {
+ synchronized (mLock) {
+ // prepare providers
+ initializeProvidersLocked();
+ }
}
@GuardedBy("mLock")
diff --git a/services/core/java/com/android/server/PackageWatchdog.java b/services/core/java/com/android/server/PackageWatchdog.java
index bc509561163a..e2fe76e94db3 100644
--- a/services/core/java/com/android/server/PackageWatchdog.java
+++ b/services/core/java/com/android/server/PackageWatchdog.java
@@ -247,7 +247,14 @@ public class PackageWatchdog {
List<MonitoredPackage> packages = new ArrayList<>();
for (int i = 0; i < packageNames.size(); i++) {
// Health checks not available yet so health check state will start INACTIVE
- packages.add(new MonitoredPackage(packageNames.get(i), durationMs, false));
+ MonitoredPackage pkg = newMonitoredPackage(packageNames.get(i), durationMs, false);
+ if (pkg != null) {
+ packages.add(pkg);
+ }
+ }
+
+ if (packages.isEmpty()) {
+ return;
}
// Sync before we add the new packages to the observers. This will #pruneObservers,
@@ -634,16 +641,8 @@ public class PackageWatchdog {
if (registeredObserver != null) {
Iterator<MonitoredPackage> it = failedPackages.iterator();
while (it.hasNext()) {
- String failedPackage = it.next().getName();
- Slog.i(TAG, "Explicit health check failed for package " + failedPackage);
- VersionedPackage versionedPkg = getVersionedPackage(failedPackage);
- if (versionedPkg == null) {
- Slog.w(TAG, "Explicit health check failed but could not find package "
- + failedPackage);
- // TODO(b/120598832): Skip. We only continue to pass tests for now since
- // the tests don't install any packages
- versionedPkg = new VersionedPackage(failedPackage, 0L);
- }
+ VersionedPackage versionedPkg = it.next().mPackage;
+ Slog.i(TAG, "Explicit health check failed for package " + versionedPkg);
registeredObserver.execute(versionedPkg);
}
}
@@ -654,7 +653,7 @@ public class PackageWatchdog {
@Nullable
private VersionedPackage getVersionedPackage(String packageName) {
final PackageManager pm = mContext.getPackageManager();
- if (pm == null) {
+ if (pm == null || TextUtils.isEmpty(packageName)) {
return null;
}
try {
@@ -848,7 +847,7 @@ public class PackageWatchdog {
public void updatePackagesLocked(List<MonitoredPackage> packages) {
for (int pIndex = 0; pIndex < packages.size(); pIndex++) {
MonitoredPackage p = packages.get(pIndex);
- this.packages.put(p.mName, p);
+ this.packages.put(p.getName(), p);
}
}
@@ -872,7 +871,7 @@ public class PackageWatchdog {
int newState = p.handleElapsedTimeLocked(elapsedMs);
if (oldState != HealthCheckState.FAILED
&& newState == HealthCheckState.FAILED) {
- Slog.i(TAG, "Package " + p.mName + " failed health check");
+ Slog.i(TAG, "Package " + p.getName() + " failed health check");
failedPackages.add(p);
}
if (p.isExpiredLocked()) {
@@ -925,9 +924,10 @@ public class PackageWatchdog {
ATTR_EXPLICIT_HEALTH_CHECK_DURATION));
boolean hasPassedHealthCheck = Boolean.parseBoolean(
parser.getAttributeValue(null, ATTR_PASSED_HEALTH_CHECK));
- if (!TextUtils.isEmpty(packageName)) {
- packages.add(watchdog.new MonitoredPackage(packageName, duration,
- healthCheckDuration, hasPassedHealthCheck));
+ MonitoredPackage pkg = watchdog.newMonitoredPackage(packageName,
+ duration, healthCheckDuration, hasPassedHealthCheck);
+ if (pkg != null) {
+ packages.add(pkg);
}
} catch (NumberFormatException e) {
Slog.wtf(TAG, "Skipping package for observer " + observerName, e);
@@ -963,6 +963,20 @@ public class PackageWatchdog {
int FAILED = 3;
}
+ MonitoredPackage newMonitoredPackage(
+ String name, long durationMs, boolean hasPassedHealthCheck) {
+ return newMonitoredPackage(name, durationMs, Long.MAX_VALUE, hasPassedHealthCheck);
+ }
+
+ MonitoredPackage newMonitoredPackage(String name, long durationMs, long healthCheckDurationMs,
+ boolean hasPassedHealthCheck) {
+ VersionedPackage pkg = getVersionedPackage(name);
+ if (pkg == null) {
+ return null;
+ }
+ return new MonitoredPackage(pkg, durationMs, healthCheckDurationMs, hasPassedHealthCheck);
+ }
+
/**
* Represents a package and its health check state along with the time
* it should be monitored for.
@@ -971,8 +985,7 @@ public class PackageWatchdog {
* instances of this class.
*/
class MonitoredPackage {
- //TODO(b/120598832): VersionedPackage?
- private final String mName;
+ private final VersionedPackage mPackage;
// Times when package failures happen sorted in ascending order
@GuardedBy("mLock")
private final LongArrayQueue mFailureHistory = new LongArrayQueue();
@@ -996,13 +1009,9 @@ public class PackageWatchdog {
@GuardedBy("mLock")
private long mHealthCheckDurationMs = Long.MAX_VALUE;
- MonitoredPackage(String name, long durationMs, boolean hasPassedHealthCheck) {
- this(name, durationMs, Long.MAX_VALUE, hasPassedHealthCheck);
- }
-
- MonitoredPackage(String name, long durationMs, long healthCheckDurationMs,
- boolean hasPassedHealthCheck) {
- mName = name;
+ private MonitoredPackage(VersionedPackage pkg, long durationMs,
+ long healthCheckDurationMs, boolean hasPassedHealthCheck) {
+ mPackage = pkg;
mDurationMs = durationMs;
mHealthCheckDurationMs = healthCheckDurationMs;
mHasPassedHealthCheck = hasPassedHealthCheck;
@@ -1013,7 +1022,7 @@ public class PackageWatchdog {
@GuardedBy("mLock")
public void writeLocked(XmlSerializer out) throws IOException {
out.startTag(null, TAG_PACKAGE);
- out.attribute(null, ATTR_NAME, mName);
+ out.attribute(null, ATTR_NAME, getName());
out.attribute(null, ATTR_DURATION, String.valueOf(mDurationMs));
out.attribute(null, ATTR_EXPLICIT_HEALTH_CHECK_DURATION,
String.valueOf(mHealthCheckDurationMs));
@@ -1053,7 +1062,7 @@ public class PackageWatchdog {
public int setHealthCheckActiveLocked(long initialHealthCheckDurationMs) {
if (initialHealthCheckDurationMs <= 0) {
Slog.wtf(TAG, "Cannot set non-positive health check duration "
- + initialHealthCheckDurationMs + "ms for package " + mName
+ + initialHealthCheckDurationMs + "ms for package " + getName()
+ ". Using total duration " + mDurationMs + "ms instead");
initialHealthCheckDurationMs = mDurationMs;
}
@@ -1072,7 +1081,7 @@ public class PackageWatchdog {
@GuardedBy("mLock")
public int handleElapsedTimeLocked(long elapsedMs) {
if (elapsedMs <= 0) {
- Slog.w(TAG, "Cannot handle non-positive elapsed time for package " + mName);
+ Slog.w(TAG, "Cannot handle non-positive elapsed time for package " + getName());
return mHealthCheckState;
}
// Transitions to FAILED if now <= 0 and health check not passed
@@ -1105,7 +1114,7 @@ public class PackageWatchdog {
/** Returns the monitored package name. */
private String getName() {
- return mName;
+ return mPackage.getPackageName();
}
/**
@@ -1170,7 +1179,7 @@ public class PackageWatchdog {
} else {
mHealthCheckState = HealthCheckState.ACTIVE;
}
- Slog.i(TAG, "Updated health check state for package " + mName + ": "
+ Slog.i(TAG, "Updated health check state for package " + getName() + ": "
+ toString(oldState) + " -> " + toString(mHealthCheckState));
return mHealthCheckState;
}
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index a4bc3bd9101c..9d1eb6cb5326 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -118,6 +118,7 @@ import android.text.format.DateUtils;
import android.util.ArrayMap;
import android.util.AtomicFile;
import android.util.DataUnit;
+import android.util.FeatureFlagUtils;
import android.util.Log;
import android.util.Pair;
import android.util.Slog;
@@ -819,7 +820,6 @@ class StorageManagerService extends IStorageManager.Stub
refreshFuseSettings();
});
refreshIsolatedStorageSettings();
- refreshFuseSettings();
}
/**
@@ -883,16 +883,25 @@ class StorageManagerService extends IStorageManager.Stub
SystemProperties.set(StorageManager.PROP_ISOLATED_STORAGE, Boolean.toString(res));
}
+ /**
+ * The most recent flag change takes precedence. Change fuse Settings flag if Device Config is
+ * changed. Settings flag change will in turn change fuse system property (persist.sys.fuse)
+ * whenever the user reboots.
+ */
private void refreshFuseSettings() {
int isFuseEnabled = DeviceConfig.getInt(DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT,
FUSE_ENABLED, 0);
if (isFuseEnabled == 1) {
- SystemProperties.set(StorageManager.PROP_FUSE, "true");
+ Slog.d(TAG, "Device Config flag for FUSE is enabled, turn Settings fuse flag on");
+ SystemProperties.set(FeatureFlagUtils.PERSIST_PREFIX
+ + FeatureFlagUtils.SETTINGS_FUSE_FLAG, "true");
} else if (isFuseEnabled == -1) {
- SystemProperties.set(StorageManager.PROP_FUSE, "false");
+ Slog.d(TAG, "Device Config flag for FUSE is disabled, turn Settings fuse flag off");
+ SystemProperties.set(FeatureFlagUtils.PERSIST_PREFIX
+ + FeatureFlagUtils.SETTINGS_FUSE_FLAG, "false");
}
// else, keep the build config.
- // This can be overridden be direct adjustment of persist.sys.prop
+ // This can be overridden by direct adjustment of persist.sys.fflag.override.settings_fuse
}
/**
@@ -1548,6 +1557,8 @@ class StorageManagerService extends IStorageManager.Stub
public StorageManagerService(Context context) {
sSelf = this;
+ updateFusePropFromSettings();
+
// Snapshot feature flag used for this boot
SystemProperties.set(StorageManager.PROP_ISOLATED_STORAGE_SNAPSHOT, Boolean.toString(
SystemProperties.getBoolean(StorageManager.PROP_ISOLATED_STORAGE, true)));
@@ -1609,6 +1620,23 @@ class StorageManagerService extends IStorageManager.Stub
}
}
+ /**
+ * Checks if user changed the persistent settings_fuse flag from Settings UI
+ * and updates PROP_FUSE (reboots if changed).
+ */
+ private void updateFusePropFromSettings() {
+ Boolean settingsFuseFlag = SystemProperties.getBoolean((FeatureFlagUtils.PERSIST_PREFIX
+ + FeatureFlagUtils.SETTINGS_FUSE_FLAG), false);
+ Slog.d(TAG, "The value of Settings Fuse Flag is " + settingsFuseFlag);
+ if (SystemProperties.getBoolean(StorageManager.PROP_FUSE, false) != settingsFuseFlag) {
+ Slog.d(TAG, "Set persist.sys.fuse to " + settingsFuseFlag);
+ SystemProperties.set(StorageManager.PROP_FUSE, Boolean.toString(settingsFuseFlag));
+ // Perform hard reboot to kick policy into place
+ mContext.getSystemService(PowerManager.class).reboot("Reboot device for FUSE system"
+ + "property change to take effect");
+ }
+ }
+
private void start() {
connectStoraged();
connectVold();
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 770db58773eb..e119d1e995b4 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -2786,8 +2786,8 @@ public class ActivityManagerService extends IActivityManager.Stub
int total = user + system + iowait + irq + softIrq + idle;
if (total == 0) total = 1;
- EventLog.writeEvent(EventLogTags.CPU,
- ((user+system+iowait+irq+softIrq) * 100) / total,
+ EventLogTags.writeCpu(
+ ((user + system + iowait + irq + softIrq) * 100) / total,
(user * 100) / total,
(system * 100) / total,
(iowait * 100) / total,
@@ -3656,7 +3656,7 @@ public class ActivityManagerService extends IActivityManager.Stub
final ArrayList<ProcessMemInfo> memInfos
= doReport ? new ArrayList<ProcessMemInfo>(mProcessList.getLruSizeLocked())
: null;
- EventLog.writeEvent(EventLogTags.AM_LOW_MEMORY, mProcessList.getLruSizeLocked());
+ EventLogTags.writeAmLowMemory(mProcessList.getLruSizeLocked());
long now = SystemClock.uptimeMillis();
for (int i = mProcessList.mLruProcesses.size() - 1; i >= 0; i--) {
ProcessRecord rec = mProcessList.mLruProcesses.get(i);
@@ -3737,8 +3737,8 @@ public class ActivityManagerService extends IActivityManager.Stub
mAllowLowerMemLevel = false;
doLowMem = false;
}
- EventLog.writeEvent(EventLogTags.AM_PROC_DIED, app.userId, app.pid, app.processName,
- app.setAdj, app.setProcState);
+ EventLogTags.writeAmProcDied(app.userId, app.pid, app.processName, app.setAdj,
+ app.setProcState);
if (DEBUG_CLEANUP) Slog.v(TAG_CLEANUP,
"Dying app: " + app + ", pid: " + pid + ", thread: " + thread.asBinder());
handleAppDiedLocked(app, false, true);
@@ -3761,7 +3761,8 @@ public class ActivityManagerService extends IActivityManager.Stub
// Execute the callback if there is any.
doAppDiedCallbackLocked(app);
- EventLog.writeEvent(EventLogTags.AM_PROC_DIED, app.userId, app.pid, app.processName);
+ EventLogTags.writeAmProcDied(app.userId, app.pid, app.processName, app.setAdj,
+ app.setProcState);
} else if (DEBUG_PROCESSES) {
Slog.d(TAG_PROCESSES, "Received spurious death notification for thread "
+ thread.asBinder());
@@ -3783,7 +3784,7 @@ public class ActivityManagerService extends IActivityManager.Stub
}
@GuardedBy("this")
- private void waitForProcKillLocked(final ProcessRecord app, final String formatString,
+ void waitForProcKillLocked(final ProcessRecord app, final String formatString,
final long startTime) {
app.mAppDiedCallback = () -> {
synchronized (ActivityManagerService.this) {
@@ -4755,8 +4756,7 @@ public class ActivityManagerService extends IActivityManager.Stub
if (gone) {
Slog.w(TAG, "Process " + app + " failed to attach");
- EventLog.writeEvent(EventLogTags.AM_PROCESS_START_TIMEOUT, app.userId,
- pid, app.uid, app.processName);
+ EventLogTags.writeAmProcessStartTimeout(app.userId, pid, app.uid, app.processName);
mProcessList.removeProcessNameLocked(app.processName, app.uid);
mAtmInternal.clearHeavyWeightProcessIfEquals(app.getWindowProcessController());
mBatteryStatsService.noteProcessFinish(app.processName, app.info.uid);
@@ -4847,7 +4847,7 @@ public class ActivityManagerService extends IActivityManager.Stub
if (app == null) {
Slog.w(TAG, "No pending application record for pid " + pid
+ " (IApplicationThread " + thread + "); dropping process");
- EventLog.writeEvent(EventLogTags.AM_DROP_PROCESS, pid);
+ EventLogTags.writeAmDropProcess(pid);
if (pid > 0 && pid != MY_PID) {
killProcessQuiet(pid);
//TODO: killProcessGroup(app.info.uid, pid);
@@ -4885,7 +4885,7 @@ public class ActivityManagerService extends IActivityManager.Stub
return false;
}
- EventLog.writeEvent(EventLogTags.AM_PROC_BOUND, app.userId, app.pid, app.processName);
+ EventLogTags.writeAmProcBound(app.userId, app.pid, app.processName);
app.curAdj = app.setAdj = app.verifiedAdj = ProcessList.INVALID_ADJ;
mOomAdjuster.setAttachingSchedGroupLocked(app);
@@ -7163,7 +7163,7 @@ public class ActivityManagerService extends IActivityManager.Stub
+ cpi.applicationInfo.packageName + "/"
+ cpi.applicationInfo.uid + " for provider "
+ name + ": launching app became null");
- EventLog.writeEvent(EventLogTags.AM_PROVIDER_LOST_PROCESS,
+ EventLogTags.writeAmProviderLostProcess(
UserHandle.getUserId(cpi.applicationInfo.uid),
cpi.applicationInfo.packageName,
cpi.applicationInfo.uid, name);
@@ -9156,7 +9156,8 @@ public class ActivityManagerService extends IActivityManager.Stub
t.traceEnd(); // KillProcesses
Slog.i(TAG, "System now ready");
- EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_AMS_READY, SystemClock.uptimeMillis());
+
+ EventLogTags.writeBootProgressAmsReady(SystemClock.uptimeMillis());
t.traceBegin("updateTopComponentForFactoryTest");
mAtmInternal.updateTopComponentForFactoryTest();
@@ -9410,7 +9411,8 @@ public class ActivityManagerService extends IActivityManager.Stub
*/
void handleApplicationCrashInner(String eventType, ProcessRecord r, String processName,
ApplicationErrorReport.CrashInfo crashInfo) {
- EventLog.writeEvent(EventLogTags.AM_CRASH, Binder.getCallingPid(),
+
+ EventLogTags.writeAmCrash(Binder.getCallingPid(),
UserHandle.getUserId(Binder.getCallingUid()), processName,
r == null ? -1 : r.info.flags,
crashInfo.exceptionClassName,
@@ -9613,7 +9615,7 @@ public class ActivityManagerService extends IActivityManager.Stub
final String processName = app == null ? "system_server"
: (r == null ? "unknown" : r.processName);
- EventLog.writeEvent(EventLogTags.AM_WTF, UserHandle.getUserId(callingUid), callingPid,
+ EventLogTags.writeAmWtf(UserHandle.getUserId(callingUid), callingPid,
processName, r == null ? -1 : r.info.flags, tag, crashInfo.exceptionMessage);
StatsLog.write(StatsLog.WTF_OCCURRED, callingUid, tag, processName,
diff --git a/services/core/java/com/android/server/am/AppCompactor.java b/services/core/java/com/android/server/am/AppCompactor.java
index b0f8f86ada6b..b7e206516640 100644
--- a/services/core/java/com/android/server/am/AppCompactor.java
+++ b/services/core/java/com/android/server/am/AppCompactor.java
@@ -189,10 +189,10 @@ public final class AppCompactor {
@GuardedBy("mPhenotypeFlagLock")
@VisibleForTesting volatile long mFullAnonRssThrottleKb =
DEFAULT_COMPACT_FULL_RSS_THROTTLE_KB;
- @GuardedBy("mPhenoypeFlagLock")
+ @GuardedBy("mPhenotypeFlagLock")
@VisibleForTesting volatile long mFullDeltaRssThrottleKb =
DEFAULT_COMPACT_FULL_DELTA_RSS_THROTTLE_KB;
- @GuardedBy("mPhenoypeFlagLock")
+ @GuardedBy("mPhenotypeFlagLock")
@VisibleForTesting final Set<Integer> mProcStateThrottle;
// Handler on which compaction runs.
diff --git a/services/core/java/com/android/server/am/EventLogTags.logtags b/services/core/java/com/android/server/am/EventLogTags.logtags
index cf0de061185f..23674bbd89c7 100644
--- a/services/core/java/com/android/server/am/EventLogTags.logtags
+++ b/services/core/java/com/android/server/am/EventLogTags.logtags
@@ -13,32 +13,14 @@ option java_package com.android.server.am
# Do not change these names without updating the checkin_events setting in
# google3/googledata/wireless/android/provisioning/gservices.config !!
#
-# An activity is being finished:
-30001 am_finish_activity (User|1|5),(Token|1|5),(Task ID|1|5),(Component Name|3),(Reason|3)
-# A task is being brought to the front of the screen:
-30002 am_task_to_front (User|1|5),(Task|1|5)
-# An existing activity is being given a new intent:
-30003 am_new_intent (User|1|5),(Token|1|5),(Task ID|1|5),(Component Name|3),(Action|3),(MIME Type|3),(URI|3),(Flags|1|5)
-# A new task is being created:
-30004 am_create_task (User|1|5),(Task ID|1|5)
-# A new activity is being created in an existing task:
-30005 am_create_activity (User|1|5),(Token|1|5),(Task ID|1|5),(Component Name|3),(Action|3),(MIME Type|3),(URI|3),(Flags|1|5)
-# An activity has been resumed into the foreground but was not already running:
-30006 am_restart_activity (User|1|5),(Token|1|5),(Task ID|1|5),(Component Name|3)
-# An activity has been resumed and is now in the foreground:
-30007 am_resume_activity (User|1|5),(Token|1|5),(Task ID|1|5),(Component Name|3)
# Application Not Responding
30008 am_anr (User|1|5),(pid|1|5),(Package Name|3),(Flags|1|5),(reason|3)
-# Activity launch time
-30009 am_activity_launch_time (User|1|5),(Token|1|5),(Component Name|3),(time|2|3)
+
# Application process bound to work
30010 am_proc_bound (User|1|5),(PID|1|5),(Process Name|3)
# Application process died
30011 am_proc_died (User|1|5),(PID|1|5),(Process Name|3),(OomAdj|1|5),(ProcState|1|5)
-# The Activity Manager failed to pause the given activity.
-30012 am_failed_to_pause (User|1|5),(Token|1|5),(Wanting to pause|3),(Currently pausing|3)
-# Attempting to pause the current activity
-30013 am_pause_activity (User|1|5),(Token|1|5),(Component Name|3),(User Leaving|3)
+
# Application process has been started
30014 am_proc_start (User|1|5),(PID|1|5),(UID|1|5),(Process Name|3),(Type|3),(Component|3)
# An application process has been marked as bad
@@ -47,16 +29,7 @@ option java_package com.android.server.am
30016 am_proc_good (User|1|5),(UID|1|5),(Process Name|3)
# Reporting to applications that memory is low
30017 am_low_memory (Num Processes|1|1)
-# An activity is being destroyed:
-30018 am_destroy_activity (User|1|5),(Token|1|5),(Task ID|1|5),(Component Name|3),(Reason|3)
-# An activity has been relaunched, resumed, and is now in the foreground:
-30019 am_relaunch_resume_activity (User|1|5),(Token|1|5),(Task ID|1|5),(Component Name|3)
-# An activity has been relaunched:
-30020 am_relaunch_activity (User|1|5),(Token|1|5),(Task ID|1|5),(Component Name|3)
-# The activity's onPause has been called.
-30021 am_on_paused_called (Token|1|5),(Component Name|3),(Reason|3)
-# The activity's onResume has been called.
-30022 am_on_resume_called (Token|1|5),(Component Name|3),(Reason|3)
+
# Kill a process to reclaim memory.
30023 am_kill (User|1|5),(PID|1|5),(Process Name|3),(OomAdj|1|5),(Reason|3)
# Discard an undelivered serialized broadcast (timeout/ANR/crash)
@@ -87,12 +60,6 @@ option java_package com.android.server.am
# User switched
30041 am_switch_user (id|1|5)
-# Activity set to resumed
-30043 am_set_resumed_activity (User|1|5),(Component Name|3),(Reason|3)
-
-# Stack focus
-30044 am_focused_stack (User|1|5),(Display Id|1|5),(Focused Stack Id|1|5),(Last Focused Stack Id|1|5),(Reason|3)
-
# Running pre boot receiver
30045 am_pre_boot (User|1|5),(Package|3)
@@ -101,11 +68,6 @@ option java_package com.android.server.am
# Report collection of memory used by a process
30047 am_pss (Pid|1|5),(UID|1|5),(Process Name|3),(Pss|2|2),(Uss|2|2),(SwapPss|2|2),(Rss|2|2),(StatType|1|5),(ProcState|1|5),(TimeToCollect|2|2)
-# Attempting to stop an activity
-30048 am_stop_activity (User|1|5),(Token|1|5),(Component Name|3)
-# The activity's onStop has been called.
-30049 am_on_stop_called (Token|1|5),(Component Name|3),(Reason|3)
-
# Report changing memory conditions (Values are ProcessStats.ADJ_MEM_FACTOR* constants)
30050 am_mem_factor (Current|1|5),(Previous|1|5)
@@ -123,30 +85,6 @@ option java_package com.android.server.am
# Note when a service is being forcibly stopped because its app went idle.
30056 am_stop_idle_service (UID|1|5),(Component Name|3)
-# The activity's onCreate has been called.
-30057 am_on_create_called (Token|1|5),(Component Name|3),(Reason|3)
-# The activity's onRestart has been called.
-30058 am_on_restart_called (Token|1|5),(Component Name|3),(Reason|3)
-# The activity's onStart has been called.
-30059 am_on_start_called (Token|1|5),(Component Name|3),(Reason|3)
-# The activity's onDestroy has been called.
-30060 am_on_destroy_called (Token|1|5),(Component Name|3),(Reason|3)
-# The activity's onActivityResult has been called.
-30062 am_on_activity_result_called (Token|1|5),(Component Name|3),(Reason|3)
-
-# The task is being removed from its parent stack
-30061 am_remove_task (Task ID|1|5), (Stack ID|1|5)
-
# The task is being compacted
30063 am_compact (Pid|1|5),(Process Name|3),(Action|3),(BeforeRssTotal|2|2),(BeforeRssFile|2|2),(BeforeRssAnon|2|2),(BeforeRssSwap|2|2),(DeltaRssTotal|2|2),(DeltaRssFile|2|2),(DeltaRssAnon|2|2),(DeltaRssSwap|2|2),(Time|2|3),(LastAction|1|2),(LastActionTimestamp|2|3),(setAdj|1|2),(procState|1|2),(BeforeZRAMFree|2|2),(DeltaZRAMFree|2|2)
-# The activity's onTopResumedActivityChanged(true) has been called.
-30064 am_on_top_resumed_gained_called (Token|1|5),(Component Name|3),(Reason|3)
-# The activity's onTopResumedActivityChanged(false) has been called.
-30065 am_on_top_resumed_lost_called (Token|1|5),(Component Name|3),(Reason|3)
-
-# An activity been add into stopping list
-30066 am_add_to_stopping (User|1|5),(Token|1|5),(Component Name|3),(Reason|3)
-
-# Keyguard status changed
-+30067 am_set_keyguard_shown (keyguardShowing|1),(aodShowing|1),(keyguardGoingAway|1),(Reason|3) \ No newline at end of file
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 2bb703545cad..375da8a2f385 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -1421,7 +1421,7 @@ public final class ProcessList {
if (app.pendingStart) {
return true;
}
- long startTime = SystemClock.elapsedRealtime();
+ long startTime = SystemClock.uptimeMillis();
if (app.pid > 0 && app.pid != ActivityManagerService.MY_PID) {
checkSlow(startTime, "startProcess: removing from pids map");
mService.mPidsSelfLocked.remove(app);
@@ -1856,7 +1856,7 @@ public final class ProcessList {
boolean knownToBeDead, int intentFlags, HostingRecord hostingRecord,
boolean allowWhileBooting, boolean isolated, int isolatedUid, boolean keepIfLarge,
String abiOverride, String entryPoint, String[] entryPointArgs, Runnable crashHandler) {
- long startTime = SystemClock.elapsedRealtime();
+ long startTime = SystemClock.uptimeMillis();
ProcessRecord app;
if (!isolated) {
app = getProcessRecordLocked(processName, info.uid, keepIfLarge);
@@ -1917,10 +1917,9 @@ public final class ProcessList {
// An application record is attached to a previous process,
// clean it up now.
if (DEBUG_PROCESSES) Slog.v(TAG_PROCESSES, "App died: " + app);
- checkSlow(startTime, "startProcess: bad proc running, killing");
ProcessList.killProcessGroup(app.uid, app.pid);
- mService.handleAppDiedLocked(app, true, true);
- checkSlow(startTime, "startProcess: done killing old proc");
+ mService.waitForProcKillLocked(app, "startProcess: bad proc running, killing: %s",
+ startTime);
}
if (app == null) {
diff --git a/services/core/java/com/android/server/compat/CompatChange.java b/services/core/java/com/android/server/compat/CompatChange.java
index 87624359ef85..95582f73035a 100644
--- a/services/core/java/com/android/server/compat/CompatChange.java
+++ b/services/core/java/com/android/server/compat/CompatChange.java
@@ -38,6 +38,20 @@ import java.util.Map;
*/
public final class CompatChange extends CompatibilityChangeInfo {
+ /**
+ * Callback listener for when compat changes are updated for a package.
+ * See {@link #registerListener(ChangeListener)} for more details.
+ */
+ public interface ChangeListener {
+ /**
+ * Called upon an override change for packageName and the change this listener is
+ * registered for. Called before the app is killed.
+ */
+ void onCompatChange(String packageName);
+ }
+
+ ChangeListener mListener = null;
+
private Map<String, Boolean> mPackageOverrides;
public CompatChange(long changeId) {
@@ -64,6 +78,15 @@ public final class CompatChange extends CompatibilityChangeInfo {
change.getDisabled());
}
+ void registerListener(ChangeListener listener) {
+ if (mListener != null) {
+ throw new IllegalStateException(
+ "Listener for change " + toString() + " already registered.");
+ }
+ mListener = listener;
+ }
+
+
/**
* Force the enabled state of this change for a given package name. The change will only take
* effect after that packages process is killed and restarted.
@@ -78,6 +101,7 @@ public final class CompatChange extends CompatibilityChangeInfo {
mPackageOverrides = new HashMap<>();
}
mPackageOverrides.put(pname, enabled);
+ notifyListener(pname);
}
/**
@@ -89,7 +113,9 @@ public final class CompatChange extends CompatibilityChangeInfo {
*/
void removePackageOverride(String pname) {
if (mPackageOverrides != null) {
- mPackageOverrides.remove(pname);
+ if (mPackageOverrides.remove(pname) != null) {
+ notifyListener(pname);
+ }
}
}
@@ -131,4 +157,10 @@ public final class CompatChange extends CompatibilityChangeInfo {
}
return sb.append(")").toString();
}
+
+ private void notifyListener(String packageName) {
+ if (mListener != null) {
+ mListener.onCompatChange(packageName);
+ }
+ }
}
diff --git a/services/core/java/com/android/server/compat/CompatConfig.java b/services/core/java/com/android/server/compat/CompatConfig.java
index 490cce347188..39c6e7552e3c 100644
--- a/services/core/java/com/android/server/compat/CompatConfig.java
+++ b/services/core/java/com/android/server/compat/CompatConfig.java
@@ -228,7 +228,7 @@ final class CompatConfig {
/**
* Removes all overrides previously added via {@link #addOverride(long, String, boolean)} or
- * {@link #addAppOverrides(CompatibilityChangeConfig, String)} for a certain package.
+ * {@link #addOverrides(CompatibilityChangeConfig, String)} for a certain package.
*
* <p>This restores the default behaviour for the given change and app, once any app
* processes have been restarted.
@@ -243,6 +243,27 @@ final class CompatConfig {
}
}
+ boolean registerListener(long changeId, CompatChange.ChangeListener listener) {
+ boolean alreadyKnown = true;
+ synchronized (mChanges) {
+ CompatChange c = mChanges.get(changeId);
+ if (c == null) {
+ alreadyKnown = false;
+ c = new CompatChange(changeId);
+ addChange(c);
+ }
+ c.registerListener(listener);
+ }
+ return alreadyKnown;
+ }
+
+ @VisibleForTesting
+ void clearChanges() {
+ synchronized (mChanges) {
+ mChanges.clear();
+ }
+ }
+
/**
* Dumps the current list of compatibility config information.
*
diff --git a/services/core/java/com/android/server/compat/PlatformCompat.java b/services/core/java/com/android/server/compat/PlatformCompat.java
index 311e24fd5ee2..6ec4b9fbdb93 100644
--- a/services/core/java/com/android/server/compat/PlatformCompat.java
+++ b/services/core/java/com/android/server/compat/PlatformCompat.java
@@ -108,6 +108,23 @@ public class PlatformCompat extends IPlatformCompat.Stub {
return enabled;
}
+ /**
+ * Register a listener for change state overrides. Only one listener per change is allowed.
+ *
+ * <p>{@code listener.onCompatChange(String)} method is guaranteed to be called with
+ * packageName before the app is killed upon an override change. The state of a change is not
+ * guaranteed to change when {@code listener.onCompatChange(String)} is called.
+ *
+ * @param changeId to get updates for
+ * @param listener the listener that will be called upon a potential change for package.
+ * @throws IllegalStateException if a listener was already registered for changeId
+ * @returns {@code true} if a change with changeId was already known, or (@code false}
+ * otherwise.
+ */
+ public boolean registerListener(long changeId, CompatChange.ChangeListener listener) {
+ return CompatConfig.get().registerListener(changeId, listener);
+ }
+
@Override
public void setOverrides(CompatibilityChangeConfig overrides, String packageName) {
CompatConfig.get().addOverrides(overrides, packageName);
diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
index 24a5b7fa1489..bb7f86233a40 100644
--- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
@@ -580,7 +580,7 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
// semantics of WakeupMessage guarantee that if cancel is called then the alarm will
// never call its callback (handleLingerComplete), even if it has already fired.
// WakeupMessage makes no such guarantees about rescheduling a message, so if mLingerMessage
- // has already been dispatched, rescheduling to some time in the future it won't stop it
+ // has already been dispatched, rescheduling to some time in the future won't stop it
// from calling its callback immediately.
if (mLingerMessage != null) {
mLingerMessage.cancel();
diff --git a/services/core/java/com/android/server/display/DisplayDevice.java b/services/core/java/com/android/server/display/DisplayDevice.java
index 9882f6c0d4c1..7ce63c5f89b2 100644
--- a/services/core/java/com/android/server/display/DisplayDevice.java
+++ b/services/core/java/com/android/server/display/DisplayDevice.java
@@ -138,13 +138,17 @@ abstract class DisplayDevice {
}
/**
- * Sets the display modes the system is allowed to switch between, roughly ordered by
- * preference.
+ * Sets the refresh ranges, and display modes that the system is allowed to switch between.
+ * Display modes are roughly ordered by preference.
*
* Not all display devices will automatically switch between modes, so it's important that the
* most-desired modes are at the beginning of the allowed array.
+ *
+ * @param defaultModeId is used, if the device does not support multiple refresh
+ * rates, and to navigate other parameters.
*/
- public void setAllowedDisplayModesLocked(int[] modes) {
+ public void setDesiredDisplayConfigSpecs(int defaultModeId, float minRefreshRate,
+ float maxRefreshRate, int[] modes) {
}
/**
diff --git a/services/core/java/com/android/server/display/DisplayModeDirector.java b/services/core/java/com/android/server/display/DisplayModeDirector.java
index d24bd1aad1b1..6118df55e059 100644
--- a/services/core/java/com/android/server/display/DisplayModeDirector.java
+++ b/services/core/java/com/android/server/display/DisplayModeDirector.java
@@ -18,26 +18,22 @@ package com.android.server.display;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
import android.content.res.Resources;
import android.database.ContentObserver;
-import android.hardware.display.DisplayManager;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
-
+import android.hardware.display.DisplayManager;
import android.net.Uri;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
-import android.os.UserHandle;
import android.os.PowerManager;
import android.os.SystemClock;
+import android.os.UserHandle;
import android.provider.DeviceConfig;
import android.provider.Settings;
import android.text.TextUtils;
@@ -47,11 +43,11 @@ import android.util.SparseArray;
import android.view.Display;
import android.view.DisplayInfo;
-import com.android.internal.os.BackgroundThread;
import com.android.internal.R;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.os.BackgroundThread;
import com.android.server.display.utils.AmbientFilter;
import com.android.server.display.utils.AmbientFilterFactory;
-import com.android.server.display.whitebalance.DisplayWhiteBalanceFactory;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -87,11 +83,11 @@ public class DisplayModeDirector {
// A map from the display ID to the collection of votes and their priority. The latter takes
// the form of another map from the priority to the vote itself so that each priority is
// guaranteed to have exactly one vote, which is also easily and efficiently replaceable.
- private final SparseArray<SparseArray<Vote>> mVotesByDisplay;
+ private SparseArray<SparseArray<Vote>> mVotesByDisplay;
// A map from the display ID to the supported modes on that display.
- private final SparseArray<Display.Mode[]> mSupportedModesByDisplay;
+ private SparseArray<Display.Mode[]> mSupportedModesByDisplay;
// A map from the display ID to the default mode of that display.
- private final SparseArray<Display.Mode> mDefaultModeByDisplay;
+ private SparseArray<Display.Mode> mDefaultModeByDisplay;
private final AppRequestObserver mAppRequestObserver;
private final SettingsObserver mSettingsObserver;
@@ -143,17 +139,7 @@ public class DisplayModeDirector {
*/
@NonNull
public int[] getAllowedModes(int displayId) {
- synchronized (mLock) {
- SparseArray<Vote> votes = getVotesLocked(displayId);
- Display.Mode[] modes = mSupportedModesByDisplay.get(displayId);
- Display.Mode defaultMode = mDefaultModeByDisplay.get(displayId);
- if (modes == null || defaultMode == null) {
- Slog.e(TAG, "Asked about unknown display, returning empty allowed set! (id="
- + displayId + ")");
- return new int[0];
- }
- return getAllowedModesLocked(votes, modes, defaultMode);
- }
+ return getDesiredDisplayConfigSpecs(displayId).allowedConfigs;
}
@NonNull
@@ -178,76 +164,101 @@ public class DisplayModeDirector {
return votes;
}
+ /**
+ * Calculates the refresh rate ranges and display modes that the system is allowed to freely
+ * switch between based on global and display-specific constraints.
+ *
+ * @param displayId The display to query for.
+ * @return The ID of the default mode the system should use, and the refresh rate range the
+ * system is allowed to switch between.
+ */
@NonNull
- private int[] getAllowedModesLocked(@NonNull SparseArray<Vote> votes,
- @NonNull Display.Mode[] modes, @NonNull Display.Mode defaultMode) {
- int lowestConsideredPriority = Vote.MIN_PRIORITY;
- while (lowestConsideredPriority <= Vote.MAX_PRIORITY) {
+ public DesiredDisplayConfigSpecs getDesiredDisplayConfigSpecs(int displayId) {
+ synchronized (mLock) {
+ SparseArray<Vote> votes = getVotesLocked(displayId);
+ Display.Mode[] modes = mSupportedModesByDisplay.get(displayId);
+ Display.Mode defaultMode = mDefaultModeByDisplay.get(displayId);
+ if (modes == null || defaultMode == null) {
+ Slog.e(TAG, "Asked about unknown display, returning empty desired configs!"
+ + "(id=" + displayId + ")");
+ return new DesiredDisplayConfigSpecs(displayId, new RefreshRateRange(60, 60),
+ new int[0]);
+ }
+
+ int[] availableModes = new int[]{defaultMode.getModeId()};
float minRefreshRate = 0f;
float maxRefreshRate = Float.POSITIVE_INFINITY;
- int height = Vote.INVALID_SIZE;
- int width = Vote.INVALID_SIZE;
-
- for (int priority = Vote.MAX_PRIORITY;
- priority >= lowestConsideredPriority;
- priority--) {
- Vote vote = votes.get(priority);
- if (vote == null) {
- continue;
+ int lowestConsideredPriority = Vote.MIN_PRIORITY;
+ while (lowestConsideredPriority <= Vote.MAX_PRIORITY) {
+ int height = Vote.INVALID_SIZE;
+ int width = Vote.INVALID_SIZE;
+
+ for (int priority = Vote.MAX_PRIORITY;
+ priority >= lowestConsideredPriority; priority--) {
+ Vote vote = votes.get(priority);
+ if (vote == null) {
+ continue;
+ }
+ // For refresh rates, just use the tightest bounds of all the votes
+ minRefreshRate = Math.max(minRefreshRate, vote.refreshRateRange.min);
+ maxRefreshRate = Math.min(maxRefreshRate, vote.refreshRateRange.max);
+ // For display size, use only the first vote we come across (i.e. the highest
+ // priority vote that includes the width / height).
+ if (height == Vote.INVALID_SIZE && width == Vote.INVALID_SIZE
+ && vote.height > 0 && vote.width > 0) {
+ width = vote.width;
+ height = vote.height;
+ }
}
- // For refresh rates, just use the tightest bounds of all the votes
- minRefreshRate = Math.max(minRefreshRate, vote.minRefreshRate);
- maxRefreshRate = Math.min(maxRefreshRate, vote.maxRefreshRate);
- // For display size, use only the first vote we come across (i.e. the highest
- // priority vote that includes the width / height).
- if (height == Vote.INVALID_SIZE && width == Vote.INVALID_SIZE
- && vote.height > 0 && vote.width > 0) {
- width = vote.width;
- height = vote.height;
+
+ // If we don't have anything specifying the width / height of the display, just use
+ // the default width and height. We don't want these switching out from underneath
+ // us since it's a pretty disruptive behavior.
+ if (height == Vote.INVALID_SIZE || width == Vote.INVALID_SIZE) {
+ width = defaultMode.getPhysicalWidth();
+ height = defaultMode.getPhysicalHeight();
}
- }
- // If we don't have anything specifying the width / height of the display, just use the
- // default width and height. We don't want these switching out from underneath us since
- // it's a pretty disruptive behavior.
- if (height == Vote.INVALID_SIZE || width == Vote.INVALID_SIZE) {
- width = defaultMode.getPhysicalWidth();
- height = defaultMode.getPhysicalHeight();
- }
+ availableModes = filterModes(modes, width, height, minRefreshRate, maxRefreshRate);
+ if (availableModes.length > 0) {
+ if (DEBUG) {
+ Slog.w(TAG, "Found available modes=" + Arrays.toString(availableModes)
+ + " with lowest priority considered "
+ + Vote.priorityToString(lowestConsideredPriority)
+ + " and constraints: "
+ + "width=" + width
+ + ", height=" + height
+ + ", minRefreshRate=" + minRefreshRate
+ + ", maxRefreshRate=" + maxRefreshRate);
+ }
+ break;
+ }
- int[] availableModes =
- filterModes(modes, width, height, minRefreshRate, maxRefreshRate);
- if (availableModes.length > 0) {
if (DEBUG) {
- Slog.w(TAG, "Found available modes=" + Arrays.toString(availableModes)
- + " with lowest priority considered "
+ Slog.w(TAG, "Couldn't find available modes with lowest priority set to "
+ Vote.priorityToString(lowestConsideredPriority)
- + " and constraints: "
+ + " and with the following constraints: "
+ "width=" + width
+ ", height=" + height
+ ", minRefreshRate=" + minRefreshRate
+ ", maxRefreshRate=" + maxRefreshRate);
}
- return availableModes;
+
+ // If we haven't found anything with the current set of votes, drop the
+ // current lowest priority vote.
+ lowestConsideredPriority++;
}
- if (DEBUG) {
- Slog.w(TAG, "Couldn't find available modes with lowest priority set to "
- + Vote.priorityToString(lowestConsideredPriority)
- + " and with the following constraints: "
- + "width=" + width
- + ", height=" + height
- + ", minRefreshRate=" + minRefreshRate
- + ", maxRefreshRate=" + maxRefreshRate);
- }
- // If we haven't found anything with the current set of votes, drop the current lowest
- // priority vote.
- lowestConsideredPriority++;
- }
-
- // If we still haven't found anything that matches our current set of votes, just fall back
- // to the default mode.
- return new int[] { defaultMode.getModeId() };
+ int defaultModeId = defaultMode.getModeId();
+ if (availableModes.length > 0) {
+ defaultModeId = availableModes[0];
+ }
+ // filterModes function is going to filter the modes based on the voting system. If
+ // the application requests a given mode with preferredModeId function, it will be
+ // stored as the first and only element in available modes array.
+ return new DesiredDisplayConfigSpecs(defaultModeId,
+ new RefreshRateRange(minRefreshRate, maxRefreshRate), availableModes);
+ }
}
private int[] filterModes(Display.Mode[] supportedModes,
@@ -403,6 +414,21 @@ public class DisplayModeDirector {
}
}
+ @VisibleForTesting
+ void injectSupportedModesByDisplay(SparseArray<Display.Mode[]> supportedModesByDisplay) {
+ mSupportedModesByDisplay = supportedModesByDisplay;
+ }
+
+ @VisibleForTesting
+ void injectDefaultModeByDisplay(SparseArray<Display.Mode> defaultModeByDisplay) {
+ mDefaultModeByDisplay = defaultModeByDisplay;
+ }
+
+ @VisibleForTesting
+ void injectVotesByDisplay(SparseArray<SparseArray<Vote>> votesByDisplay) {
+ mVotesByDisplay = votesByDisplay;
+ }
+
/**
* Listens for changes to display mode coordination.
*/
@@ -452,7 +478,129 @@ public class DisplayModeDirector {
}
}
- private static final class Vote {
+ /**
+ * Information about the min and max refresh rate DM would like to set the display to.
+ */
+ public static final class RefreshRateRange {
+ /**
+ * The lowest desired refresh rate.
+ */
+ public final float min;
+ /**
+ * The highest desired refresh rate.
+ */
+ public final float max;
+
+ public RefreshRateRange(float min, float max) {
+ if (min < 0 || max < 0 || min > max) {
+ Slog.e(TAG, "Wrong values for min and max when initializing RefreshRateRange : "
+ + min + " " + max);
+ this.min = this.max = 0;
+ return;
+ }
+ this.min = min;
+ this.max = max;
+ }
+
+ /**
+ * Checks whether the two objects have the same values.
+ */
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ if (!(other instanceof RefreshRateRange)) {
+ return false;
+ }
+
+ RefreshRateRange refreshRateRange = (RefreshRateRange) other;
+ return (min == refreshRateRange.min && max == refreshRateRange.max);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(min, max);
+ }
+
+ @Override
+ public String toString() {
+ return "(" + min + " " + max + ")";
+ }
+ }
+
+ /**
+ * Information about the desired configuration to be set by the system. Includes the default
+ * configuration ID, refresh rate range, and the list of policy decisions that influenced the
+ * choice.
+ */
+ public static final class DesiredDisplayConfigSpecs {
+ /**
+ * Default configuration ID. This is what system defaults to for all other settings, or
+ * if the refresh rate range is not available.
+ */
+ public final int defaultModeId;
+ /**
+ * The refresh rate range.
+ */
+ public final RefreshRateRange refreshRateRange;
+ /**
+ * For legacy reasons, keep a list of allowed configs.
+ * TODO(b/142507213): Re-assess whether the list of allowed configs is still necessary.
+ */
+ public final int[] allowedConfigs;
+
+ public DesiredDisplayConfigSpecs(int defaultModeId,
+ @NonNull RefreshRateRange refreshRateRange,
+ @NonNull int[] allowedConfigs) {
+ this.defaultModeId = defaultModeId;
+ this.refreshRateRange = refreshRateRange;
+ this.allowedConfigs = allowedConfigs;
+ }
+
+ /**
+ * Returns a string representation of the object.
+ */
+ @Override
+ public String toString() {
+ return "DesiredDisplayConfigSpecs(defaultModeId=" + defaultModeId
+ + ", refreshRateRange=" + refreshRateRange.toString()
+ + ", allowedConfigs=" + Arrays.toString(allowedConfigs) + ")";
+ }
+ /**
+ * Checks whether the two objects have the same values.
+ */
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+
+ if (!(other instanceof DesiredDisplayConfigSpecs)) {
+ return false;
+ }
+
+ DesiredDisplayConfigSpecs desiredDisplayConfigSpecs =
+ (DesiredDisplayConfigSpecs) other;
+
+ if (defaultModeId != desiredDisplayConfigSpecs.defaultModeId) {
+ return false;
+ }
+ if (!refreshRateRange.equals(desiredDisplayConfigSpecs.refreshRateRange)) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(defaultModeId, refreshRateRange);
+ }
+ }
+
+ @VisibleForTesting
+ static final class Vote {
// LOW_BRIGHTNESS votes for a single refresh rate like [60,60], [90,90] or null.
// If the higher voters result is a range, it will fix the rate to a single choice.
// It's used to avoid rate switch in certain conditions.
@@ -499,15 +647,10 @@ public class DisplayModeDirector {
* The requested height of the display in pixels, or INVALID_SIZE;
*/
public final int height;
-
/**
- * The lowest desired refresh rate.
- */
- public final float minRefreshRate;
- /**
- * The highest desired refresh rate.
+ * Information about the min and max refresh rate DM would like to set the display to.
*/
- public final float maxRefreshRate;
+ public final RefreshRateRange refreshRateRange;
public static Vote forRefreshRates(float minRefreshRate, float maxRefreshRate) {
return new Vote(INVALID_SIZE, INVALID_SIZE, minRefreshRate, maxRefreshRate);
@@ -521,8 +664,8 @@ public class DisplayModeDirector {
float minRefreshRate, float maxRefreshRate) {
this.width = width;
this.height = height;
- this.minRefreshRate = minRefreshRate;
- this.maxRefreshRate = maxRefreshRate;
+ this.refreshRateRange =
+ new RefreshRateRange(minRefreshRate, maxRefreshRate);
}
public static String priorityToString(int priority) {
@@ -547,11 +690,9 @@ public class DisplayModeDirector {
@Override
public String toString() {
return "Vote{"
- + "width=" + width
- + ", height=" + height
- + ", minRefreshRate=" + minRefreshRate
- + ", maxRefreshRate=" + maxRefreshRate
- + "}";
+ + "width=" + width + ", height=" + height
+ + ", minRefreshRate=" + refreshRateRange.min
+ + ", maxRefreshRate=" + refreshRateRange.max + "}";
}
}
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index b03dc3b2ae93..158647395003 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -173,6 +173,8 @@ final class LocalDisplayAdapter extends DisplayAdapter {
private int mActiveModeId;
private boolean mActiveModeInvalid;
private int[] mAllowedModeIds;
+ private float mMinRefreshRate;
+ private float mMaxRefreshRate;
private boolean mAllowedModeIdsInvalid;
private int mActivePhysIndex;
private int[] mAllowedPhysIndexes;
@@ -623,7 +625,9 @@ final class LocalDisplayAdapter extends DisplayAdapter {
}
@Override
- public void setAllowedDisplayModesLocked(int[] modes) {
+ public void setDesiredDisplayConfigSpecs(int defaultModeId, float minRefreshRate,
+ float maxRefreshRate, int[] modes) {
+ updateDesiredDisplayConfigSpecs(defaultModeId, minRefreshRate, maxRefreshRate);
updateAllowedModesLocked(modes);
}
@@ -653,6 +657,7 @@ final class LocalDisplayAdapter extends DisplayAdapter {
return true;
}
+ // TODO(b/142507213): Remove once refresh rates are plummed through to kernel.
public void updateAllowedModesLocked(int[] allowedModes) {
if (Arrays.equals(allowedModes, mAllowedModeIds) && !mAllowedModeIdsInvalid) {
return;
@@ -662,6 +667,38 @@ final class LocalDisplayAdapter extends DisplayAdapter {
}
}
+ public void updateDesiredDisplayConfigSpecs(int defaultModeId, float minRefreshRate,
+ float maxRefreshRate) {
+ if (minRefreshRate == mMinRefreshRate
+ && maxRefreshRate == mMaxRefreshRate
+ && defaultModeId == mDefaultModeId) {
+ return;
+ }
+ if (updateDesiredDisplayConfigSpecsInternalLocked(defaultModeId, minRefreshRate,
+ maxRefreshRate)) {
+ updateDeviceInfoLocked();
+ }
+ }
+
+ public boolean updateDesiredDisplayConfigSpecsInternalLocked(int defaultModeId,
+ float minRefreshRate, float maxRefreshRate) {
+ if (DEBUG) {
+ Slog.w(TAG, "updateDesiredDisplayConfigSpecsInternalLocked("
+ + "defaultModeId="
+ + Integer.toString(defaultModeId)
+ + ", minRefreshRate="
+ + Float.toString(minRefreshRate)
+ + ", maxRefreshRate="
+ + Float.toString(minRefreshRate));
+ }
+
+ final IBinder token = getDisplayTokenLocked();
+ SurfaceControl.setDesiredDisplayConfigSpecs(token, defaultModeId, minRefreshRate,
+ maxRefreshRate);
+ int activePhysIndex = SurfaceControl.getActiveConfig(token);
+ return updateActiveModeLocked(activePhysIndex);
+ }
+
public boolean updateAllowedModesInternalLocked(int[] allowedModes) {
if (DEBUG) {
Slog.w(TAG, "updateAllowedModesInternalLocked(allowedModes="
@@ -735,6 +772,8 @@ final class LocalDisplayAdapter extends DisplayAdapter {
pw.println("mPhysicalDisplayId=" + mPhysicalDisplayId);
pw.println("mAllowedPhysIndexes=" + Arrays.toString(mAllowedPhysIndexes));
pw.println("mAllowedModeIds=" + Arrays.toString(mAllowedModeIds));
+ pw.println("mMinRefreshRate=" + mMinRefreshRate);
+ pw.println("mMaxRefreshRate=" + mMaxRefreshRate);
pw.println("mAllowedModeIdsInvalid=" + mAllowedModeIdsInvalid);
pw.println("mActivePhysIndex=" + mActivePhysIndex);
pw.println("mActiveModeId=" + mActiveModeId);
diff --git a/services/core/java/com/android/server/display/LogicalDisplay.java b/services/core/java/com/android/server/display/LogicalDisplay.java
index dcef99817fac..f4b2dc8cfc98 100644
--- a/services/core/java/com/android/server/display/LogicalDisplay.java
+++ b/services/core/java/com/android/server/display/LogicalDisplay.java
@@ -352,11 +352,12 @@ final class LogicalDisplay {
// Set the color mode and allowed display mode.
if (device == mPrimaryDisplayDevice) {
- device.setAllowedDisplayModesLocked(mAllowedDisplayModes);
+ // See ag/9588196 for correct values.
+ device.setDesiredDisplayConfigSpecs(0, 60, 60, mAllowedDisplayModes);
device.setRequestedColorModeLocked(mRequestedColorMode);
} else {
// Reset to default for non primary displays
- device.setAllowedDisplayModesLocked(new int[] {0});
+ device.setDesiredDisplayConfigSpecs(0, 60, 60, new int[] {0});
device.setRequestedColorModeLocked(0);
}
diff --git a/services/core/java/com/android/server/display/OverlayDisplayAdapter.java b/services/core/java/com/android/server/display/OverlayDisplayAdapter.java
index 60cfbd0da2c3..739dd64451e4 100644
--- a/services/core/java/com/android/server/display/OverlayDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/OverlayDisplayAdapter.java
@@ -315,16 +315,9 @@ final class OverlayDisplayAdapter extends DisplayAdapter {
}
@Override
- public void setAllowedDisplayModesLocked(int[] modes) {
- final int id;
- if (modes.length > 0) {
- // The allowed modes should be ordered by preference, so just use the first mode
- // here.
- id = modes[0];
- } else {
- // If we don't have any allowed modes, just use the default mode.
- id = 0;
- }
+ public void setDesiredDisplayConfigSpecs(int defaultModeId, float minRefreshRate,
+ float maxRefreshRate, int[] modes) {
+ final int id = defaultModeId;
int index = -1;
if (id == 0) {
// Use the default.
diff --git a/services/core/java/com/android/server/display/WifiDisplayController.java b/services/core/java/com/android/server/display/WifiDisplayController.java
index 283a78b4e8b4..2992f1e47dc7 100644
--- a/services/core/java/com/android/server/display/WifiDisplayController.java
+++ b/services/core/java/com/android/server/display/WifiDisplayController.java
@@ -508,8 +508,7 @@ final class WifiDisplayController implements DumpUtils.Dump {
Slog.d(TAG, "updateDesiredDevice: new information "
+ describeWifiP2pDevice(device));
}
- mDesiredDevice.updateSupplicantDetails(device);
- mDesiredDevice.status = device.status;
+ mDesiredDevice.update(device);
if (mAdvertisedDisplay != null
&& mAdvertisedDisplay.getDeviceAddress().equals(address)) {
readvertiseDisplay(createWifiDisplay(mDesiredDevice));
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
index 9a85f952446b..a702ce517f40 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
@@ -1557,6 +1557,18 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
if (!connected) {
removeCecSwitches(portId);
}
+
+ // Turning System Audio Mode off when the AVR is unlugged or standby.
+ // When the device is not unplugged but reawaken from standby, we check if the System
+ // Audio Control Feature is enabled or not then decide if turning SAM on/off accordingly.
+ if (getAvrDeviceInfo() != null && portId == getAvrDeviceInfo().getPortId()) {
+ if (!connected) {
+ setSystemAudioMode(false);
+ } else if (mSystemAudioControlFeatureEnabled != mService.isSystemAudioActivated()){
+ setSystemAudioMode(mSystemAudioControlFeatureEnabled);
+ }
+ }
+
// Tv device will have permanent HotplugDetectionAction.
List<HotplugDetectionAction> hotplugActions = getActions(HotplugDetectionAction.class);
if (!hotplugActions.isEmpty()) {
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index 67a23dd73854..16b7d9951ad4 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -171,7 +171,6 @@ public class InputManagerService extends IInputManager.Stub
private final ArrayList<InputDevice>
mTempFullKeyboards = new ArrayList<InputDevice>(); // handler thread only
private boolean mKeyboardLayoutNotificationShown;
- private PendingIntent mKeyboardLayoutIntent;
private Toast mSwitchedKeyboardLayoutToast;
// State for vibrator tokens.
@@ -205,6 +204,7 @@ public class InputManagerService extends IInputManager.Stub
private static native void nativeUnregisterInputChannel(long ptr, InputChannel inputChannel);
private static native void nativePilferPointers(long ptr, IBinder token);
private static native void nativeSetInputFilterEnabled(long ptr, boolean enable);
+ private static native void nativeSetInTouchMode(long ptr, boolean inTouchMode);
private static native int nativeInjectInputEvent(long ptr, InputEvent event,
int injectorPid, int injectorUid, int syncMode, int timeoutMillis,
int policyFlags);
@@ -603,6 +603,25 @@ public class InputManagerService extends IInputManager.Stub
}
}
+ /**
+ * Set the state of the touch mode.
+ *
+ * WindowManager remains the source of truth of the touch mode state.
+ * However, we need to keep a copy of this state in input.
+ *
+ * The apps determine the touch mode state. Therefore, a single app will
+ * affect the global state. That state change needs to be propagated to
+ * other apps, when they become focused.
+ *
+ * When input dispatches focus to the apps, the touch mode state
+ * will be sent together with the focus change.
+ *
+ * @param inTouchMode true if the device is in touch mode.
+ */
+ public void setInTouchMode(boolean inTouchMode) {
+ nativeSetInTouchMode(mPtr, inTouchMode);
+ }
+
@Override // Binder call
public boolean injectInputEvent(InputEvent event, int mode) {
return injectInputEventInternal(event, mode);
diff --git a/services/core/java/com/android/server/integrity/engine/RuleEvaluationEngine.java b/services/core/java/com/android/server/integrity/engine/RuleEvaluationEngine.java
index f0bb192e3b61..b8202b6c0dc6 100644
--- a/services/core/java/com/android/server/integrity/engine/RuleEvaluationEngine.java
+++ b/services/core/java/com/android/server/integrity/engine/RuleEvaluationEngine.java
@@ -16,9 +16,10 @@
package com.android.server.integrity.engine;
-import com.android.server.integrity.model.AppInstallMetadata;
+import android.content.integrity.AppInstallMetadata;
+import android.content.integrity.Rule;
+
import com.android.server.integrity.model.IntegrityCheckResult;
-import com.android.server.integrity.model.Rule;
import java.util.ArrayList;
import java.util.List;
@@ -26,8 +27,8 @@ import java.util.List;
/**
* The engine used to evaluate rules against app installs.
*
- * <p>Every app install is evaluated against rules (pushed by the verifier) by the evaluation
- * engine to allow/block that install.
+ * <p>Every app install is evaluated against rules (pushed by the verifier) by the evaluation engine
+ * to allow/block that install.
*/
public final class RuleEvaluationEngine {
private static final String TAG = "RuleEvaluation";
@@ -36,9 +37,7 @@ public final class RuleEvaluationEngine {
// installs against rules.
private static RuleEvaluationEngine sRuleEvaluationEngine;
- /**
- * Provide a singleton instance of the rule evaluation engine.
- */
+ /** Provide a singleton instance of the rule evaluation engine. */
public static synchronized RuleEvaluationEngine getRuleEvaluationEngine() {
if (sRuleEvaluationEngine == null) {
return new RuleEvaluationEngine();
@@ -50,7 +49,7 @@ public final class RuleEvaluationEngine {
* Load, and match the list of rules against an app install metadata.
*
* @param appInstallMetadata Metadata of the app to be installed, and to evaluate the rules
- * against.
+ * against.
* @return result of the integrity check
*/
public IntegrityCheckResult evaluate(AppInstallMetadata appInstallMetadata) {
diff --git a/services/core/java/com/android/server/integrity/engine/RuleEvaluator.java b/services/core/java/com/android/server/integrity/engine/RuleEvaluator.java
index 7deae466ac3f..ee51d4f87848 100644
--- a/services/core/java/com/android/server/integrity/engine/RuleEvaluator.java
+++ b/services/core/java/com/android/server/integrity/engine/RuleEvaluator.java
@@ -16,18 +16,18 @@
package com.android.server.integrity.engine;
-import static com.android.server.integrity.model.Rule.DENY;
-import static com.android.server.integrity.model.Rule.FORCE_ALLOW;
+import static android.content.integrity.Rule.DENY;
+import static android.content.integrity.Rule.FORCE_ALLOW;
import android.annotation.NonNull;
+import android.content.integrity.AppInstallMetadata;
+import android.content.integrity.AtomicFormula;
+import android.content.integrity.CompoundFormula;
+import android.content.integrity.Formula;
+import android.content.integrity.Rule;
import android.util.Slog;
-import com.android.server.integrity.model.AppInstallMetadata;
-import com.android.server.integrity.model.AtomicFormula;
-import com.android.server.integrity.model.Formula;
import com.android.server.integrity.model.IntegrityCheckResult;
-import com.android.server.integrity.model.OpenFormula;
-import com.android.server.integrity.model.Rule;
import java.util.ArrayList;
import java.util.List;
@@ -89,17 +89,17 @@ final class RuleEvaluator {
if (isAtomicFormula(formula)) {
return true;
}
- OpenFormula openFormula = (OpenFormula) formula;
- return openFormula.getConnector() == OpenFormula.AND
- && openFormula.getFormulas().stream().allMatch(RuleEvaluator::isAtomicFormula);
+ CompoundFormula compoundFormula = (CompoundFormula) formula;
+ return compoundFormula.getConnector() == CompoundFormula.AND
+ && compoundFormula.getFormulas().stream().allMatch(RuleEvaluator::isAtomicFormula);
}
private static boolean isAtomicFormula(Formula formula) {
if (formula instanceof AtomicFormula) {
return true;
}
- OpenFormula openFormula = (OpenFormula) formula;
- return openFormula.getConnector() == OpenFormula.NOT
- && openFormula.getFormulas().get(0) instanceof AtomicFormula;
+ CompoundFormula compoundFormula = (CompoundFormula) formula;
+ return compoundFormula.getConnector() == CompoundFormula.NOT
+ && compoundFormula.getFormulas().get(0) instanceof AtomicFormula;
}
}
diff --git a/services/core/java/com/android/server/integrity/engine/RuleLoader.java b/services/core/java/com/android/server/integrity/engine/RuleLoader.java
index af24d7a21dc8..4ba2bfb00d05 100644
--- a/services/core/java/com/android/server/integrity/engine/RuleLoader.java
+++ b/services/core/java/com/android/server/integrity/engine/RuleLoader.java
@@ -16,7 +16,7 @@
package com.android.server.integrity.engine;
-import com.android.server.integrity.model.Rule;
+import android.content.integrity.Rule;
import java.util.ArrayList;
import java.util.List;
diff --git a/services/core/java/com/android/server/integrity/model/IntegrityCheckResult.java b/services/core/java/com/android/server/integrity/model/IntegrityCheckResult.java
index ef0751d329d0..b3cb31ac8cb1 100644
--- a/services/core/java/com/android/server/integrity/model/IntegrityCheckResult.java
+++ b/services/core/java/com/android/server/integrity/model/IntegrityCheckResult.java
@@ -17,6 +17,7 @@
package com.android.server.integrity.model;
import android.annotation.Nullable;
+import android.content.integrity.Rule;
/**
* A class encapsulating the result from the evaluation engine after evaluating rules against app
diff --git a/services/core/java/com/android/server/integrity/parser/RuleBinaryParser.java b/services/core/java/com/android/server/integrity/parser/RuleBinaryParser.java
index 5ed282cd8b1f..111b95a05d24 100644
--- a/services/core/java/com/android/server/integrity/parser/RuleBinaryParser.java
+++ b/services/core/java/com/android/server/integrity/parser/RuleBinaryParser.java
@@ -16,7 +16,7 @@
package com.android.server.integrity.parser;
-import com.android.server.integrity.model.Rule;
+import android.content.integrity.Rule;
import java.io.InputStream;
import java.util.List;
diff --git a/services/core/java/com/android/server/integrity/parser/RuleParser.java b/services/core/java/com/android/server/integrity/parser/RuleParser.java
index 08e0a5db8c20..4e1f9141c8ed 100644
--- a/services/core/java/com/android/server/integrity/parser/RuleParser.java
+++ b/services/core/java/com/android/server/integrity/parser/RuleParser.java
@@ -16,7 +16,7 @@
package com.android.server.integrity.parser;
-import com.android.server.integrity.model.Rule;
+import android.content.integrity.Rule;
import java.io.InputStream;
import java.util.List;
diff --git a/services/core/java/com/android/server/integrity/parser/RuleXmlParser.java b/services/core/java/com/android/server/integrity/parser/RuleXmlParser.java
index 1508c273f553..1212a083bfaa 100644
--- a/services/core/java/com/android/server/integrity/parser/RuleXmlParser.java
+++ b/services/core/java/com/android/server/integrity/parser/RuleXmlParser.java
@@ -16,13 +16,12 @@
package com.android.server.integrity.parser;
+import android.content.integrity.AtomicFormula;
+import android.content.integrity.CompoundFormula;
+import android.content.integrity.Formula;
+import android.content.integrity.Rule;
import android.util.Xml;
-import com.android.server.integrity.model.AtomicFormula;
-import com.android.server.integrity.model.Formula;
-import com.android.server.integrity.model.OpenFormula;
-import com.android.server.integrity.model.Rule;
-
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -34,9 +33,7 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
-/**
- * A helper class to parse rules into the {@link Rule} model from Xml representation.
- */
+/** A helper class to parse rules into the {@link Rule} model from Xml representation. */
public final class RuleXmlParser implements RuleParser {
public static final String TAG = "RuleXmlParser";
@@ -90,7 +87,8 @@ public final class RuleXmlParser implements RuleParser {
// corrupt in the XML, it will be skipped to the next rule.
if (!nodeName.equals(RULE_LIST_TAG)) {
throw new RuntimeException(
- String.format("Rules must start with RuleList <RL> tag. Found: %s at %s",
+ String.format(
+ "Rules must start with RuleList <RL> tag. Found: %s at %s",
nodeName, parser.getPositionDescription()));
}
@@ -141,8 +139,8 @@ public final class RuleXmlParser implements RuleParser {
private static Formula parseOpenFormula(XmlPullParser parser)
throws IOException, XmlPullParserException {
- int connector = Integer.parseInt(
- extractAttributeValue(parser, CONNECTOR_ATTRIBUTE).orElse("-1"));
+ int connector =
+ Integer.parseInt(extractAttributeValue(parser, CONNECTOR_ATTRIBUTE).orElse("-1"));
List<Formula> formulas = new ArrayList<>();
int eventType;
@@ -171,17 +169,17 @@ public final class RuleXmlParser implements RuleParser {
}
}
- return new OpenFormula(connector, formulas);
+ return new CompoundFormula(connector, formulas);
}
private static Formula parseAtomicFormula(XmlPullParser parser)
throws IOException, XmlPullParserException {
int key = Integer.parseInt(extractAttributeValue(parser, KEY_ATTRIBUTE).orElse("-1"));
- int operator = Integer.parseInt(
- extractAttributeValue(parser, OPERATOR_ATTRIBUTE).orElse("-1"));
+ int operator =
+ Integer.parseInt(extractAttributeValue(parser, OPERATOR_ATTRIBUTE).orElse("-1"));
String value = extractAttributeValue(parser, VALUE_ATTRIBUTE).orElse(null);
- String isHashedValue = extractAttributeValue(parser, IS_HASHED_VALUE_ATTRIBUTE).orElse(
- null);
+ String isHashedValue =
+ extractAttributeValue(parser, IS_HASHED_VALUE_ATTRIBUTE).orElse(null);
int eventType;
while ((eventType = parser.next()) != XmlPullParser.END_DOCUMENT) {
@@ -192,15 +190,18 @@ public final class RuleXmlParser implements RuleParser {
return constructAtomicFormulaBasedOnKey(key, operator, value, isHashedValue);
}
- private static Formula constructAtomicFormulaBasedOnKey(@AtomicFormula.Key int key,
- @AtomicFormula.Operator int operator, String value, String isHashedValue) {
+ private static Formula constructAtomicFormulaBasedOnKey(
+ @AtomicFormula.Key int key,
+ @AtomicFormula.Operator int operator,
+ String value,
+ String isHashedValue) {
switch (key) {
case AtomicFormula.PACKAGE_NAME:
case AtomicFormula.INSTALLER_NAME:
case AtomicFormula.APP_CERTIFICATE:
case AtomicFormula.INSTALLER_CERTIFICATE:
- return new AtomicFormula.StringAtomicFormula(key, value,
- Boolean.parseBoolean(isHashedValue));
+ return new AtomicFormula.StringAtomicFormula(
+ key, value, Boolean.parseBoolean(isHashedValue));
case AtomicFormula.PRE_INSTALLED:
return new AtomicFormula.BooleanAtomicFormula(key, Boolean.parseBoolean(value));
case AtomicFormula.VERSION_CODE:
diff --git a/services/core/java/com/android/server/integrity/serializer/RuleBinarySerializer.java b/services/core/java/com/android/server/integrity/serializer/RuleBinarySerializer.java
index ee95d2bb4d69..7ecd6240e49a 100644
--- a/services/core/java/com/android/server/integrity/serializer/RuleBinarySerializer.java
+++ b/services/core/java/com/android/server/integrity/serializer/RuleBinarySerializer.java
@@ -16,21 +16,23 @@
package com.android.server.integrity.serializer;
-import com.android.server.integrity.model.Rule;
+import android.content.integrity.Rule;
import java.io.OutputStream;
import java.util.List;
+import java.util.Optional;
/** A helper class to serialize rules from the {@link Rule} model to Xml representation. */
public class RuleBinarySerializer implements RuleSerializer {
@Override
- public void serialize(List<Rule> rules, OutputStream outputStream) {
+ public void serialize(
+ List<Rule> rules, Optional<Integer> formatVersion, OutputStream outputStream) {
// TODO: Implement stream serializer.
}
@Override
- public String serialize(List<Rule> rules) {
+ public String serialize(List<Rule> rules, Optional<Integer> formatVersion) {
// TODO: Implement text serializer.
return null;
}
diff --git a/services/core/java/com/android/server/integrity/serializer/RuleSerializer.java b/services/core/java/com/android/server/integrity/serializer/RuleSerializer.java
index 5c99c5a4c2da..1125f788f635 100644
--- a/services/core/java/com/android/server/integrity/serializer/RuleSerializer.java
+++ b/services/core/java/com/android/server/integrity/serializer/RuleSerializer.java
@@ -16,17 +16,20 @@
package com.android.server.integrity.serializer;
-import com.android.server.integrity.model.Rule;
+import android.content.integrity.Rule;
import java.io.OutputStream;
import java.util.List;
+import java.util.Optional;
/** A helper class to serialize rules from the {@link Rule} model. */
public interface RuleSerializer {
/** Serialize rules to an output stream */
- void serialize(List<Rule> rules, OutputStream outputStream) throws RuleSerializeException;
+ void serialize(List<Rule> rules, Optional<Integer> formatVersion, OutputStream outputStream)
+ throws RuleSerializeException;
/** Serialize rules to a string. */
- String serialize(List<Rule> rule) throws RuleSerializeException;
+ String serialize(List<Rule> rule, Optional<Integer> formatVersion)
+ throws RuleSerializeException;
}
diff --git a/services/core/java/com/android/server/integrity/serializer/RuleXmlSerializer.java b/services/core/java/com/android/server/integrity/serializer/RuleXmlSerializer.java
index f2ba756ee0d1..254baba65df8 100644
--- a/services/core/java/com/android/server/integrity/serializer/RuleXmlSerializer.java
+++ b/services/core/java/com/android/server/integrity/serializer/RuleXmlSerializer.java
@@ -16,13 +16,12 @@
package com.android.server.integrity.serializer;
+import android.content.integrity.AtomicFormula;
+import android.content.integrity.CompoundFormula;
+import android.content.integrity.Formula;
+import android.content.integrity.Rule;
import android.util.Xml;
-import com.android.server.integrity.model.AtomicFormula;
-import com.android.server.integrity.model.Formula;
-import com.android.server.integrity.model.OpenFormula;
-import com.android.server.integrity.model.Rule;
-
import org.xmlpull.v1.XmlSerializer;
import java.io.IOException;
@@ -30,10 +29,9 @@ import java.io.OutputStream;
import java.io.StringWriter;
import java.nio.charset.StandardCharsets;
import java.util.List;
+import java.util.Optional;
-/**
- * A helper class to serialize rules from the {@link Rule} model to Xml representation.
- */
+/** A helper class to serialize rules from the {@link Rule} model to Xml representation. */
public class RuleXmlSerializer implements RuleSerializer {
public static final String TAG = "RuleXmlSerializer";
@@ -51,7 +49,8 @@ public class RuleXmlSerializer implements RuleSerializer {
private static final String IS_HASHED_VALUE_ATTRIBUTE = "H";
@Override
- public void serialize(List<Rule> rules, OutputStream outputStream)
+ public void serialize(
+ List<Rule> rules, Optional<Integer> formatVersion, OutputStream outputStream)
throws RuleSerializeException {
try {
XmlSerializer xmlSerializer = Xml.newSerializer();
@@ -63,7 +62,8 @@ public class RuleXmlSerializer implements RuleSerializer {
}
@Override
- public String serialize(List<Rule> rules) throws RuleSerializeException {
+ public String serialize(List<Rule> rules, Optional<Integer> formatVersion)
+ throws RuleSerializeException {
try {
XmlSerializer xmlSerializer = Xml.newSerializer();
StringWriter writer = new StringWriter();
@@ -97,23 +97,23 @@ public class RuleXmlSerializer implements RuleSerializer {
private void serializeFormula(Formula formula, XmlSerializer xmlSerializer) throws IOException {
if (formula instanceof AtomicFormula) {
serializeAtomicFormula((AtomicFormula) formula, xmlSerializer);
- } else if (formula instanceof OpenFormula) {
- serializeOpenFormula((OpenFormula) formula, xmlSerializer);
+ } else if (formula instanceof CompoundFormula) {
+ serializeOpenFormula((CompoundFormula) formula, xmlSerializer);
} else {
throw new IllegalArgumentException(
String.format("Invalid formula type: %s", formula.getClass()));
}
}
- private void serializeOpenFormula(OpenFormula openFormula, XmlSerializer xmlSerializer)
+ private void serializeOpenFormula(CompoundFormula compoundFormula, XmlSerializer xmlSerializer)
throws IOException {
- if (openFormula == null) {
+ if (compoundFormula == null) {
return;
}
xmlSerializer.startTag(NAMESPACE, OPEN_FORMULA_TAG);
- serializeAttributeValue(CONNECTOR_ATTRIBUTE, String.valueOf(openFormula.getConnector()),
- xmlSerializer);
- for (Formula formula : openFormula.getFormulas()) {
+ serializeAttributeValue(
+ CONNECTOR_ATTRIBUTE, String.valueOf(compoundFormula.getConnector()), xmlSerializer);
+ for (Formula formula : compoundFormula.getFormulas()) {
serializeFormula(formula, xmlSerializer);
}
xmlSerializer.endTag(NAMESPACE, OPEN_FORMULA_TAG);
@@ -125,24 +125,30 @@ public class RuleXmlSerializer implements RuleSerializer {
return;
}
xmlSerializer.startTag(NAMESPACE, ATOMIC_FORMULA_TAG);
- serializeAttributeValue(KEY_ATTRIBUTE, String.valueOf(atomicFormula.getKey()),
- xmlSerializer);
+ serializeAttributeValue(
+ KEY_ATTRIBUTE, String.valueOf(atomicFormula.getKey()), xmlSerializer);
if (atomicFormula instanceof AtomicFormula.StringAtomicFormula) {
- serializeAttributeValue(VALUE_ATTRIBUTE,
- ((AtomicFormula.StringAtomicFormula) atomicFormula).getValue(), xmlSerializer);
- serializeAttributeValue(IS_HASHED_VALUE_ATTRIBUTE,
+ serializeAttributeValue(
+ VALUE_ATTRIBUTE,
+ ((AtomicFormula.StringAtomicFormula) atomicFormula).getValue(),
+ xmlSerializer);
+ serializeAttributeValue(
+ IS_HASHED_VALUE_ATTRIBUTE,
String.valueOf(
((AtomicFormula.StringAtomicFormula) atomicFormula).getIsHashedValue()),
xmlSerializer);
} else if (atomicFormula instanceof AtomicFormula.IntAtomicFormula) {
- serializeAttributeValue(OPERATOR_ATTRIBUTE,
+ serializeAttributeValue(
+ OPERATOR_ATTRIBUTE,
String.valueOf(((AtomicFormula.IntAtomicFormula) atomicFormula).getOperator()),
xmlSerializer);
- serializeAttributeValue(VALUE_ATTRIBUTE,
+ serializeAttributeValue(
+ VALUE_ATTRIBUTE,
String.valueOf(((AtomicFormula.IntAtomicFormula) atomicFormula).getValue()),
xmlSerializer);
} else if (atomicFormula instanceof AtomicFormula.BooleanAtomicFormula) {
- serializeAttributeValue(VALUE_ATTRIBUTE,
+ serializeAttributeValue(
+ VALUE_ATTRIBUTE,
String.valueOf(((AtomicFormula.BooleanAtomicFormula) atomicFormula).getValue()),
xmlSerializer);
} else {
@@ -152,9 +158,8 @@ public class RuleXmlSerializer implements RuleSerializer {
xmlSerializer.endTag(NAMESPACE, ATOMIC_FORMULA_TAG);
}
- private void serializeAttributeValue(String attribute, String value,
- XmlSerializer xmlSerializer)
- throws IOException {
+ private void serializeAttributeValue(
+ String attribute, String value, XmlSerializer xmlSerializer) throws IOException {
if (value == null) {
return;
}
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index c84745e84646..557ba54b536d 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -1447,11 +1447,13 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
private float[] mSvElevations;
private float[] mSvAzimuths;
private float[] mSvCarrierFreqs;
+ private float[] mBasebandCn0s;
}
@NativeEntryPoint
private void reportSvStatus(int svCount, int[] svidWithFlags, float[] cn0s,
- float[] svElevations, float[] svAzimuths, float[] svCarrierFreqs) {
+ float[] svElevations, float[] svAzimuths, float[] svCarrierFreqs,
+ float[] basebandCn0s) {
SvStatusInfo svStatusInfo = new SvStatusInfo();
svStatusInfo.mSvCount = svCount;
svStatusInfo.mSvidWithFlags = svidWithFlags;
@@ -1459,6 +1461,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
svStatusInfo.mSvElevations = svElevations;
svStatusInfo.mSvAzimuths = svAzimuths;
svStatusInfo.mSvCarrierFreqs = svCarrierFreqs;
+ svStatusInfo.mBasebandCn0s = basebandCn0s;
sendMessage(REPORT_SV_STATUS, 0, svStatusInfo);
}
@@ -1470,7 +1473,8 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
info.mCn0s,
info.mSvElevations,
info.mSvAzimuths,
- info.mSvCarrierFreqs);
+ info.mSvCarrierFreqs,
+ info.mBasebandCn0s);
// Log CN0 as part of GNSS metrics
mGnssMetrics.logCn0(info.mCn0s, info.mSvCount, info.mSvCarrierFreqs);
@@ -1485,7 +1489,8 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
info.mCn0s,
info.mSvElevations,
info.mSvAzimuths,
- info.mSvCarrierFreqs);
+ info.mSvCarrierFreqs,
+ info.mBasebandCn0s);
int usedInFixCount = 0;
int maxCn0 = 0;
int meanCn0 = 0;
@@ -1501,13 +1506,15 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
if (VERBOSE) {
Log.v(TAG, "svid: " + gnssStatus.getSvid(i)
+ " cn0: " + gnssStatus.getCn0DbHz(i)
+ + " basebandCn0: " + gnssStatus.getBasebandCn0DbHz(i)
+ " elev: " + gnssStatus.getElevationDegrees(i)
+ " azimuth: " + gnssStatus.getAzimuthDegrees(i)
+ " carrier frequency: " + gnssStatus.getCn0DbHz(i)
+ (gnssStatus.hasEphemerisData(i) ? " E" : " ")
+ (gnssStatus.hasAlmanacData(i) ? " A" : " ")
+ (gnssStatus.usedInFix(i) ? "U" : "")
- + (gnssStatus.hasCarrierFrequencyHz(i) ? "F" : ""));
+ + (gnssStatus.hasCarrierFrequencyHz(i) ? "F" : "")
+ + (gnssStatus.hasBasebandCn0DbHz(i) ? "B" : ""));
}
}
if (usedInFixCount > 0) {
diff --git a/services/core/java/com/android/server/location/GnssStatusListenerHelper.java b/services/core/java/com/android/server/location/GnssStatusListenerHelper.java
index d67d0c5fe612..eaf63c87d93f 100644
--- a/services/core/java/com/android/server/location/GnssStatusListenerHelper.java
+++ b/services/core/java/com/android/server/location/GnssStatusListenerHelper.java
@@ -71,7 +71,8 @@ public abstract class GnssStatusListenerHelper extends RemoteListenerHelper<IGns
final float[] cn0s,
final float[] elevations,
final float[] azimuths,
- final float[] carrierFreqs) {
+ final float[] carrierFreqs,
+ final float[] basebandCn0s) {
foreach((IGnssStatusListener listener, CallerIdentity callerIdentity) -> {
if (!hasPermission(mContext, callerIdentity)) {
logPermissionDisabledEventNotReported(TAG, callerIdentity.mPackageName,
@@ -79,7 +80,7 @@ public abstract class GnssStatusListenerHelper extends RemoteListenerHelper<IGns
return;
}
listener.onSvStatusChanged(svCount, prnWithFlags, cn0s, elevations, azimuths,
- carrierFreqs);
+ carrierFreqs, basebandCn0s);
});
}
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index a4e7ac4d272b..83b62159f9b0 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -181,6 +181,7 @@ public class LockSettingsService extends ILockSettings.Stub {
private static final String SEPARATE_PROFILE_CHALLENGE_KEY = "lockscreen.profilechallenge";
private static final String PREV_SYNTHETIC_PASSWORD_HANDLE_KEY = "prev-sp-handle";
private static final String SYNTHETIC_PASSWORD_UPDATE_TIME_KEY = "sp-handle-ts";
+ private static final String USER_SERIAL_NUMBER_KEY = "serial-number";
// No challenge provided
private static final int CHALLENGE_NONE = 0;
@@ -661,6 +662,34 @@ public class LockSettingsService extends ILockSettings.Stub {
}
/**
+ * Clean up states associated with the given user, in case the userId is reused but LSS didn't
+ * get a chance to do cleanup previously during ACTION_USER_REMOVED.
+ *
+ * Internally, LSS stores serial number for each user and check it against the current user's
+ * serial number to determine if the userId is reused and invoke cleanup code.
+ */
+ private void cleanupDataForReusedUserIdIfNecessary(int userId) {
+ if (userId == UserHandle.USER_SYSTEM) {
+ // Short circuit as we never clean up user 0.
+ return;
+ }
+ // Serial number is never reusued, so we can use it as a distinguisher for user Id reuse.
+ int serialNumber = mUserManager.getUserSerialNumber(userId);
+
+ int storedSerialNumber = getIntUnchecked(USER_SERIAL_NUMBER_KEY, -1, userId);
+ if (storedSerialNumber != serialNumber) {
+ // If LockSettingsStorage does not have a copy of the serial number, it could be either
+ // this is a user created before the serial number recording logic is introduced, or
+ // the user does not exist or was removed and cleaned up properly. In either case, don't
+ // invoke removeUser().
+ if (storedSerialNumber != -1) {
+ removeUser(userId, /* unknownUser */ true);
+ }
+ setIntUnchecked(USER_SERIAL_NUMBER_KEY, serialNumber, userId);
+ }
+ }
+
+ /**
* Check if profile got unlocked but the keystore is still locked. This happens on full disk
* encryption devices since the profile may not yet be running when we consider unlocking it
* during the normal flow. In this case unlock the keystore for the profile.
@@ -684,6 +713,7 @@ public class LockSettingsService extends ILockSettings.Stub {
mHandler.post(new Runnable() {
@Override
public void run() {
+ cleanupDataForReusedUserIdIfNecessary(userId);
ensureProfileKeystoreUnlocked(userId);
// Hide notification first, as tie managed profile lock takes time
hideEncryptionNotification(new UserHandle(userId));
@@ -729,9 +759,6 @@ public class LockSettingsService extends ILockSettings.Stub {
if (Intent.ACTION_USER_ADDED.equals(intent.getAction())) {
// Notify keystore that a new user was added.
final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
- if (userHandle > UserHandle.USER_SYSTEM) {
- removeUser(userHandle, /* unknownUser= */ true);
- }
final KeyStore ks = KeyStore.getInstance();
final UserInfo parentInfo = mUserManager.getProfileParent(userHandle);
final int parentHandle = parentInfo != null ? parentInfo.id : -1;
@@ -1066,6 +1093,10 @@ public class LockSettingsService extends ILockSettings.Stub {
setStringUnchecked(key, userId, Long.toString(value));
}
+ private void setIntUnchecked(String key, int value, int userId) {
+ setStringUnchecked(key, userId, Integer.toString(value));
+ }
+
@Override
public void setString(String key, String value, int userId) {
checkWritePermission(userId);
@@ -1104,6 +1135,11 @@ public class LockSettingsService extends ILockSettings.Stub {
return TextUtils.isEmpty(value) ? defaultValue : Long.parseLong(value);
}
+ private int getIntUnchecked(String key, int defaultValue, int userId) {
+ String value = getStringUnchecked(key, null, userId);
+ return TextUtils.isEmpty(value) ? defaultValue : Integer.parseInt(value);
+ }
+
@Override
public String getString(String key, String defaultValue, int userId) {
checkReadPermission(key, userId);
@@ -2171,8 +2207,8 @@ public class LockSettingsService extends ILockSettings.Stub {
}
private void removeUser(int userId, boolean unknownUser) {
+ Slog.i(TAG, "RemoveUser: " + userId);
mSpManager.removeUser(userId);
- mStorage.removeUser(userId);
mStrongAuth.removeUser(userId);
tryRemoveUserFromSpCacheLater(userId);
@@ -2183,6 +2219,9 @@ public class LockSettingsService extends ILockSettings.Stub {
if (unknownUser || mUserManager.getUserInfo(userId).isManagedProfile()) {
removeKeystoreProfileKey(userId);
}
+ // Clean up storage last, this is to ensure that cleanupDataForReusedUserIdIfNecessary()
+ // can make the assumption that no USER_SERIAL_NUMBER_KEY means user is fully removed.
+ mStorage.removeUser(userId);
}
private void removeKeystoreProfileKey(int targetUserId) {
diff --git a/services/core/java/com/android/server/media/MediaRoute2Provider.java b/services/core/java/com/android/server/media/MediaRoute2Provider.java
index 91c9253269a3..9a49c166e2b2 100644
--- a/services/core/java/com/android/server/media/MediaRoute2Provider.java
+++ b/services/core/java/com/android/server/media/MediaRoute2Provider.java
@@ -22,6 +22,7 @@ import android.content.ComponentName;
import android.content.Intent;
import android.media.MediaRoute2Info;
import android.media.MediaRoute2ProviderInfo;
+import android.os.Bundle;
import java.util.Objects;
@@ -29,7 +30,7 @@ abstract class MediaRoute2Provider {
final ComponentName mComponentName;
final String mUniqueId;
- private Callback mCallback;
+ Callback mCallback;
private MediaRoute2ProviderInfo mProviderInfo;
MediaRoute2Provider(@NonNull ComponentName componentName) {
@@ -77,6 +78,9 @@ abstract class MediaRoute2Provider {
}
public interface Callback {
- void onProviderStateChanged(MediaRoute2Provider provider);
+ void onProviderStateChanged(@Nullable MediaRoute2Provider provider);
+ void onRouteSelected(@NonNull MediaRoute2ProviderProxy provider,
+ @NonNull String clientPackageName, @NonNull MediaRoute2Info route,
+ @Nullable Bundle controlHints, int seq);
}
}
diff --git a/services/core/java/com/android/server/media/MediaRoute2ProviderProxy.java b/services/core/java/com/android/server/media/MediaRoute2ProviderProxy.java
index 3b6580ad7357..a5abb1835e7b 100644
--- a/services/core/java/com/android/server/media/MediaRoute2ProviderProxy.java
+++ b/services/core/java/com/android/server/media/MediaRoute2ProviderProxy.java
@@ -26,6 +26,7 @@ import android.media.IMediaRoute2ProviderClient;
import android.media.MediaRoute2Info;
import android.media.MediaRoute2ProviderInfo;
import android.media.MediaRoute2ProviderService;
+import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.IBinder.DeathRecipient;
@@ -253,6 +254,20 @@ final class MediaRoute2ProviderProxy extends MediaRoute2Provider implements Serv
setAndNotifyProviderInfo(info);
}
+ private void onRouteSelected(Connection connection,
+ String packageName, String routeId, Bundle controlHints, int seq) {
+ if (mActiveConnection != connection) {
+ return;
+ }
+ MediaRoute2ProviderInfo providerInfo = getProviderInfo();
+ MediaRoute2Info route = (providerInfo == null) ? null : providerInfo.getRoute(routeId);
+ if (route == null) {
+ Slog.w(TAG, this + ": Unknown route " + routeId + " is selected from remove provider");
+ return;
+ }
+ mCallback.onRouteSelected(this, packageName, route, controlHints, seq);
+ }
+
private void disconnect() {
if (mActiveConnection != null) {
mConnectionReady = false;
@@ -341,6 +356,11 @@ final class MediaRoute2ProviderProxy extends MediaRoute2Provider implements Serv
void postProviderInfoUpdated(MediaRoute2ProviderInfo info) {
mHandler.post(() -> onProviderInfoUpdated(Connection.this, info));
}
+
+ void postRouteSelected(String packageName, String routeId, Bundle controlHints, int seq) {
+ mHandler.post(() -> onRouteSelected(Connection.this,
+ packageName, routeId, controlHints, seq));
+ }
}
private static final class ProviderClient extends IMediaRoute2ProviderClient.Stub {
@@ -361,5 +381,15 @@ final class MediaRoute2ProviderProxy extends MediaRoute2Provider implements Serv
connection.postProviderInfoUpdated(info);
}
}
+
+ @Override
+ public void notifyRouteSelected(String packageName, String routeId,
+ Bundle controlHints, int seq) {
+ Connection connection = mConnectionRef.get();
+ if (connection != null) {
+ connection.postRouteSelected(packageName, routeId, controlHints, seq);
+ }
+ }
+
}
}
diff --git a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
index 2cf920d1aba4..2c478dff4679 100644
--- a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
+++ b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
@@ -77,7 +77,7 @@ class MediaRouter2ServiceImpl {
@GuardedBy("mLock")
private int mCurrentUserId = -1;
@GuardedBy("mLock")
- private int mSelectRouteRequestSequenceNumber = 0;
+ private int mSelectRouteRequestSequenceNumber = 1;
MediaRouter2ServiceImpl(Context context) {
mContext = context;
@@ -218,7 +218,7 @@ class MediaRouter2ServiceImpl {
final long token = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
- requestSelectRoute2Locked(mAllClientRecords.get(client.asBinder()), route);
+ requestSelectRoute2Locked(mAllClientRecords.get(client.asBinder()), false, route);
}
} finally {
Binder.restoreCallingIdentity(token);
@@ -399,10 +399,12 @@ class MediaRouter2ServiceImpl {
}
}
- private void requestSelectRoute2Locked(ClientRecord clientRecord, MediaRoute2Info route) {
+ private void requestSelectRoute2Locked(ClientRecord clientRecord, boolean selectedByManager,
+ MediaRoute2Info route) {
if (clientRecord != null) {
MediaRoute2Info oldRoute = clientRecord.mSelectedRoute;
clientRecord.mSelectingRoute = route;
+ clientRecord.mIsManagerSelecting = selectedByManager;
UserHandler handler = clientRecord.mUserRecord.mHandler;
//TODO: Handle transfer instead of unselect and select
@@ -417,7 +419,6 @@ class MediaRouter2ServiceImpl {
handler.sendMessage(obtainMessage(
UserHandler::requestSelectRoute, handler, clientRecord.mPackageName,
route, seq));
-
// Remove all previous timeout messages
for (int previousSeq : clientRecord.mSelectRouteSequenceNumbers) {
clientRecord.mUserRecord.mHandler.removeMessages(previousSeq);
@@ -543,7 +544,7 @@ class MediaRouter2ServiceImpl {
Slog.w(TAG, "Ignoring route selection for unknown client.");
}
if (clientRecord != null && managerRecord.mTrusted) {
- requestSelectRoute2Locked(clientRecord, route);
+ requestSelectRoute2Locked(clientRecord, true, route);
}
}
}
@@ -656,7 +657,9 @@ class MediaRouter2ServiceImpl {
public final UserRecord mUserRecord;
public final String mPackageName;
public final List<Integer> mSelectRouteSequenceNumbers;
+
public List<String> mControlCategories;
+ public boolean mIsManagerSelecting;
public MediaRoute2Info mSelectingRoute;
public MediaRoute2Info mSelectedRoute;
@@ -802,9 +805,8 @@ class MediaRouter2ServiceImpl {
sendMessage(PooledLambda.obtainMessage(UserHandler::updateProvider, this, provider));
}
- // TODO: When introducing MediaRoute2ProviderService#sendControlHints(),
- // Make this method to be called.
- public void onRouteSelectionRequestHandled(@NonNull MediaRoute2ProviderProxy provider,
+ @Override
+ public void onRouteSelected(@NonNull MediaRoute2ProviderProxy provider,
String clientPackageName, MediaRoute2Info route, Bundle controlHints, int seq) {
sendMessage(PooledLambda.obtainMessage(
UserHandler::updateSelectedRoute, this, provider, clientPackageName, route,
@@ -917,6 +919,8 @@ class MediaRouter2ServiceImpl {
return;
}
+ //TODO: handle a case such that controlHints is null. (How should we notify MR2?)
+
if (clientRecord.mSelectingRoute == null || !TextUtils.equals(
clientRecord.mSelectingRoute.getUniqueId(), selectedRoute.getUniqueId())) {
Log.w(TAG, "Ignoring invalid updateSelectedRoute call. selectingRoute="
@@ -929,7 +933,9 @@ class MediaRouter2ServiceImpl {
notifyRouteSelectedToClient(((Client2Record) clientRecord).mClient,
selectedRoute,
- MediaRouter2.SELECT_REASON_USER_SELECTED,
+ clientRecord.mIsManagerSelecting
+ ? MediaRouter2.SELECT_REASON_SYSTEM_SELECTED :
+ MediaRouter2.SELECT_REASON_USER_SELECTED,
controlHints);
updateClientUsage(clientRecord);
diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java
index 08c94267e969..e473c96980b6 100644
--- a/services/core/java/com/android/server/net/NetworkStatsService.java
+++ b/services/core/java/com/android/server/net/NetworkStatsService.java
@@ -138,7 +138,6 @@ import com.android.internal.util.FileRotator;
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.EventLogTags;
import com.android.server.LocalServices;
-import com.android.server.connectivity.Tethering;
import java.io.File;
import java.io.FileDescriptor;
diff --git a/services/core/java/com/android/server/notification/NotificationHistoryDatabase.java b/services/core/java/com/android/server/notification/NotificationHistoryDatabase.java
index 378ca4a51974..2247e54ac5f7 100644
--- a/services/core/java/com/android/server/notification/NotificationHistoryDatabase.java
+++ b/services/core/java/com/android/server/notification/NotificationHistoryDatabase.java
@@ -183,6 +183,7 @@ public class NotificationHistoryDatabase {
public NotificationHistory readNotificationHistory() {
synchronized (mLock) {
NotificationHistory notifications = new NotificationHistory();
+ notifications.addNotificationsToWrite(mBuffer);
for (AtomicFile file : mHistoryFiles) {
try {
@@ -223,6 +224,13 @@ public class NotificationHistoryDatabase {
}
}
+ public void disableHistory() {
+ synchronized (mLock) {
+ mHistoryDir.delete();
+ mHistoryFiles.clear();
+ }
+ }
+
/**
* Remove any files that are too old and schedule jobs to clean up the rest
*/
@@ -241,6 +249,7 @@ public class NotificationHistoryDatabase {
Slog.d(TAG, "Removed " + currentOldestFile.getBaseFile().getName());
}
currentOldestFile.delete();
+ // TODO: delete all relevant bitmaps, once they exist
mHistoryFiles.removeLast();
} else {
// all remaining files are newer than the cut off; schedule jobs to delete
diff --git a/services/core/java/com/android/server/notification/NotificationHistoryManager.java b/services/core/java/com/android/server/notification/NotificationHistoryManager.java
index a350a6b2acd5..1b56c7bb5b8f 100644
--- a/services/core/java/com/android/server/notification/NotificationHistoryManager.java
+++ b/services/core/java/com/android/server/notification/NotificationHistoryManager.java
@@ -21,9 +21,16 @@ import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.app.NotificationHistory;
import android.app.NotificationHistory.HistoricalNotification;
+import android.content.ContentResolver;
import android.content.Context;
+import android.content.pm.UserInfo;
+import android.database.ContentObserver;
+import android.net.Uri;
import android.os.Environment;
+import android.os.Handler;
+import android.os.UserHandle;
import android.os.UserManager;
+import android.provider.Settings;
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
@@ -49,6 +56,8 @@ public class NotificationHistoryManager {
private final Context mContext;
private final UserManager mUserManager;
+ @VisibleForTesting
+ final SettingsObserver mSettingsObserver;
private final Object mLock = new Object();
@GuardedBy("mLock")
private final SparseArray<NotificationHistoryDatabase> mUserState = new SparseArray<>();
@@ -57,19 +66,26 @@ public class NotificationHistoryManager {
// TODO: does this need to be persisted across reboots?
@GuardedBy("mLock")
private final SparseArray<List<String>> mUserPendingPackageRemovals = new SparseArray<>();
+ @GuardedBy("mLock")
+ private final SparseBooleanArray mHistoryEnabled = new SparseBooleanArray();
- public NotificationHistoryManager(Context context) {
+ public NotificationHistoryManager(Context context, Handler handler) {
mContext = context;
mUserManager = context.getSystemService(UserManager.class);
+ mSettingsObserver = new SettingsObserver(handler);
}
- public void onUserUnlocked(@UserIdInt int userId) {
+ void onBootPhaseAppsCanStart() {
+ mSettingsObserver.observe();
+ }
+
+ void onUserUnlocked(@UserIdInt int userId) {
synchronized (mLock) {
mUserUnlockedStates.put(userId, true);
final NotificationHistoryDatabase userHistory =
getUserHistoryAndInitializeIfNeededLocked(userId);
if (userHistory == null) {
- Slog.i(TAG, "Attempted to unlock stopped or removed user " + userId);
+ Slog.i(TAG, "Attempted to unlock gone/disabled user " + userId);
return;
}
@@ -81,6 +97,11 @@ public class NotificationHistoryManager {
}
mUserPendingPackageRemovals.put(userId, null);
}
+
+ // delete history if it was disabled when the user was locked
+ if (!mHistoryEnabled.get(userId)) {
+ userHistory.disableHistory();
+ }
}
}
@@ -91,22 +112,25 @@ public class NotificationHistoryManager {
}
}
- void onUserRemoved(@UserIdInt int userId) {
+ public void onUserRemoved(@UserIdInt int userId) {
synchronized (mLock) {
// Actual data deletion is handled by other parts of the system (the entire directory is
// removed) - we just need clean up our internal state for GC
mUserPendingPackageRemovals.put(userId, null);
+ mHistoryEnabled.put(userId, false);
onUserStopped(userId);
}
}
- void onPackageRemoved(int userId, String packageName) {
+ public void onPackageRemoved(int userId, String packageName) {
synchronized (mLock) {
if (!mUserUnlockedStates.get(userId, false)) {
- List<String> userPendingRemovals =
- mUserPendingPackageRemovals.get(userId, new ArrayList<>());
- userPendingRemovals.add(packageName);
- mUserPendingPackageRemovals.put(userId, userPendingRemovals);
+ if (mHistoryEnabled.get(userId, false)) {
+ List<String> userPendingRemovals =
+ mUserPendingPackageRemovals.get(userId, new ArrayList<>());
+ userPendingRemovals.add(packageName);
+ mUserPendingPackageRemovals.put(userId, userPendingRemovals);
+ }
return;
}
final NotificationHistoryDatabase userHistory = mUserState.get(userId);
@@ -118,7 +142,8 @@ public class NotificationHistoryManager {
}
}
- void triggerWriteToDisk() {
+ // TODO: wire this up to AMS when power button is long pressed
+ public void triggerWriteToDisk() {
synchronized (mLock) {
final int userCount = mUserState.size();
for (int i = 0; i < userCount; i++) {
@@ -139,7 +164,7 @@ public class NotificationHistoryManager {
final NotificationHistoryDatabase userHistory =
getUserHistoryAndInitializeIfNeededLocked(notification.getUserId());
if (userHistory == null) {
- Slog.w(TAG, "Attempted to add notif for locked/gone user "
+ Slog.w(TAG, "Attempted to add notif for locked/gone/disabled user "
+ notification.getUserId());
return;
}
@@ -157,7 +182,7 @@ public class NotificationHistoryManager {
final NotificationHistoryDatabase userHistory =
getUserHistoryAndInitializeIfNeededLocked(userId);
if (userHistory == null) {
- Slog.i(TAG, "Attempted to read history for locked/gone user " +userId);
+ Slog.i(TAG, "Attempted to read history for locked/gone/disabled user " +userId);
continue;
}
mergedHistory.addNotificationsToWrite(userHistory.readNotificationHistory());
@@ -172,7 +197,7 @@ public class NotificationHistoryManager {
final NotificationHistoryDatabase userHistory =
getUserHistoryAndInitializeIfNeededLocked(userId);
if (userHistory == null) {
- Slog.i(TAG, "Attempted to read history for locked/gone user " +userId);
+ Slog.i(TAG, "Attempted to read history for locked/gone/disabled user " +userId);
return new android.app.NotificationHistory();
}
@@ -180,9 +205,38 @@ public class NotificationHistoryManager {
}
}
+ boolean isHistoryEnabled(@UserIdInt int userId) {
+ synchronized (mLock) {
+ return mHistoryEnabled.get(userId);
+ }
+ }
+
+ void onHistoryEnabledChanged(@UserIdInt int userId, boolean historyEnabled) {
+ synchronized (mLock) {
+ mHistoryEnabled.put(userId, historyEnabled);
+
+ // These requests might fail if the user is locked; onUserUnlocked will pick up those
+ // cases
+ final NotificationHistoryDatabase userHistory =
+ getUserHistoryAndInitializeIfNeededLocked(userId);
+ if (userHistory != null) {
+ if (!historyEnabled) {
+ userHistory.disableHistory();
+ }
+ }
+ }
+ }
+
@GuardedBy("mLock")
private @Nullable NotificationHistoryDatabase getUserHistoryAndInitializeIfNeededLocked(
int userId) {
+ if (!mHistoryEnabled.get(userId)) {
+ if (DEBUG) {
+ Slog.i(TAG, "History disabled for user " + userId);
+ }
+ mUserState.put(userId, null);
+ return null;
+ }
NotificationHistoryDatabase userHistory = mUserState.get(userId);
if (userHistory == null) {
final File historyDir = new File(Environment.getDataSystemCeDirectory(userId),
@@ -242,4 +296,39 @@ public class NotificationHistoryManager {
return mUserPendingPackageRemovals.get(userId);
}
}
+
+ final class SettingsObserver extends ContentObserver {
+ private final Uri NOTIFICATION_HISTORY_URI
+ = Settings.Secure.getUriFor(Settings.Secure.NOTIFICATION_HISTORY_ENABLED);
+
+ SettingsObserver(Handler handler) {
+ super(handler);
+ }
+
+ void observe() {
+ ContentResolver resolver = mContext.getContentResolver();
+ resolver.registerContentObserver(NOTIFICATION_HISTORY_URI,
+ false, this, UserHandle.USER_ALL);
+ synchronized (mLock) {
+ for (UserInfo userInfo : mUserManager.getUsers()) {
+ update(null, userInfo.id);
+ }
+ }
+ }
+
+ @Override
+ public void onChange(boolean selfChange, Uri uri, int userId) {
+ update(uri, userId);
+ }
+
+ public void update(Uri uri, int userId) {
+ ContentResolver resolver = mContext.getContentResolver();
+ if (uri == null || NOTIFICATION_HISTORY_URI.equals(uri)) {
+ boolean historyEnabled = Settings.Secure.getIntForUser(resolver,
+ Settings.Secure.NOTIFICATION_HISTORY_ENABLED, 0, userId)
+ != 0;
+ onHistoryEnabledChanged(userId, historyEnabled);
+ }
+ }
+ }
}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index d5f2d7e550d7..863991cec3bd 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -103,6 +103,8 @@ import android.Manifest.permission;
import android.annotation.CallbackExecutor;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
+import android.annotation.WorkerThread;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
import android.app.AlarmManager;
@@ -116,6 +118,8 @@ import android.app.IUriGrantsManager;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationChannelGroup;
+import android.app.NotificationHistory;
+import android.app.NotificationHistory.HistoricalNotification;
import android.app.NotificationManager;
import android.app.NotificationManager.Policy;
import android.app.PendingIntent;
@@ -160,6 +164,7 @@ import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
+import android.os.HandlerExecutor;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.IDeviceIdleController;
@@ -477,12 +482,14 @@ public class NotificationManagerService extends SystemService {
private long mLastOverRateLogTime;
private float mMaxPackageEnqueueRate = DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE;
+ private NotificationHistoryManager mHistoryManager;
private SnoozeHelper mSnoozeHelper;
private GroupHelper mGroupHelper;
private int mAutoGroupAtCount;
private boolean mIsTelevision;
private boolean mIsAutomotive;
private boolean mNotificationEffectsEnabledForAutomotive;
+ private DeviceConfig.OnPropertiesChangedListener mDeviceConfigChangedListener;
private int mWarnRemoteViewsSizeBytes;
private int mStripRemoteViewsSizeBytes;
@@ -1547,6 +1554,7 @@ public class NotificationManagerService extends SystemService {
mListeners.onUserRemoved(userId);
mConditionProviders.onUserRemoved(userId);
mAssistants.onUserRemoved(userId);
+ mHistoryManager.onUserRemoved(userId);
handleSavePolicyFile();
} else if (action.equals(Intent.ACTION_USER_UNLOCKED)) {
final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
@@ -1775,8 +1783,8 @@ public class NotificationManagerService extends SystemService {
// TODO: All tests should use this init instead of the one-off setters above.
@VisibleForTesting
- void init(Looper looper, RankingHandler rankingHandler, IPackageManager packageManager,
- PackageManager packageManagerClient,
+ void init(WorkerHandler handler, RankingHandler rankingHandler,
+ IPackageManager packageManager, PackageManager packageManagerClient,
LightsManager lightsManager, NotificationListeners notificationListeners,
NotificationAssistants notificationAssistants, ConditionProviders conditionProviders,
ICompanionDeviceManager companionManager, SnoozeHelper snoozeHelper,
@@ -1784,7 +1792,8 @@ public class NotificationManagerService extends SystemService {
ActivityManager activityManager, GroupHelper groupHelper, IActivityManager am,
UsageStatsManagerInternal appUsageStats, DevicePolicyManagerInternal dpm,
IUriGrantsManager ugm, UriGrantsManagerInternal ugmInternal, AppOpsManager appOps,
- UserManager userManager) {
+ UserManager userManager, NotificationHistoryManager historyManager) {
+ mHandler = handler;
Resources resources = getContext().getResources();
mMaxPackageEnqueueRate = Settings.Global.getFloat(getContext().getContentResolver(),
Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE,
@@ -1810,7 +1819,6 @@ public class NotificationManagerService extends SystemService {
mPlatformCompat = IPlatformCompat.Stub.asInterface(
ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE));
- mHandler = new WorkerHandler(looper);
mUiHandler = new Handler(UiThread.get().getLooper());
String[] extractorNames;
try {
@@ -1869,6 +1877,7 @@ public class NotificationManagerService extends SystemService {
extractorNames);
mSnoozeHelper = snoozeHelper;
mGroupHelper = groupHelper;
+ mHistoryManager = historyManager;
// This is a ManagedServices object that keeps track of the listeners.
mListeners = notificationListeners;
@@ -1966,7 +1975,9 @@ public class NotificationManagerService extends SystemService {
final File systemDir = new File(Environment.getDataDirectory(), "system");
mRankingThread.start();
- init(Looper.myLooper(), new RankingHandlerWorker(mRankingThread.getLooper()),
+ WorkerHandler handler = new WorkerHandler(Looper.myLooper());
+
+ init(handler, new RankingHandlerWorker(mRankingThread.getLooper()),
AppGlobals.getPackageManager(), getContext().getPackageManager(),
getLocalService(LightsManager.class),
new NotificationListeners(AppGlobals.getPackageManager()),
@@ -1983,7 +1994,8 @@ public class NotificationManagerService extends SystemService {
UriGrantsManager.getService(),
LocalServices.getService(UriGrantsManagerInternal.class),
(AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE),
- getContext().getSystemService(UserManager.class));
+ getContext().getSystemService(UserManager.class),
+ new NotificationHistoryManager(getContext(), handler));
// register for various Intents
IntentFilter filter = new IntentFilter();
@@ -2036,19 +2048,26 @@ public class NotificationManagerService extends SystemService {
}
private void registerDeviceConfigChange() {
+ mDeviceConfigChangedListener = properties -> {
+ if (!DeviceConfig.NAMESPACE_SYSTEMUI.equals(properties.getNamespace())) {
+ return;
+ }
+ if (properties.getKeyset()
+ .contains(SystemUiDeviceConfigFlags.NAS_DEFAULT_SERVICE)) {
+ mAssistants.allowAdjustmentType(Adjustment.KEY_IMPORTANCE);
+ mAssistants.resetDefaultAssistantsIfNecessary();
+ }
+ };
DeviceConfig.addOnPropertiesChangedListener(
DeviceConfig.NAMESPACE_SYSTEMUI,
- getContext().getMainExecutor(),
- (properties) -> {
- if (!DeviceConfig.NAMESPACE_SYSTEMUI.equals(properties.getNamespace())) {
- return;
- }
- if (properties.getKeyset()
- .contains(SystemUiDeviceConfigFlags.NAS_DEFAULT_SERVICE)) {
- mAssistants.allowAdjustmentType(Adjustment.KEY_IMPORTANCE);
- mAssistants.resetDefaultAssistantsIfNecessary();
- }
- });
+ new HandlerExecutor(mHandler),
+ mDeviceConfigChangedListener);
+ }
+
+ void unregisterDeviceConfigChange() {
+ if (mDeviceConfigChangedListener != null) {
+ DeviceConfig.removeOnPropertiesChangedListener(mDeviceConfigChangedListener);
+ }
}
private GroupHelper getGroupHelper() {
@@ -2134,10 +2153,21 @@ public class NotificationManagerService extends SystemService {
mListeners.onBootPhaseAppsCanStart();
mAssistants.onBootPhaseAppsCanStart();
mConditionProviders.onBootPhaseAppsCanStart();
+ mHistoryManager.onBootPhaseAppsCanStart();
registerDeviceConfigChange();
}
}
+ @Override
+ public void onUnlockUser(@NonNull UserInfo userInfo) {
+ mHandler.post(() -> mHistoryManager.onUserUnlocked(userInfo.id));
+ }
+
+ @Override
+ public void onStopUser(@NonNull UserInfo userInfo) {
+ mHandler.post(() -> mHistoryManager.onUserStopped(userInfo.id));
+ }
+
@GuardedBy("mNotificationLock")
private void updateListenerHintsLocked() {
final int hints = calculateHints();
@@ -2449,10 +2479,56 @@ public class NotificationManagerService extends SystemService {
mAppUsageStats.reportInterruptiveNotification(r.sbn.getPackageName(),
r.getChannel().getId(),
getRealUserId(r.sbn.getUserId()));
+ mHistoryManager.addNotification(new HistoricalNotification.Builder()
+ .setPackage(r.sbn.getPackageName())
+ .setUid(r.sbn.getUid())
+ .setChannelId(r.getChannel().getId())
+ .setChannelName(r.getChannel().getName().toString())
+ .setPostedTimeMs(r.sbn.getPostTime())
+ .setTitle(getHistoryTitle(r.getNotification()))
+ .setText(getHistoryText(
+ r.sbn.getPackageContext(getContext()), r.getNotification()))
+ .setIcon(r.getNotification().getSmallIcon())
+ .build());
r.setRecordedInterruption(true);
}
}
+ private String getHistoryTitle(Notification n) {
+ CharSequence title = null;
+ if (n.extras != null) {
+ title = n.extras.getCharSequence(Notification.EXTRA_TITLE);
+ }
+ return title == null? null : String.valueOf(title);
+ }
+
+ /**
+ * Returns the appropriate substring for this notification based on the style of notification.
+ */
+ private String getHistoryText(Context appContext, Notification n) {
+ CharSequence text = null;
+ if (n.extras != null) {
+ text = n.extras.getCharSequence(Notification.EXTRA_TEXT);
+
+ Notification.Builder nb = Notification.Builder.recoverBuilder(appContext, n);
+
+ if (nb.getStyle() instanceof Notification.BigTextStyle) {
+ text = ((Notification.BigTextStyle) nb.getStyle()).getBigText();
+ } else if (nb.getStyle() instanceof Notification.MessagingStyle) {
+ Notification.MessagingStyle ms = (Notification.MessagingStyle) nb.getStyle();
+ final List<Notification.MessagingStyle.Message> messages = ms.getMessages();
+ if (messages != null && messages.size() > 0) {
+ text = messages.get(messages.size() - 1).getText();
+ }
+ }
+
+ if (TextUtils.isEmpty(text)) {
+ text = n.extras.getCharSequence(Notification.EXTRA_TEXT);
+ }
+ }
+ return text == null ? null : String.valueOf(text);
+ }
+
/**
* Report to usage stats that the user interacted with the notification.
* @param r notification record
@@ -3343,10 +3419,9 @@ public class NotificationManagerService extends SystemService {
/**
* System-only API for getting a list of recent (cleared, no longer shown) notifications.
- *
- * Requires ACCESS_NOTIFICATIONS which is signature|system.
*/
@Override
+ @RequiresPermission(android.Manifest.permission.ACCESS_NOTIFICATIONS)
public StatusBarNotification[] getHistoricalNotifications(String callingPkg, int count) {
// enforce() will ensure the calling uid has the correct permission
getContext().enforceCallingOrSelfPermission(
@@ -3367,6 +3442,29 @@ public class NotificationManagerService extends SystemService {
}
/**
+ * System-only API for getting a list of historical notifications. May contain multiple days
+ * of notifications.
+ */
+ @Override
+ @WorkerThread
+ @RequiresPermission(android.Manifest.permission.ACCESS_NOTIFICATIONS)
+ public NotificationHistory getNotificationHistory(String callingPkg) {
+ // enforce() will ensure the calling uid has the correct permission
+ getContext().enforceCallingOrSelfPermission(
+ android.Manifest.permission.ACCESS_NOTIFICATIONS,
+ "NotificationManagerService.getNotificationHistory");
+ int uid = Binder.getCallingUid();
+
+ // noteOp will check to make sure the callingPkg matches the uid
+ if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg)
+ == AppOpsManager.MODE_ALLOWED) {
+ IntArray currentUserIds = mUserProfiles.getCurrentProfileIds();
+ return mHistoryManager.readNotificationHistory(currentUserIds.toArray());
+ }
+ return new NotificationHistory();
+ }
+
+ /**
* Register a listener binder directly with the notification manager.
*
* Only works with system callers. Apps should extend
@@ -6831,7 +6929,7 @@ public class NotificationManagerService extends SystemService {
}
}
- private void handleOnPackageChanged(boolean removingPackage, int changeUserId,
+ void handleOnPackageChanged(boolean removingPackage, int changeUserId,
String[] pkgList, int[] uidList) {
boolean preferencesChanged = removingPackage;
mListeners.onPackagesChanged(removingPackage, pkgList, uidList);
@@ -6839,6 +6937,14 @@ public class NotificationManagerService extends SystemService {
mConditionProviders.onPackagesChanged(removingPackage, pkgList, uidList);
preferencesChanged |= mPreferencesHelper.onPackagesChanged(
removingPackage, changeUserId, pkgList, uidList);
+ if (removingPackage) {
+ int size = Math.min(pkgList.length, uidList.length);
+ for (int i = 0; i < size; i++) {
+ final String pkg = pkgList[i];
+ final int uid = uidList[i];
+ mHistoryManager.onPackageRemoved(UserHandle.getUserId(uid), pkg);
+ }
+ }
if (preferencesChanged) {
handleSavePolicyFile();
}
diff --git a/services/core/java/com/android/server/notification/SnoozeHelper.java b/services/core/java/com/android/server/notification/SnoozeHelper.java
index 8125d0d653ad..9e32d0e81a47 100644
--- a/services/core/java/com/android/server/notification/SnoozeHelper.java
+++ b/services/core/java/com/android/server/notification/SnoozeHelper.java
@@ -374,9 +374,6 @@ public class SnoozeHelper {
return;
}
NotificationRecord existing = pkgRecords.get(record.getKey());
- if (existing != null && existing.isCanceled) {
- return;
- }
pkgRecords.put(record.getKey(), record);
}
diff --git a/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java b/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java
index 259200b92597..7e478009b6b3 100644
--- a/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java
+++ b/services/core/java/com/android/server/pm/PackageAbiHelperImpl.java
@@ -19,6 +19,7 @@ package com.android.server.pm;
import static android.content.pm.PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
import static android.content.pm.PackageParser.isApkFile;
import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
+import static android.os.incremental.IncrementalManager.isIncrementalPath;
import static com.android.internal.content.NativeLibraryHelper.LIB64_DIR_NAME;
import static com.android.internal.content.NativeLibraryHelper.LIB_DIR_NAME;
@@ -309,6 +310,7 @@ final class PackageAbiHelperImpl implements PackageAbiHelper {
final String nativeLibraryRootStr = initialLibraryPaths.nativeLibraryRootDir;
final boolean useIsaSpecificSubdirs = initialLibraryPaths.nativeLibraryRootRequiresIsa;
+ final boolean onIncremental = isIncrementalPath(pkg.codePath);
String primaryCpuAbi = null;
String secondaryCpuAbi = null;
@@ -341,10 +343,18 @@ final class PackageAbiHelperImpl implements PackageAbiHelper {
int abi64 = PackageManager.NO_NATIVE_LIBRARIES;
if (Build.SUPPORTED_32_BIT_ABIS.length > 0) {
if (extractLibs) {
- Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyNativeBinaries");
- abi32 = NativeLibraryHelper.copyNativeBinariesForSupportedAbi(handle,
- nativeLibraryRoot, Build.SUPPORTED_32_BIT_ABIS,
- useIsaSpecificSubdirs);
+ if (onIncremental) {
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER,
+ "incrementalNativeBinaries");
+ abi32 = NativeLibraryHelper.configureNativeBinariesForSupportedAbi(pkg,
+ handle, nativeLibraryRoot, Build.SUPPORTED_32_BIT_ABIS,
+ useIsaSpecificSubdirs);
+ } else {
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyNativeBinaries");
+ abi32 = NativeLibraryHelper.copyNativeBinariesForSupportedAbi(handle,
+ nativeLibraryRoot, Build.SUPPORTED_32_BIT_ABIS,
+ useIsaSpecificSubdirs);
+ }
} else {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "findSupportedAbi");
abi32 = NativeLibraryHelper.findSupportedAbi(
@@ -364,10 +374,18 @@ final class PackageAbiHelperImpl implements PackageAbiHelper {
if (Build.SUPPORTED_64_BIT_ABIS.length > 0) {
if (extractLibs) {
- Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyNativeBinaries");
- abi64 = NativeLibraryHelper.copyNativeBinariesForSupportedAbi(handle,
- nativeLibraryRoot, Build.SUPPORTED_64_BIT_ABIS,
- useIsaSpecificSubdirs);
+ if (onIncremental) {
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER,
+ "incrementalNativeBinaries");
+ abi64 = NativeLibraryHelper.configureNativeBinariesForSupportedAbi(pkg,
+ handle, nativeLibraryRoot, Build.SUPPORTED_64_BIT_ABIS,
+ useIsaSpecificSubdirs);
+ } else {
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyNativeBinaries");
+ abi64 = NativeLibraryHelper.copyNativeBinariesForSupportedAbi(handle,
+ nativeLibraryRoot, Build.SUPPORTED_64_BIT_ABIS,
+ useIsaSpecificSubdirs);
+ }
} else {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "findSupportedAbi");
abi64 = NativeLibraryHelper.findSupportedAbi(
@@ -418,9 +436,15 @@ final class PackageAbiHelperImpl implements PackageAbiHelper {
final int copyRet;
if (extractLibs) {
- Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyNativeBinaries");
- copyRet = NativeLibraryHelper.copyNativeBinariesForSupportedAbi(handle,
- nativeLibraryRoot, abiList, useIsaSpecificSubdirs);
+ if (onIncremental) {
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "incrementalNativeBinaries");
+ copyRet = NativeLibraryHelper.configureNativeBinariesForSupportedAbi(pkg,
+ handle, nativeLibraryRoot, abiList, useIsaSpecificSubdirs);
+ } else {
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyNativeBinaries");
+ copyRet = NativeLibraryHelper.copyNativeBinariesForSupportedAbi(handle,
+ nativeLibraryRoot, abiList, useIsaSpecificSubdirs);
+ }
} else {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "findSupportedAbi");
copyRet = NativeLibraryHelper.findSupportedAbi(handle, abiList);
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index a09657be83d4..d63e7041ea52 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -959,9 +959,13 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
assertPreparedAndNotDestroyedLocked("commit");
assertNoWriteFileTransfersOpenLocked();
- if (forTransfer) {
+ final boolean enforceInstallPackages = forTransfer
+ || (android.provider.Settings.Secure.getInt(mContext.getContentResolver(),
+ android.provider.Settings.Secure.SECURE_FRP_MODE, 0) == 1);
+ if (enforceInstallPackages) {
mContext.enforceCallingOrSelfPermission(Manifest.permission.INSTALL_PACKAGES, null);
-
+ }
+ if (forTransfer) {
if (mInstallerUid == mOriginalInstallerUid) {
throw new IllegalArgumentException("Session has not been transferred");
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index eebc8d7db81f..8439a0de3a06 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -87,6 +87,7 @@ import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.content.pm.PackageManager.RESTRICTION_NONE;
import static android.content.pm.PackageParser.isApkFile;
import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
+import static android.os.incremental.IncrementalManager.isIncrementalPath;
import static android.os.storage.StorageManager.FLAG_STORAGE_CE;
import static android.os.storage.StorageManager.FLAG_STORAGE_DE;
import static android.os.storage.StorageManager.FLAG_STORAGE_EXTERNAL;
@@ -226,6 +227,7 @@ import android.os.Trace;
import android.os.UserHandle;
import android.os.UserManager;
import android.os.UserManagerInternal;
+import android.os.incremental.IncrementalManager;
import android.os.storage.DiskInfo;
import android.os.storage.IStorageManager;
import android.os.storage.StorageEventListener;
@@ -1074,6 +1076,8 @@ public class PackageManagerService extends IPackageManager.Stub
private Future<?> mPrepareAppDataFuture;
+ private final IncrementalManager mIncrementalManager;
+
private static class IFVerificationParams {
PackageParser.Package pkg;
boolean replacing;
@@ -1492,7 +1496,6 @@ public class PackageManagerService extends IPackageManager.Stub
final @Nullable String mAppPredictionServicePackage;
final @Nullable String mIncidentReportApproverPackage;
final @Nullable String[] mTelephonyPackages;
- final @Nullable String mWifiPackage;
final @NonNull String mServicesSystemSharedLibraryPackageName;
final @NonNull String mSharedSystemSharedLibraryPackageName;
@@ -2510,6 +2513,8 @@ public class PackageManagerService extends IPackageManager.Stub
mPermissionManager = injector.getPermissionManagerServiceInternal();
mSettings = injector.getSettings();
mPermissionManagerService = (IPermissionManager) ServiceManager.getService("permissionmgr");
+ mIncrementalManager =
+ (IncrementalManager) mContext.getSystemService(Context.INCREMENTAL_SERVICE);
// CHECKSTYLE:ON IndentationCheck
t.traceEnd();
@@ -2974,7 +2979,6 @@ public class PackageManagerService extends IPackageManager.Stub
mAppPredictionServicePackage = getAppPredictionServicePackageName();
mIncidentReportApproverPackage = getIncidentReportApproverPackageName();
mTelephonyPackages = getTelephonyPackageNames();
- mWifiPackage = mContext.getString(R.string.config_wifiPackage);
// Now that we know all of the shared libraries, update all clients to have
// the correct library paths.
@@ -8800,6 +8804,7 @@ public class PackageManagerService extends IPackageManager.Stub
// Full APK verification can be skipped during certificate collection, only if the file is
// in verified partition, or can be verified on access (when apk verity is enabled). In both
// cases, only data in Signing Block is verified instead of the whole file.
+ // TODO(b/136132412): skip for Incremental installation
final boolean skipVerify = scanSystemPartition
|| (forceCollect && canSkipForcedPackageVerification(pkg));
collectCertificatesLI(pkgSetting, pkg, forceCollect, skipVerify);
@@ -14677,9 +14682,16 @@ public class PackageManagerService extends IPackageManager.Stub
final File afterCodeFile = getNextCodePath(targetDir, pkg.packageName);
if (DEBUG_INSTALL) Slog.d(TAG, "Renaming " + beforeCodeFile + " to " + afterCodeFile);
+ final boolean onIncremental = mIncrementalManager != null
+ && isIncrementalPath(beforeCodeFile.getAbsolutePath());
try {
- Os.rename(beforeCodeFile.getAbsolutePath(), afterCodeFile.getAbsolutePath());
- } catch (ErrnoException e) {
+ if (onIncremental) {
+ mIncrementalManager.rename(beforeCodeFile.getAbsolutePath(),
+ afterCodeFile.getAbsolutePath());
+ } else {
+ Os.rename(beforeCodeFile.getAbsolutePath(), afterCodeFile.getAbsolutePath());
+ }
+ } catch (IOException | ErrnoException e) {
Slog.w(TAG, "Failed to rename", e);
return false;
}
@@ -14739,6 +14751,11 @@ public class PackageManagerService extends IPackageManager.Stub
return false;
}
+ String codePath = codeFile.getAbsolutePath();
+ if (mIncrementalManager != null && isIncrementalPath(codePath)) {
+ mIncrementalManager.closeStorage(codePath);
+ }
+
removeCodePathLI(codeFile);
if (resourceFile != null && !FileUtils.contains(codeFile, resourceFile)) {
@@ -15930,6 +15947,8 @@ public class PackageManagerService extends IPackageManager.Stub
& PackageManagerService.SCAN_AS_INSTANT_APP) != 0);
final PackageParser.Package pkg = reconciledPkg.pkgSetting.pkg;
final String packageName = pkg.packageName;
+ final boolean onIncremental = mIncrementalManager != null
+ && isIncrementalPath(pkg.codePath);
prepareAppDataAfterInstallLIF(pkg);
if (reconciledPkg.prepareResult.clearCodeCache) {
clearAppDataLIF(pkg, UserHandle.USER_ALL, FLAG_STORAGE_DE | FLAG_STORAGE_CE
@@ -15960,6 +15979,7 @@ public class PackageManagerService extends IPackageManager.Stub
// We only need to dexopt if the package meets ALL of the following conditions:
// 1) it is not an instant app or if it is then dexopt is enabled via gservices.
// 2) it is not debuggable.
+ // 3) it is not on Incremental File System.
//
// Note that we do not dexopt instant apps by default. dexopt can take some time to
// complete, so we skip this step during installation. Instead, we'll take extra time
@@ -15970,7 +15990,8 @@ public class PackageManagerService extends IPackageManager.Stub
final boolean performDexopt =
(!instantApp || Global.getInt(mContext.getContentResolver(),
Global.INSTANT_APP_DEXOPT_ENABLED, 0) != 0)
- && ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) == 0);
+ && ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) == 0)
+ && (!onIncremental);
if (performDexopt) {
// Compile the layout resources.
@@ -16202,6 +16223,7 @@ public class PackageManagerService extends IPackageManager.Stub
if (args.signingDetails != PackageParser.SigningDetails.UNKNOWN) {
pkg.setSigningDetails(args.signingDetails);
} else {
+ // TODO(b/136132412): skip for Incremental installation
PackageParser.collectCertificates(pkg, false /* skipVerify */);
}
} catch (PackageParserException e) {
@@ -22938,8 +22960,6 @@ public class PackageManagerService extends IPackageManager.Stub
return filterOnlySystemPackages(mAppPredictionServicePackage);
case PackageManagerInternal.PACKAGE_TELEPHONY:
return filterOnlySystemPackages(mTelephonyPackages);
- case PackageManagerInternal.PACKAGE_WIFI:
- return filterOnlySystemPackages(mWifiPackage);
default:
return ArrayUtils.emptyArray(String.class);
}
@@ -23527,7 +23547,7 @@ public class PackageManagerService extends IPackageManager.Stub
@Override
public void uninstallApex(String packageName, long versionCode, int userId,
- IntentSender intentSender) {
+ IntentSender intentSender, int flags) {
final int callerUid = Binder.getCallingUid();
if (callerUid != Process.ROOT_UID && callerUid != Process.SHELL_UID) {
throw new SecurityException("Not allowed to uninstall apexes");
@@ -23536,7 +23556,7 @@ public class PackageManagerService extends IPackageManager.Stub
new PackageInstallerService.PackageDeleteObserverAdapter(
PackageManagerService.this.mContext, intentSender, packageName,
false, userId);
- if (userId != UserHandle.USER_ALL) {
+ if ((flags & PackageManager.DELETE_ALL_USERS) == 0) {
adapter.onPackageDeleted(packageName, PackageManager.DELETE_FAILED_ABORTED,
"Can't uninstall an apex for a single user");
return;
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 232374c6773e..9afc9a87d629 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -504,11 +504,9 @@ class PackageManagerShellCommand extends ShellCommand {
getErrPrintWriter().println("Error: no package specified");
return 1;
}
- userId = translateUserId(userId, true /*allowAll*/, "runPath");
- if (userId == UserHandle.USER_ALL) {
- userId = UserHandle.USER_SYSTEM;
- }
- return displayPackageFilePath(pkg, userId);
+ final int translatedUserId =
+ translateUserId(userId, UserHandle.USER_NULL, "runPath");
+ return displayPackageFilePath(pkg, translatedUserId);
}
private int runList() throws RemoteException {
@@ -730,13 +728,14 @@ class PackageManagerShellCommand extends ShellCommand {
final String filter = getNextArg();
- userId = translateUserId(userId, true /*allowAll*/, "runListPackages");
if (userId == UserHandle.USER_ALL) {
- userId = UserHandle.USER_SYSTEM;
+ getFlags |= PackageManager.MATCH_KNOWN_PACKAGES;
}
+ final int translatedUserId =
+ translateUserId(userId, UserHandle.USER_SYSTEM, "runListPackages");
@SuppressWarnings("unchecked")
final ParceledListSlice<PackageInfo> slice =
- mInterface.getInstalledPackages(getFlags, userId);
+ mInterface.getInstalledPackages(getFlags, translatedUserId);
final List<PackageInfo> packages = slice.getList();
final int count = packages.size();
@@ -900,29 +899,29 @@ class PackageManagerShellCommand extends ShellCommand {
}
private int runListStagedSessions() {
- final IndentingPrintWriter pw = new IndentingPrintWriter(
- getOutPrintWriter(), /* singleIndent */ " ", /* wrapLength */ 120);
+ try (IndentingPrintWriter pw = new IndentingPrintWriter(
+ getOutPrintWriter(), /* singleIndent */ " ", /* wrapLength */ 120)) {
+ final SessionDump sessionDump = new SessionDump();
+ String opt;
+ while ((opt = getNextOption()) != null) {
+ if (!setSessionFlag(opt, sessionDump)) {
+ pw.println("Error: Unknown option: " + opt);
+ return -1;
+ }
+ }
- SessionDump sessionDump = new SessionDump();
- String opt;
- while ((opt = getNextOption()) != null) {
- if (!setSessionFlag(opt, sessionDump)) {
- pw.println("Error: Unknown option: " + opt);
+ try {
+ final List<SessionInfo> stagedSessions =
+ mInterface.getPackageInstaller().getStagedSessions().getList();
+ printSessionList(pw, stagedSessions, sessionDump);
+ } catch (RemoteException e) {
+ pw.println("Failure ["
+ + e.getClass().getName() + " - "
+ + e.getMessage() + "]");
return -1;
}
+ return 1;
}
-
- try {
- List<SessionInfo> stagedSessions =
- mInterface.getPackageInstaller().getStagedSessions().getList();
- printSessionList(pw, stagedSessions, sessionDump);
- } catch (RemoteException e) {
- pw.println("Failure ["
- + e.getClass().getName() + " - "
- + e.getMessage() + "]");
- return -1;
- }
- return 1;
}
private void printSessionList(IndentingPrintWriter pw, List<SessionInfo> stagedSessions,
@@ -1357,19 +1356,17 @@ class PackageManagerShellCommand extends ShellCommand {
pw.println("Error: package name not specified");
return 1;
}
- userId = translateUserId(userId, true /*allowAll*/, "runInstallExisting");
- if (userId == UserHandle.USER_ALL) {
- userId = UserHandle.USER_SYSTEM;
- }
+ final int translatedUserId =
+ translateUserId(userId, UserHandle.USER_NULL, "runInstallExisting");
int installReason = PackageManager.INSTALL_REASON_UNKNOWN;
try {
if (waitTillComplete) {
final LocalIntentReceiver receiver = new LocalIntentReceiver();
final IPackageInstaller installer = mInterface.getPackageInstaller();
- pw.println("Installing package " + packageName + " for user: " + userId);
+ pw.println("Installing package " + packageName + " for user: " + translatedUserId);
installer.installExistingPackage(packageName, installFlags, installReason,
- receiver.getIntentSender(), userId, null);
+ receiver.getIntentSender(), translatedUserId, null);
final Intent result = receiver.getResult();
final int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,
PackageInstaller.STATUS_FAILURE);
@@ -1377,12 +1374,12 @@ class PackageManagerShellCommand extends ShellCommand {
return status == PackageInstaller.STATUS_SUCCESS ? 0 : 1;
}
- final int res = mInterface.installExistingPackageAsUser(packageName, userId,
+ final int res = mInterface.installExistingPackageAsUser(packageName, translatedUserId,
installFlags, installReason, null);
if (res == PackageManager.INSTALL_FAILED_INVALID_URI) {
throw new NameNotFoundException("Package " + packageName + " doesn't exist");
}
- pw.println("Package " + packageName + " installed for user: " + userId);
+ pw.println("Package " + packageName + " installed for user: " + translatedUserId);
return 0;
} catch (RemoteException | NameNotFoundException e) {
pw.println(e.toString());
@@ -1845,36 +1842,37 @@ class PackageManagerShellCommand extends ShellCommand {
return runRemoveSplits(packageName, splitNames);
}
- userId = translateUserId(userId, true /*allowAll*/, "runUninstall");
+ if (userId == UserHandle.USER_ALL) {
+ flags |= PackageManager.DELETE_ALL_USERS;
+ }
+ final int translatedUserId =
+ translateUserId(userId, UserHandle.USER_SYSTEM, "runUninstall");
final LocalIntentReceiver receiver = new LocalIntentReceiver();
- PackageManagerInternal internal = LocalServices.getService(PackageManagerInternal.class);
+ final PackageManagerInternal internal =
+ LocalServices.getService(PackageManagerInternal.class);
if (internal.isApexPackage(packageName)) {
- internal.uninstallApex(packageName, versionCode, userId, receiver.getIntentSender());
- } else {
- if (userId == UserHandle.USER_ALL) {
- userId = UserHandle.USER_SYSTEM;
- flags |= PackageManager.DELETE_ALL_USERS;
- } else {
- final PackageInfo info = mInterface.getPackageInfo(packageName,
- PackageManager.MATCH_STATIC_SHARED_LIBRARIES, userId);
- if (info == null) {
- pw.println("Failure [not installed for " + userId + "]");
- return 1;
- }
- final boolean isSystem =
- (info.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
- // If we are being asked to delete a system app for just one
- // user set flag so it disables rather than reverting to system
- // version of the app.
- if (isSystem) {
- flags |= PackageManager.DELETE_SYSTEM_APP;
- }
+ internal.uninstallApex(
+ packageName, versionCode, translatedUserId, receiver.getIntentSender(), flags);
+ } else if ((flags & PackageManager.DELETE_ALL_USERS) != 0) {
+ final PackageInfo info = mInterface.getPackageInfo(packageName,
+ PackageManager.MATCH_STATIC_SHARED_LIBRARIES, translatedUserId);
+ if (info == null) {
+ pw.println("Failure [not installed for " + translatedUserId + "]");
+ return 1;
+ }
+ final boolean isSystem =
+ (info.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
+ // If we are being asked to delete a system app for just one
+ // user set flag so it disables rather than reverting to system
+ // version of the app.
+ if (isSystem) {
+ flags |= PackageManager.DELETE_SYSTEM_APP;
}
mInterface.getPackageInstaller().uninstall(new VersionedPackage(packageName,
versionCode), null /*callerPackageName*/, flags,
- receiver.getIntentSender(), userId);
+ receiver.getIntentSender(), translatedUserId);
}
final Intent result = receiver.getResult();
@@ -1948,8 +1946,10 @@ class PackageManagerShellCommand extends ShellCommand {
return 1;
}
- ClearDataObserver obs = new ClearDataObserver();
- ActivityManager.getService().clearApplicationUserData(pkg, false, obs, userId);
+ final int translatedUserId =
+ translateUserId(userId, UserHandle.USER_NULL, "runClear");
+ final ClearDataObserver obs = new ClearDataObserver();
+ ActivityManager.getService().clearApplicationUserData(pkg, false, obs, translatedUserId);
synchronized (obs) {
while (!obs.finished) {
try {
@@ -1991,28 +1991,26 @@ class PackageManagerShellCommand extends ShellCommand {
userId = UserHandle.parseUserArg(getNextArgRequired());
}
- String pkg = getNextArg();
+ final String pkg = getNextArg();
if (pkg == null) {
getErrPrintWriter().println("Error: no package or component specified");
return 1;
}
- userId = translateUserId(userId, true /*allowAll*/, "runSetEnabledSetting");
- if (userId == UserHandle.USER_ALL) {
- userId = UserHandle.USER_SYSTEM;
- }
- ComponentName cn = ComponentName.unflattenFromString(pkg);
+ final int translatedUserId =
+ translateUserId(userId, UserHandle.USER_NULL, "runSetEnabledSetting");
+ final ComponentName cn = ComponentName.unflattenFromString(pkg);
if (cn == null) {
- mInterface.setApplicationEnabledSetting(pkg, state, 0, userId,
+ mInterface.setApplicationEnabledSetting(pkg, state, 0, translatedUserId,
"shell:" + android.os.Process.myUid());
getOutPrintWriter().println("Package " + pkg + " new state: "
+ enabledSettingToString(
- mInterface.getApplicationEnabledSetting(pkg, userId)));
+ mInterface.getApplicationEnabledSetting(pkg, translatedUserId)));
return 0;
} else {
- mInterface.setComponentEnabledSetting(cn, state, 0, userId);
+ mInterface.setComponentEnabledSetting(cn, state, 0, translatedUserId);
getOutPrintWriter().println("Component " + cn.toShortString() + " new state: "
+ enabledSettingToString(
- mInterface.getComponentEnabledSetting(cn, userId)));
+ mInterface.getComponentEnabledSetting(cn, translatedUserId)));
return 0;
}
}
@@ -2029,13 +2027,11 @@ class PackageManagerShellCommand extends ShellCommand {
getErrPrintWriter().println("Error: no package or component specified");
return 1;
}
- userId = translateUserId(userId, true /*allowAll*/, "runSetHiddenSetting");
- if (userId == UserHandle.USER_ALL) {
- userId = UserHandle.USER_SYSTEM;
- }
- mInterface.setApplicationHiddenSettingAsUser(pkg, state, userId);
+ final int translatedUserId =
+ translateUserId(userId, UserHandle.USER_NULL, "runSetHiddenSetting");
+ mInterface.setApplicationHiddenSettingAsUser(pkg, state, translatedUserId);
getOutPrintWriter().println("Package " + pkg + " new hidden state: "
- + mInterface.getApplicationHiddenSettingAsUser(pkg, userId));
+ + mInterface.getApplicationHiddenSettingAsUser(pkg, translatedUserId));
return 0;
}
@@ -2102,16 +2098,14 @@ class PackageManagerShellCommand extends ShellCommand {
info = null;
}
try {
- userId = translateUserId(userId, true /*allowAll*/, "runSuspend");
- if (userId == UserHandle.USER_ALL) {
- userId = UserHandle.USER_SYSTEM;
- }
+ final int translatedUserId =
+ translateUserId(userId, UserHandle.USER_NULL, "runSuspend");
mInterface.setPackagesSuspendedAsUser(new String[]{packageName}, suspendedState,
((appExtras.size() > 0) ? appExtras : null),
((launcherExtras.size() > 0) ? launcherExtras : null),
- info, callingPackage, userId);
+ info, callingPackage, translatedUserId);
pw.println("Package " + packageName + " new suspended state: "
- + mInterface.isPackageSuspendedForUser(packageName, userId));
+ + mInterface.isPackageSuspendedForUser(packageName, translatedUserId));
return 0;
} catch (RemoteException | IllegalArgumentException e) {
pw.println(e.toString());
@@ -2139,11 +2133,12 @@ class PackageManagerShellCommand extends ShellCommand {
getErrPrintWriter().println("Error: no permission specified");
return 1;
}
- userId = translateUserId(userId, true /*allowAll*/, "runGrantRevokePermission");
+ final int translatedUserId =
+ translateUserId(userId, UserHandle.USER_NULL, "runGrantRevokePermission");
if (grant) {
- mPermissionManager.grantRuntimePermission(pkg, perm, userId);
+ mPermissionManager.grantRuntimePermission(pkg, perm, translatedUserId);
} else {
- mPermissionManager.revokeRuntimePermission(pkg, perm, userId);
+ mPermissionManager.revokeRuntimePermission(pkg, perm, translatedUserId);
}
return 0;
}
@@ -2327,11 +2322,9 @@ class PackageManagerShellCommand extends ShellCommand {
return 1;
}
- userId = translateUserId(userId, true /*allowAll*/, "runSetAppLink");
- if (userId == UserHandle.USER_ALL) {
- userId = UserHandle.USER_SYSTEM;
- }
- final PackageInfo info = mInterface.getPackageInfo(pkg, 0, userId);
+ final int translatedUserId =
+ translateUserId(userId, UserHandle.USER_NULL, "runSetAppLink");
+ final PackageInfo info = mInterface.getPackageInfo(pkg, 0, translatedUserId);
if (info == null) {
getErrPrintWriter().println("Error: package " + pkg + " not found.");
return 1;
@@ -2342,7 +2335,7 @@ class PackageManagerShellCommand extends ShellCommand {
return 1;
}
- if (!mInterface.updateIntentVerificationStatus(pkg, newMode, userId)) {
+ if (!mInterface.updateIntentVerificationStatus(pkg, newMode, translatedUserId)) {
getErrPrintWriter().println("Error: unable to update app link status for " + pkg);
return 1;
}
@@ -2371,11 +2364,9 @@ class PackageManagerShellCommand extends ShellCommand {
return 1;
}
- userId = translateUserId(userId, true /*allowAll*/, "runGetAppLink");
- if (userId == UserHandle.USER_ALL) {
- userId = UserHandle.USER_SYSTEM;
- }
- final PackageInfo info = mInterface.getPackageInfo(pkg, 0, userId);
+ final int translatedUserId =
+ translateUserId(userId, UserHandle.USER_NULL, "runGetAppLink");
+ final PackageInfo info = mInterface.getPackageInfo(pkg, 0, translatedUserId);
if (info == null) {
getErrPrintWriter().println("Error: package " + pkg + " not found.");
return 1;
@@ -2388,7 +2379,7 @@ class PackageManagerShellCommand extends ShellCommand {
}
getOutPrintWriter().println(linkStateToString(
- mInterface.getIntentVerificationStatus(pkg, userId)));
+ mInterface.getIntentVerificationStatus(pkg, translatedUserId)));
return 0;
}
@@ -2565,9 +2556,11 @@ class PackageManagerShellCommand extends ShellCommand {
getErrPrintWriter().println("Error: valid value not specified");
return 1;
}
- IUserManager um = IUserManager.Stub.asInterface(
+ final int translatedUserId =
+ translateUserId(userId, UserHandle.USER_NULL, "runSetUserRestriction");
+ final IUserManager um = IUserManager.Stub.asInterface(
ServiceManager.getService(Context.USER_SERVICE));
- um.setUserRestriction(restriction, value, userId);
+ um.setUserRestriction(restriction, value, translatedUserId);
return 0;
}
@@ -2763,14 +2756,15 @@ class PackageManagerShellCommand extends ShellCommand {
}
pkgName = componentName.getPackageName();
}
- userId = translateUserId(userId, true /*allowAll*/, "runInstallCreate");
+ final int translatedUserId =
+ translateUserId(userId, UserHandle.USER_NULL, "runSetHomeActivity");
final CompletableFuture<Boolean> future = new CompletableFuture<>();
final RemoteCallback callback = new RemoteCallback(res -> future.complete(res != null));
try {
IRoleManager roleManager = android.app.role.IRoleManager.Stub.asInterface(
ServiceManager.getServiceOrThrow(Context.ROLE_SERVICE));
roleManager.addRoleHolderAsUser(RoleManager.ROLE_HOME, pkgName,
- 0, userId, callback);
+ 0, translatedUserId, callback);
boolean success = future.get();
if (success) {
pw.println("Success");
@@ -2859,14 +2853,12 @@ class PackageManagerShellCommand extends ShellCommand {
}
}
- userId = translateUserId(userId, true /*allowAll*/, "runSetHarmfulAppWarning");
- if (userId == UserHandle.USER_ALL) {
- userId = UserHandle.USER_SYSTEM;
- }
+ final int translatedUserId =
+ translateUserId(userId, UserHandle.USER_NULL, "runSetHarmfulAppWarning");
final String packageName = getNextArgRequired();
final String warning = getNextArg();
- mInterface.setHarmfulAppWarning(packageName, warning, userId);
+ mInterface.setHarmfulAppWarning(packageName, warning, translatedUserId);
return 0;
}
@@ -2884,12 +2876,10 @@ class PackageManagerShellCommand extends ShellCommand {
}
}
- userId = translateUserId(userId, true /*allowAll*/, "runGetHarmfulAppWarning");
- if (userId == UserHandle.USER_ALL) {
- userId = UserHandle.USER_SYSTEM;
- }
+ final int translatedUserId =
+ translateUserId(userId, UserHandle.USER_NULL, "runGetHarmfulAppWarning");
final String packageName = getNextArgRequired();
- final CharSequence warning = mInterface.getHarmfulAppWarning(packageName, userId);
+ final CharSequence warning = mInterface.getHarmfulAppWarning(packageName, translatedUserId);
if (!TextUtils.isEmpty(warning)) {
getOutPrintWriter().println(warning);
return 0;
@@ -2917,21 +2907,22 @@ class PackageManagerShellCommand extends ShellCommand {
throw new IllegalArgumentException("ABI " + abi + " not supported on this device");
}
- private int translateUserId(int userId, boolean allowAll, String logContext) {
- return ActivityManager.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
- userId, allowAll, true, logContext, "pm command");
+ private int translateUserId(int userId, int allUserId, String logContext) {
+ final boolean allowAll = (allUserId != UserHandle.USER_NULL);
+ final int translatedUserId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
+ Binder.getCallingUid(), userId, allowAll, true, logContext, "pm command");
+ return translatedUserId == UserHandle.USER_ALL ? allUserId : translatedUserId;
}
private int doCreateSession(SessionParams params, String installerPackageName, int userId)
throws RemoteException {
- userId = translateUserId(userId, true /*allowAll*/, "doCreateSession");
if (userId == UserHandle.USER_ALL) {
- userId = UserHandle.USER_SYSTEM;
params.installFlags |= PackageManager.INSTALL_ALL_USERS;
}
-
+ final int translatedUserId =
+ translateUserId(userId, UserHandle.USER_SYSTEM, "doCreateSession");
final int sessionId = mInterface.getPackageInstaller()
- .createSession(params, installerPackageName, userId);
+ .createSession(params, installerPackageName, translatedUserId);
return sessionId;
}
diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java
index 27eefc6f71c0..7ea4e984b426 100644
--- a/services/core/java/com/android/server/pm/StagingManager.java
+++ b/services/core/java/com/android/server/pm/StagingManager.java
@@ -620,32 +620,6 @@ public class StagingManager {
PackageManager.INSTALL_FAILED_OTHER_STAGED_SESSION_IN_PROGRESS,
"Cannot stage multiple sessions without checkpoint support", null);
}
-
- // TODO:b/141843321 Add support for staging multiple sessions in apexd
- // Since apexd doesn't support multiple staged sessions yet, we have to careful how
- // we handle apex sessions. We want to allow a set of apex sessions under the same
- // parent to be staged when there is no previously staged apex sessions.
- if (isApexSession(session) && isApexSession(stagedSession)) {
- // session is apex and it can co-exist with stagedSession only if they are from
- // same parent
- final boolean coExist;
- if (!session.hasParentSessionId() && !stagedSession.hasParentSessionId()) {
- // Both single package apex sessions. Cannot co-exist.
- coExist = false;
- } else {
- // At least one of the session has parent. Both must be from same parent.
- coExist =
- session.getParentSessionId() == stagedSession.getParentSessionId();
- }
- if (!coExist) {
- throw new PackageManagerException(
- PackageManager.INSTALL_FAILED_OTHER_STAGED_SESSION_IN_PROGRESS,
- "Package: " + session.getPackageName() + " in session: "
- + session.sessionId + " cannot be staged as there is "
- + "already another apex staged session: "
- + stagedSession.sessionId, null);
- }
- }
}
}
}
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 3a00e6067e97..05f62b2a5f35 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -564,7 +564,7 @@ public class UserManagerService extends IUserManager.Stub {
readUserListLP();
sInstance = this;
}
- mSystemPackageInstaller = new UserSystemPackageInstaller(this);
+ mSystemPackageInstaller = new UserSystemPackageInstaller(this, mUserTypes);
mLocalService = new LocalService();
LocalServices.addService(UserManagerInternal.class, mLocalService);
mLockPatternUtils = new LockPatternUtils(mContext);
@@ -1205,6 +1205,24 @@ public class UserManagerService extends IUserManager.Stub {
}
}
+ /** Returns whether the given user type is one of the FULL user types. */
+ boolean isUserTypeSubtypeOfFull(String userType) {
+ UserTypeDetails userTypeDetails = mUserTypes.get(userType);
+ return userTypeDetails != null && userTypeDetails.isFull();
+ }
+
+ /** Returns whether the given user type is one of the PROFILE user types. */
+ boolean isUserTypeSubtypeOfProfile(String userType) {
+ UserTypeDetails userTypeDetails = mUserTypes.get(userType);
+ return userTypeDetails != null && userTypeDetails.isProfile();
+ }
+
+ /** Returns whether the given user type is one of the SYSTEM user types. */
+ boolean isUserTypeSubtypeOfSystem(String userType) {
+ UserTypeDetails userTypeDetails = mUserTypes.get(userType);
+ return userTypeDetails != null && userTypeDetails.isSystem();
+ }
+
@Override
public boolean hasBadge(@UserIdInt int userId) {
checkManageOrInteractPermIfCallerInOtherProfileGroup(userId, "hasBadge");
@@ -1616,13 +1634,14 @@ public class UserManagerService extends IUserManager.Stub {
* See {@link UserManagerInternal#setDevicePolicyUserRestrictions}
*/
private void setDevicePolicyUserRestrictionsInner(@UserIdInt int userId,
- @Nullable Bundle restrictions, boolean isDeviceOwner, int cameraRestrictionScope) {
+ @Nullable Bundle restrictions,
+ @UserManagerInternal.OwnerType int restrictionOwnerType) {
final Bundle global = new Bundle();
final Bundle local = new Bundle();
// Sort restrictions into local and global ensuring they don't overlap.
- UserRestrictionsUtils.sortToGlobalAndLocal(restrictions, isDeviceOwner,
- cameraRestrictionScope, global, local);
+ UserRestrictionsUtils.sortToGlobalAndLocal(restrictions, restrictionOwnerType, global,
+ local);
boolean globalChanged, localChanged;
synchronized (mRestrictionsLock) {
@@ -1632,7 +1651,7 @@ public class UserManagerService extends IUserManager.Stub {
localChanged = updateRestrictionsIfNeededLR(
userId, local, mDevicePolicyLocalUserRestrictions);
- if (isDeviceOwner) {
+ if (restrictionOwnerType == UserManagerInternal.OWNER_TYPE_DEVICE_OWNER) {
// Remember the global restriction owner userId to be able to make a distinction
// in getUserRestrictionSource on who set local policies.
mDeviceOwnerUserId = userId;
@@ -3240,8 +3259,8 @@ public class UserManagerService extends IUserManager.Stub {
StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE);
t.traceEnd();
- final Set<String> installablePackages = // TODO(b/142482943): use userType
- mSystemPackageInstaller.getInstallablePackagesForUserType(flags);
+ final Set<String> installablePackages =
+ mSystemPackageInstaller.getInstallablePackagesForUserType(userType);
t.traceBegin("PM.createNewUser");
mPm.createNewUser(userId, installablePackages, disallowedPackages);
t.traceEnd();
@@ -4474,9 +4493,9 @@ public class UserManagerService extends IUserManager.Stub {
private class LocalService extends UserManagerInternal {
@Override
public void setDevicePolicyUserRestrictions(@UserIdInt int userId,
- @Nullable Bundle restrictions, boolean isDeviceOwner, int cameraRestrictionScope) {
- UserManagerService.this.setDevicePolicyUserRestrictionsInner(userId, restrictions,
- isDeviceOwner, cameraRestrictionScope);
+ @Nullable Bundle restrictions, @OwnerType int restrictionOwnerType) {
+ UserManagerService.this.setDevicePolicyUserRestrictionsInner(userId,
+ restrictions, restrictionOwnerType);
}
@Override
diff --git a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
index 3be51c58798e..f071c65cc772 100644
--- a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
+++ b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
@@ -194,7 +194,18 @@ public class UserRestrictionsUtils {
UserManager.DISALLOW_SYSTEM_ERROR_DIALOGS,
UserManager.DISALLOW_RUN_IN_BACKGROUND,
UserManager.DISALLOW_UNMUTE_MICROPHONE,
- UserManager.DISALLOW_UNMUTE_DEVICE
+ UserManager.DISALLOW_UNMUTE_DEVICE,
+ UserManager.DISALLOW_CAMERA
+ );
+
+ /**
+ * Special user restrictions that are applied globally when set by the profile owner of a
+ * managed profile that was created during the device provisioning flow.
+ */
+ private static final Set<String> PROFILE_OWNER_ORGANIZATION_OWNED_GLOBAL_RESTRICTIONS =
+ Sets.newArraySet(
+ UserManager.DISALLOW_CONFIG_DATE_TIME,
+ UserManager.DISALLOW_CAMERA
);
/**
@@ -419,15 +430,9 @@ public class UserRestrictionsUtils {
* Takes restrictions that can be set by device owner, and sort them into what should be applied
* globally and what should be applied only on the current user.
*/
- public static void sortToGlobalAndLocal(@Nullable Bundle in, boolean isDeviceOwner,
- int cameraRestrictionScope,
- @NonNull Bundle global, @NonNull Bundle local) {
- // Camera restriction (as well as all others) goes to at most one bundle.
- if (cameraRestrictionScope == UserManagerInternal.CAMERA_DISABLED_GLOBALLY) {
- global.putBoolean(UserManager.DISALLOW_CAMERA, true);
- } else if (cameraRestrictionScope == UserManagerInternal.CAMERA_DISABLED_LOCALLY) {
- local.putBoolean(UserManager.DISALLOW_CAMERA, true);
- }
+ public static void sortToGlobalAndLocal(@Nullable Bundle in,
+ @UserManagerInternal.OwnerType int restrictionOwnerType, @NonNull Bundle global,
+ @NonNull Bundle local) {
if (in == null || in.size() == 0) {
return;
}
@@ -435,7 +440,7 @@ public class UserRestrictionsUtils {
if (!in.getBoolean(key)) {
continue;
}
- if (isGlobal(isDeviceOwner, key)) {
+ if (isGlobal(restrictionOwnerType, key)) {
global.putBoolean(key, true);
} else {
local.putBoolean(key, true);
@@ -446,9 +451,13 @@ public class UserRestrictionsUtils {
/**
* Whether given user restriction should be enforced globally.
*/
- private static boolean isGlobal(boolean isDeviceOwner, String key) {
- return (isDeviceOwner &&
- (PRIMARY_USER_ONLY_RESTRICTIONS.contains(key) || GLOBAL_RESTRICTIONS.contains(key)))
+ private static boolean isGlobal(@UserManagerInternal.OwnerType int restrictionOwnerType,
+ String key) {
+ return ((restrictionOwnerType == UserManagerInternal.OWNER_TYPE_DEVICE_OWNER) && (
+ PRIMARY_USER_ONLY_RESTRICTIONS.contains(key) || GLOBAL_RESTRICTIONS.contains(key)))
+ || ((restrictionOwnerType
+ == UserManagerInternal.OWNER_TYPE_PROFILE_OWNER_OF_ORGANIZATION_OWNED_DEVICE)
+ && PROFILE_OWNER_ORGANIZATION_OWNED_GLOBAL_RESTRICTIONS.contains(key))
|| PROFILE_GLOBAL_RESTRICTIONS.contains(key)
|| DEVICE_OWNER_ONLY_RESTRICTIONS.contains(key);
}
diff --git a/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java b/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java
index 95197b07deaf..0a6a43543860 100644
--- a/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java
+++ b/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java
@@ -22,7 +22,6 @@ import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.content.pm.PackageManagerInternal;
import android.content.pm.PackageParser;
-import android.content.pm.UserInfo;
import android.content.res.Resources;
import android.os.SystemProperties;
import android.os.UserHandle;
@@ -37,6 +36,8 @@ import com.android.server.SystemConfig;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.Arrays;
+import java.util.Map;
import java.util.Set;
/**
@@ -84,58 +85,84 @@ class UserSystemPackageInstaller {
* System Property whether to only install system packages on a user if they're whitelisted for
* that user type. These are flags and can be freely combined.
* <ul>
- * <li> 0 (0b000) - disable whitelist (install all system packages; no logging)</li>
- * <li> 1 (0b001) - enforce (only install system packages if they are whitelisted)</li>
- * <li> 2 (0b010) - log (log when a non-whitelisted package is run)</li>
- * <li> 4 (0b100) - implicitly whitelist any package not mentioned in the whitelist</li>
- * <li>-1 - use device default (as defined in res/res/values/config.xml)</li>
+ * <li> 0 (0b0000) - disable whitelist (install all system packages; no logging)</li>
+ * <li> 1 (0b0001) - enforce (only install system packages if they are whitelisted)</li>
+ * <li> 2 (0b0010) - log (log when a non-whitelisted package is run)</li>
+ * <li> 4 (0b0100) - implicitly whitelist any package not mentioned in the whitelist</li>
+ * <li> 8 (0b1000) - ignore OTAs (don't install system packages during OTAs)</li>
+ * <li>-1 - use device default (as defined in res/res/values/config.xml)</li>
* </ul>
* Note: This list must be kept current with config_userTypePackageWhitelistMode in
* frameworks/base/core/res/res/values/config.xml
*/
static final String PACKAGE_WHITELIST_MODE_PROP = "persist.debug.user.package_whitelist_mode";
static final int USER_TYPE_PACKAGE_WHITELIST_MODE_DISABLE = 0;
- static final int USER_TYPE_PACKAGE_WHITELIST_MODE_ENFORCE = 0b001;
- static final int USER_TYPE_PACKAGE_WHITELIST_MODE_LOG = 0b010;
- static final int USER_TYPE_PACKAGE_WHITELIST_MODE_IMPLICIT_WHITELIST = 0b100;
+ static final int USER_TYPE_PACKAGE_WHITELIST_MODE_ENFORCE = 0b0001;
+ static final int USER_TYPE_PACKAGE_WHITELIST_MODE_LOG = 0b0010;
+ static final int USER_TYPE_PACKAGE_WHITELIST_MODE_IMPLICIT_WHITELIST = 0b0100;
+ static final int USER_TYPE_PACKAGE_WHITELIST_MODE_IGNORE_OTA = 0b1000;
static final int USER_TYPE_PACKAGE_WHITELIST_MODE_DEVICE_DEFAULT = -1;
@IntDef(flag = true, prefix = "USER_TYPE_PACKAGE_WHITELIST_MODE_", value = {
USER_TYPE_PACKAGE_WHITELIST_MODE_DISABLE,
USER_TYPE_PACKAGE_WHITELIST_MODE_ENFORCE,
- USER_TYPE_PACKAGE_WHITELIST_MODE_ENFORCE,
USER_TYPE_PACKAGE_WHITELIST_MODE_LOG,
USER_TYPE_PACKAGE_WHITELIST_MODE_IMPLICIT_WHITELIST,
+ USER_TYPE_PACKAGE_WHITELIST_MODE_IGNORE_OTA,
})
@Retention(RetentionPolicy.SOURCE)
public @interface PackageWhitelistMode {}
/**
- * Maps system package manifest names to the user flags on which they should be initially
- * installed.
- * <p>Packages that are whitelisted, but then blacklisted so that they aren't to be installed on
+ * Maps system package manifest names to a bitset representing (via {@link #getUserTypeMask})
+ * the user types on which they should be initially installed.
+ * <p>
+ * E.g. if package "pkg1" should be installed on "usertype_d", which is the user type for which
+ * {@link #getUserTypeMask}("usertype_d") returns (1 << 3)
+ * then mWhitelistedPackagesForUserTypes.get("pkg1") will be a Long whose
+ * bit in position 3 will equal 1.
+ * <p>
+ * Packages that are whitelisted, but then blacklisted so that they aren't to be installed on
* any user, are purposefully still present in this list.
*/
- private final ArrayMap<String, Integer> mWhitelistedPackagesForUserTypes;
+ private final ArrayMap<String, Long> mWhitelistedPackagesForUserTypes;
private final UserManagerService mUm;
- UserSystemPackageInstaller(UserManagerService ums) {
- mUm = ums;
+ /**
+ * Alphabetically sorted list of user types.
+ * Throughout this class, a long (functioning as a bitset) has its ith bit representing
+ * the user type stored in mUserTypes[i].
+ * mUserTypes cannot exceed Long.SIZE (since we are using long for our bitset).
+ */
+ private final String[] mUserTypes;
+
+ UserSystemPackageInstaller(UserManagerService um, ArrayMap<String, UserTypeDetails> userTypes) {
+ mUm = um;
+ mUserTypes = getAndSortKeysFromMap(userTypes);
+ if (mUserTypes.length > Long.SIZE) {
+ throw new IllegalArgumentException("Device contains " + userTypes.size()
+ + " user types. However, UserSystemPackageInstaller does not work if there are"
+ + " more than " + Long.SIZE + " user types.");
+ // UserSystemPackageInstaller could use a BitSet instead of Long in this case.
+ // But, currently, 64 user types is far beyond expectations, so we have not done so.
+ }
mWhitelistedPackagesForUserTypes =
determineWhitelistedPackagesForUserTypes(SystemConfig.getInstance());
}
/** Constructor for testing purposes. */
@VisibleForTesting
- UserSystemPackageInstaller(UserManagerService ums, ArrayMap<String, Integer> whitelist) {
+ UserSystemPackageInstaller(UserManagerService ums, ArrayMap<String, Long> whitelist,
+ String[] sortedUserTypes) {
mUm = ums;
+ mUserTypes = sortedUserTypes;
mWhitelistedPackagesForUserTypes = whitelist;
}
/**
* During OTAs and first boot, install/uninstall all system packages for all users based on the
- * user's UserInfo flags and the SystemConfig whitelist.
+ * user's user type and the SystemConfig whitelist.
* We do NOT uninstall packages during an OTA though.
*
* This is responsible for enforcing the whitelist for pre-existing users (i.e. USER_SYSTEM);
@@ -144,11 +171,17 @@ class UserSystemPackageInstaller {
boolean installWhitelistedSystemPackages(boolean isFirstBoot, boolean isUpgrade) {
final int mode = getWhitelistMode();
checkWhitelistedSystemPackages(mode);
- if (!isUpgrade && !isFirstBoot) {
+ final boolean isConsideredUpgrade = isUpgrade && !isIgnoreOtaMode(mode);
+ if (!isConsideredUpgrade && !isFirstBoot) {
+ return false;
+ }
+ if (isFirstBoot && !isEnforceMode(mode)) {
+ // Note that if !isEnforceMode, we nonetheless still install packages if isUpgrade
+ // in order to undo any previous non-installing. isFirstBoot lacks this requirement.
return false;
}
Slog.i(TAG, "Reviewing whitelisted packages due to "
- + (isFirstBoot ? "[firstBoot]" : "") + (isUpgrade ? "[upgrade]" : ""));
+ + (isFirstBoot ? "[firstBoot]" : "") + (isConsideredUpgrade ? "[upgrade]" : ""));
final PackageManagerInternal pmInt = LocalServices.getService(PackageManagerInternal.class);
// Install/uninstall system packages per user.
for (int userId : mUm.getUserIds()) {
@@ -160,7 +193,7 @@ class UserSystemPackageInstaller {
final boolean install =
(userWhitelist == null || userWhitelist.contains(pkg.packageName))
&& !pkg.applicationInfo.hiddenUntilInstalled;
- if (isUpgrade && !isFirstBoot && !install) {
+ if (isConsideredUpgrade && !isFirstBoot && !install) {
return; // To be careful, we don’t uninstall apps during OTAs
}
final boolean changed = pmInt.setInstalled(pkg, userId, install);
@@ -220,6 +253,19 @@ class UserSystemPackageInstaller {
}
/**
+ * Whether to ignore OTAs, and therefore not install missing system packages during OTAs.
+ * <p>Note:
+ * If in this mode, old system packages will not be installed on pre-existing users during OTAs.
+ * Any system packages that had not been installed at the time of the user's creation,
+ * due to {@link UserSystemPackageInstaller}'s previous actions, will therefore continue to
+ * remain uninstalled, even if the whitelist (or enforcement mode) now declares that they should
+ * be.
+ */
+ boolean isIgnoreOtaMode() {
+ return isIgnoreOtaMode(getWhitelistMode());
+ }
+
+ /**
* Whether to log a warning concerning potential problems with the user-type package whitelist.
*/
boolean isLogMode() {
@@ -239,6 +285,11 @@ class UserSystemPackageInstaller {
return (whitelistMode & USER_TYPE_PACKAGE_WHITELIST_MODE_ENFORCE) != 0;
}
+ /** See {@link #isIgnoreOtaMode()}. */
+ private static boolean isIgnoreOtaMode(int whitelistMode) {
+ return (whitelistMode & USER_TYPE_PACKAGE_WHITELIST_MODE_IGNORE_OTA) != 0;
+ }
+
/** See {@link #isLogMode()}. */
private static boolean isLogMode(int whitelistMode) {
return (whitelistMode & USER_TYPE_PACKAGE_WHITELIST_MODE_LOG) != 0;
@@ -262,27 +313,27 @@ class UserSystemPackageInstaller {
/**
* Gets the system packages names that should be installed on the given user.
- * See {@link #getInstallablePackagesForUserType(int)}.
+ * See {@link #getInstallablePackagesForUserType(String)}.
*/
private @Nullable Set<String> getInstallablePackagesForUserId(@UserIdInt int userId) {
- return getInstallablePackagesForUserType(mUm.getUserInfo(userId).flags);
+ return getInstallablePackagesForUserType(mUm.getUserInfo(userId).userType);
}
/**
- * Gets the system package names that should be installed on a user with the given flags, as
+ * Gets the system package names that should be installed on users of the given user type, as
* determined by SystemConfig, the whitelist mode, and the apps actually on the device.
* Names are the {@link PackageParser.Package#packageName}, not necessarily the manifest names.
*
- * Returns null if all system packages should be installed (due enforce-mode being off).
+ * Returns null if all system packages should be installed (due to enforce-mode being off).
*/
- @Nullable Set<String> getInstallablePackagesForUserType(int flags) {
+ @Nullable Set<String> getInstallablePackagesForUserType(String userType) {
final int mode = getWhitelistMode();
if (!isEnforceMode(mode)) {
return null;
}
- final boolean isSystemUser = (flags & UserInfo.FLAG_SYSTEM) != 0;
+ final boolean isSystemUser = mUm.isUserTypeSubtypeOfSystem(userType);
final boolean isImplicitWhitelistMode = isImplicitWhitelistMode(mode);
- final Set<String> whitelistedPackages = getWhitelistedPackagesForUserType(flags);
+ final Set<String> whitelistedPackages = getWhitelistedPackagesForUserType(userType);
final Set<String> installPackages = new ArraySet<>();
final PackageManagerInternal pmInt = LocalServices.getService(PackageManagerInternal.class);
@@ -304,8 +355,9 @@ class UserSystemPackageInstaller {
* the given whitelist of system packages.
*
* @param sysPkg the system package. Must be a system package; no verification for this is done.
- * @param userTypeWhitelist map of package manifest names to user flags on which they should be
- * installed
+ * @param userTypeWhitelist map of package manifest names to user types on which they should be
+ * installed. This is only used for overriding the userWhitelist in
+ * certain situations (based on its keyset).
* @param userWhitelist set of package manifest names that should be installed on this
* particular user. This must be consistent with userTypeWhitelist, but is
* passed in separately to avoid repeatedly calculating it from
@@ -315,7 +367,7 @@ class UserSystemPackageInstaller {
*/
@VisibleForTesting
static boolean shouldInstallPackage(PackageParser.Package sysPkg,
- @NonNull ArrayMap<String, Integer> userTypeWhitelist,
+ @NonNull ArrayMap<String, Long> userTypeWhitelist,
@NonNull Set<String> userWhitelist, boolean isImplicitWhitelistMode,
boolean isSystemUser) {
@@ -335,16 +387,17 @@ class UserSystemPackageInstaller {
}
/**
- * Gets the package manifest names that are whitelisted for a user with the given flags,
+ * Gets the package manifest names that are whitelisted for users of the given user type,
* as determined by SystemConfig.
*/
@VisibleForTesting
- @NonNull Set<String> getWhitelistedPackagesForUserType(int flags) {
- Set<String> installablePkgs = new ArraySet<>(mWhitelistedPackagesForUserTypes.size());
+ @NonNull Set<String> getWhitelistedPackagesForUserType(String userType) {
+ final long userTypeMask = getUserTypeMask(userType);
+ final Set<String> installablePkgs = new ArraySet<>(mWhitelistedPackagesForUserTypes.size());
for (int i = 0; i < mWhitelistedPackagesForUserTypes.size(); i++) {
- String pkgName = mWhitelistedPackagesForUserTypes.keyAt(i);
- int whitelistedUserTypes = mWhitelistedPackagesForUserTypes.valueAt(i);
- if ((flags & whitelistedUserTypes) != 0) {
+ final String pkgName = mWhitelistedPackagesForUserTypes.keyAt(i);
+ final long whitelistedUserTypes = mWhitelistedPackagesForUserTypes.valueAt(i);
+ if ((userTypeMask & whitelistedUserTypes) != 0) {
installablePkgs.add(pkgName);
}
}
@@ -364,7 +417,8 @@ class UserSystemPackageInstaller {
}
/**
- * Returns a map of package manifest names to the user flags on which it is to be installed.
+ * Returns a map of package manifest names to the bit set representing (via
+ * {@link #getUserTypeMask}) the user types on which they are to be installed.
* Also, clears this data from SystemConfig where it was stored inefficiently (and therefore
* should be called exactly once, even if the data isn't useful).
*
@@ -375,89 +429,132 @@ class UserSystemPackageInstaller {
* <li>Packages that never whitelisted at all (even if they are explicitly blacklisted) are
* ignored.</li>
* <li>Packages that are blacklisted whenever they are whitelisted will be stored with the
- * flag 0 (since this is a valid scenario, e.g. if an OEM completely blacklists an AOSP
- * app).</li>
+ * value 0 (since this is a valid scenario, e.g. if an OEM completely blacklists an
+ * AOSP app).</li>
* </ul>
+ *
+ * @see #mWhitelistedPackagesForUserTypes
*/
@VisibleForTesting
- static ArrayMap<String, Integer> determineWhitelistedPackagesForUserTypes(
- SystemConfig sysConfig) {
+ ArrayMap<String, Long> determineWhitelistedPackagesForUserTypes(SystemConfig sysConfig) {
+ // We first get the list of user types that correspond to FULL, SYSTEM, and PROFILE.
+ final Map<String, Long> baseTypeBitSets = getBaseTypeBitSets();
final ArrayMap<String, Set<String>> whitelist =
sysConfig.getAndClearPackageToUserTypeWhitelist();
// result maps packageName -> userTypes on which the package should be installed.
- final ArrayMap<String, Integer> result = new ArrayMap<>(whitelist.size() + 1);
+ final ArrayMap<String, Long> result = new ArrayMap<>(whitelist.size() + 1);
// First, do the whitelisted user types.
for (int i = 0; i < whitelist.size(); i++) {
final String pkgName = whitelist.keyAt(i).intern();
- final int flags = getFlagsFromUserTypes(whitelist.valueAt(i));
- if (flags != 0) {
- result.put(pkgName, flags);
+ final long typesBitSet = getTypesBitSet(whitelist.valueAt(i), baseTypeBitSets);
+ if (typesBitSet != 0) {
+ result.put(pkgName, typesBitSet);
}
}
// Then, un-whitelist any blacklisted user types.
- // TODO(b/141370854): Right now, the blacklist is actually just an 'unwhitelist'. Which
- // direction we go depends on how we design user subtypes, which is still
- // being designed. For now, unwhitelisting works for current use-cases.
final ArrayMap<String, Set<String>> blacklist =
sysConfig.getAndClearPackageToUserTypeBlacklist();
for (int i = 0; i < blacklist.size(); i++) {
final String pkgName = blacklist.keyAt(i).intern();
- final int nonFlags = getFlagsFromUserTypes(blacklist.valueAt(i));
- final Integer flags = result.get(pkgName);
- if (flags != null) {
- result.put(pkgName, flags & ~nonFlags);
+ final long nonTypesBitSet = getTypesBitSet(blacklist.valueAt(i), baseTypeBitSets);
+ final Long typesBitSet = result.get(pkgName);
+ if (typesBitSet != null) {
+ result.put(pkgName, typesBitSet & ~nonTypesBitSet);
+ } else if (nonTypesBitSet != 0) {
+ // Package was never whitelisted but is validly blacklisted.
+ result.put(pkgName, 0L);
}
}
// Regardless of the whitelists/blacklists, ensure mandatory packages.
- result.put("android",
- UserInfo.FLAG_SYSTEM | UserInfo.FLAG_FULL | UserInfo.FLAG_PROFILE);
+ result.put("android", ~0L);
+ return result;
+ }
+
+ /**
+ * Returns the bitmask (with exactly one 1) corresponding to the given userType.
+ * Returns 0 if no such userType exists.
+ */
+ @VisibleForTesting
+ long getUserTypeMask(String userType) {
+ final int userTypeIndex = Arrays.binarySearch(mUserTypes, userType);
+ final long userTypeMask = userTypeIndex >= 0 ? (1 << userTypeIndex) : 0;
+ return userTypeMask;
+ }
+
+ /**
+ * Returns the mapping from the name of each base type to the bitset (as defined by
+ * {@link #getUserTypeMask}) of user types to which it corresponds (i.e. the base's subtypes).
+ * <p>
+ * E.g. if "android.type.ex" is a FULL user type for which getUserTypeMask() returns (1 << 3),
+ * then getBaseTypeBitSets().get("FULL") will contain true (1) in position 3.
+ */
+ private Map<String, Long> getBaseTypeBitSets() {
+ long typesBitSetFull = 0;
+ long typesBitSetSystem = 0;
+ long typesBitSetProfile = 0;
+ for (int idx = 0; idx < mUserTypes.length; idx++) {
+ if (mUm.isUserTypeSubtypeOfFull(mUserTypes[idx])) {
+ typesBitSetFull |= (1 << idx);
+ }
+ if (mUm.isUserTypeSubtypeOfSystem(mUserTypes[idx])) {
+ typesBitSetSystem |= (1 << idx);
+ }
+ if (mUm.isUserTypeSubtypeOfProfile(mUserTypes[idx])) {
+ typesBitSetProfile |= (1 << idx);
+ }
+ }
+
+ Map<String, Long> result = new ArrayMap<>(3);
+ result.put("FULL", typesBitSetFull);
+ result.put("SYSTEM", typesBitSetSystem);
+ result.put("PROFILE", typesBitSetProfile);
return result;
}
- /** Converts a user types, as used in SystemConfig, to a UserInfo flag. */
- private static int getFlagsFromUserTypes(Iterable<String> userTypes) {
- // TODO(b/142482943): Update all this for the new UserTypes.
- int flags = 0;
+ /**
+ * Converts a list of user types and base types, as used in SystemConfig, to a bit set
+ * representing (via {@link #getUserTypeMask}) user types.
+ *
+ * Returns 0 if userTypes does not contain any valid user or base types.
+ *
+ * @param baseTypeBitSets a map from the base types (FULL/SYSTEM/PROFILE) to their subtypes
+ * (represented as a bitset, as defined by {@link #getUserTypeMask}).
+ * (This can be created by {@link #getBaseTypeBitSets}.)
+ */
+ private long getTypesBitSet(Iterable<String> userTypes, Map<String, Long> baseTypeBitSets) {
+ long resultBitSet = 0;
for (String type : userTypes) {
- switch (type) {
- case "GUEST":
- flags |= UserInfo.FLAG_GUEST;
- break;
- case "RESTRICTED":
- flags |= UserInfo.FLAG_RESTRICTED;
- break;
- case "MANAGED_PROFILE":
- flags |= UserInfo.FLAG_MANAGED_PROFILE;
- break;
- case "EPHEMERAL":
- flags |= UserInfo.FLAG_EPHEMERAL;
- break;
- case "DEMO":
- flags |= UserInfo.FLAG_DEMO;
- break;
- case "FULL":
- flags |= UserInfo.FLAG_FULL;
- break;
- case "SYSTEM":
- flags |= UserInfo.FLAG_SYSTEM;
- break;
- case "PROFILE":
- flags |= UserInfo.FLAG_PROFILE;
- break;
- default:
- Slog.w(TAG, "SystemConfig contained an invalid user type: " + type);
- break;
- // Other UserInfo flags are forbidden.
- // In particular, FLAG_INITIALIZED, FLAG_DISABLED, FLAG_QUIET_MODE are inapplicable.
- // The following are invalid now, but are reconsiderable: FLAG_PRIMARY, FLAG_ADMIN.
+ // See if userType is a base type, like FULL.
+ final Long baseTypeBitSet = baseTypeBitSets.get(type);
+ if (baseTypeBitSet != null) {
+ resultBitSet |= baseTypeBitSet;
+ continue;
}
+ // userType wasn't a base type, so it should be the name of a specific user type.
+ final long userTypeBitSet = getUserTypeMask(type);
+ if (userTypeBitSet != 0) {
+ resultBitSet |= userTypeBitSet;
+ continue;
+ }
+ Slog.w(TAG, "SystemConfig contained an invalid user type: " + type);
+ }
+ return resultBitSet;
+ }
+
+ /** Returns a sorted array consisting of the keyset of the provided map. */
+ private static String[] getAndSortKeysFromMap(ArrayMap<String, ?> map) {
+ final String[] userTypeList = new String[map.size()];
+ for (int i = 0; i < map.size(); i++) {
+ userTypeList[i] = map.keyAt(i);
}
- return flags;
+ Arrays.sort(userTypeList);
+ return userTypeList;
}
void dump(PrintWriter pw) {
final String prefix = " ";
+ final String prefix2 = prefix + prefix;
final int mode = getWhitelistMode();
pw.println("Whitelisted packages per user type");
pw.print(prefix); pw.print("Mode: ");
@@ -465,20 +562,30 @@ class UserSystemPackageInstaller {
pw.print(isEnforceMode(mode) ? " (enforced)" : "");
pw.print(isLogMode(mode) ? " (logged)" : "");
pw.print(isImplicitWhitelistMode(mode) ? " (implicit)" : "");
+ pw.print(isIgnoreOtaMode(mode) ? " (ignore OTAs)" : "");
pw.println();
+ pw.print(prefix); pw.println("Legend");
+ for (int idx = 0; idx < mUserTypes.length; idx++) {
+ pw.print(prefix2); pw.println(idx + " -> " + mUserTypes[idx]);
+ }
+
final int size = mWhitelistedPackagesForUserTypes.size();
if (size == 0) {
pw.print(prefix); pw.println("No packages");
return;
}
- final String prefix2 = prefix + prefix;
pw.print(prefix); pw.print(size); pw.println(" packages:");
- for (int i = 0; i < size; i++) {
- final String pkgName = mWhitelistedPackagesForUserTypes.keyAt(i);
- final String whitelistedUserTypes =
- UserInfo.flagsToString(mWhitelistedPackagesForUserTypes.valueAt(i));
- pw.print(prefix2); pw.print(pkgName); pw.print(": "); pw.println(whitelistedUserTypes);
+ for (int pkgIdx = 0; pkgIdx < size; pkgIdx++) {
+ final String pkgName = mWhitelistedPackagesForUserTypes.keyAt(pkgIdx);
+ pw.print(prefix2); pw.print(pkgName); pw.print(": ");
+ final long userTypesBitSet = mWhitelistedPackagesForUserTypes.valueAt(pkgIdx);
+ for (int idx = 0; idx < mUserTypes.length; idx++) {
+ if ((userTypesBitSet & (1 << idx)) != 0) {
+ pw.print(idx); pw.print(" ");
+ }
+ }
+ pw.println();
}
}
}
diff --git a/services/core/java/com/android/server/pm/UserTypeDetails.java b/services/core/java/com/android/server/pm/UserTypeDetails.java
index 5fc3ba1fc538..1631df33587f 100644
--- a/services/core/java/com/android/server/pm/UserTypeDetails.java
+++ b/services/core/java/com/android/server/pm/UserTypeDetails.java
@@ -223,6 +223,14 @@ public final class UserTypeDetails {
return (mBaseType & UserInfo.FLAG_PROFILE) != 0;
}
+ public boolean isFull() {
+ return (mBaseType & UserInfo.FLAG_FULL) != 0;
+ }
+
+ public boolean isSystem() {
+ return (mBaseType & UserInfo.FLAG_SYSTEM) != 0;
+ }
+
// TODO(b/142482943): Hook this up and don't return the original.
public List<String> getDefaultRestrictions() {
return mDefaultRestrictions;
diff --git a/services/core/java/com/android/server/pm/permission/BasePermission.java b/services/core/java/com/android/server/pm/permission/BasePermission.java
index 037912a66b3a..c39dcfefb2e8 100644
--- a/services/core/java/com/android/server/pm/permission/BasePermission.java
+++ b/services/core/java/com/android/server/pm/permission/BasePermission.java
@@ -279,9 +279,6 @@ public final class BasePermission {
public boolean isTelephony() {
return (protectionLevel & PermissionInfo.PROTECTION_FLAG_TELEPHONY) != 0;
}
- public boolean isWifi() {
- return (protectionLevel & PermissionInfo.PROTECTION_FLAG_WIFI) != 0;
- }
public void transfer(@NonNull String origPackageName, @NonNull String newPackageName) {
if (!origPackageName.equals(sourcePackageName)) {
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index e9aad4fa94d8..2ffba45be4a3 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -3292,13 +3292,6 @@ public class PermissionManagerService extends IPermissionManager.Stub {
// Special permissions for the system telephony apps.
allowed = true;
}
- if (!allowed && bp.isWifi()
- && ArrayUtils.contains(mPackageManagerInt.getKnownPackageNames(
- PackageManagerInternal.PACKAGE_WIFI, UserHandle.USER_SYSTEM),
- pkg.packageName)) {
- // Special permissions for the system wifi.
- allowed = true;
- }
}
return allowed;
}
diff --git a/services/core/java/com/android/server/power/ShutdownThread.java b/services/core/java/com/android/server/power/ShutdownThread.java
index 0a6b38fb2e9a..6da8fb4b1edb 100644
--- a/services/core/java/com/android/server/power/ShutdownThread.java
+++ b/services/core/java/com/android/server/power/ShutdownThread.java
@@ -47,8 +47,8 @@ import android.util.TimingsTraceLog;
import android.view.WindowManager;
import com.android.internal.telephony.ITelephony;
-import com.android.server.RescueParty;
import com.android.server.LocalServices;
+import com.android.server.RescueParty;
import com.android.server.pm.PackageManagerService;
import com.android.server.statusbar.StatusBarManagerInternal;
@@ -307,7 +307,9 @@ public final class ShutdownThread extends Thread {
com.android.internal.R.string.reboot_to_update_reboot));
}
} else if (mReason != null && mReason.equals(PowerManager.REBOOT_RECOVERY)) {
- if (RescueParty.isAttemptingFactoryReset()) {
+ if (showSysuiReboot()) {
+ return null;
+ } else if (RescueParty.isAttemptingFactoryReset()) {
// We're not actually doing a factory reset yet; we're rebooting
// to ask the user if they'd like to reset, so give them a less
// scary dialog message.
diff --git a/services/core/java/com/android/server/timedetector/SimpleTimeDetectorStrategy.java b/services/core/java/com/android/server/timedetector/SimpleTimeDetectorStrategy.java
index 9dbbf16e7734..3c79b2399fa3 100644
--- a/services/core/java/com/android/server/timedetector/SimpleTimeDetectorStrategy.java
+++ b/services/core/java/com/android/server/timedetector/SimpleTimeDetectorStrategy.java
@@ -16,9 +16,11 @@
package com.android.server.timedetector;
+import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.AlarmManager;
+import android.app.timedetector.ManualTimeSuggestion;
import android.app.timedetector.PhoneTimeSuggestion;
import android.content.Intent;
import android.util.Slog;
@@ -27,6 +29,8 @@ import android.util.TimestampedValue;
import com.android.internal.telephony.TelephonyIntents;
import java.io.PrintWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
/**
* An implementation of TimeDetectorStrategy that passes only NITZ suggestions to
@@ -38,10 +42,22 @@ public final class SimpleTimeDetectorStrategy implements TimeDetectorStrategy {
private final static String TAG = "timedetector.SimpleTimeDetectorStrategy";
+ @IntDef({ ORIGIN_PHONE, ORIGIN_MANUAL })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Origin {}
+
+ /** Used when a time value originated from a telephony signal. */
+ @Origin
+ private static final int ORIGIN_PHONE = 1;
+
+ /** Used when a time value originated from a user / manual settings. */
+ @Origin
+ private static final int ORIGIN_MANUAL = 2;
+
/**
* CLOCK_PARANOIA: The maximum difference allowed between the expected system clock time and the
* actual system clock time before a warning is logged. Used to help identify situations where
- * there is something other than this class setting the system clock.
+ * there is something other than this class setting the system clock automatically.
*/
private static final long SYSTEM_CLOCK_PARANOIA_THRESHOLD_MILLIS = 2 * 1000;
@@ -52,11 +68,11 @@ public final class SimpleTimeDetectorStrategy implements TimeDetectorStrategy {
@Nullable private PhoneTimeSuggestion mLastPhoneSuggestion;
// Information about the last time signal received: Used when toggling auto-time.
- @Nullable private TimestampedValue<Long> mLastSystemClockTime;
- private boolean mLastSystemClockTimeSendNetworkBroadcast;
+ @Nullable private TimestampedValue<Long> mLastAutoSystemClockTime;
+ private boolean mLastAutoSystemClockTimeSendNetworkBroadcast;
// System clock state.
- @Nullable private TimestampedValue<Long> mLastSystemClockTimeSet;
+ @Nullable private TimestampedValue<Long> mLastAutoSystemClockTimeSet;
@Override
public void initialize(@NonNull Callback callback) {
@@ -67,23 +83,29 @@ public final class SimpleTimeDetectorStrategy implements TimeDetectorStrategy {
public void suggestPhoneTime(@NonNull PhoneTimeSuggestion timeSuggestion) {
// NITZ logic
+ // Empty suggestions are just ignored as we don't currently keep track of suggestion origin.
+ if (timeSuggestion.getUtcTime() == null) {
+ return;
+ }
+
boolean timeSuggestionIsValid =
validateNewPhoneSuggestion(timeSuggestion, mLastPhoneSuggestion);
if (!timeSuggestionIsValid) {
return;
}
// Always store the last NITZ value received, regardless of whether we go on to use it to
- // update the system clock. This is so that we can validate future NITZ signals.
+ // update the system clock. This is so that we can validate future phone suggestions.
mLastPhoneSuggestion = timeSuggestion;
// System clock update logic.
+ final TimestampedValue<Long> newUtcTime = timeSuggestion.getUtcTime();
+ setSystemClockIfRequired(ORIGIN_PHONE, newUtcTime, timeSuggestion);
+ }
- // Historically, Android has sent a telephony broadcast only when setting the time using
- // NITZ.
- final boolean sendNetworkBroadcast = true;
-
+ @Override
+ public void suggestManualTime(ManualTimeSuggestion timeSuggestion) {
final TimestampedValue<Long> newUtcTime = timeSuggestion.getUtcTime();
- setSystemClockIfRequired(newUtcTime, sendNetworkBroadcast);
+ setSystemClockIfRequired(ORIGIN_MANUAL, newUtcTime, timeSuggestion);
}
private static boolean validateNewPhoneSuggestion(@NonNull PhoneTimeSuggestion newSuggestion,
@@ -105,16 +127,31 @@ public final class SimpleTimeDetectorStrategy implements TimeDetectorStrategy {
}
private void setSystemClockIfRequired(
- TimestampedValue<Long> time, boolean sendNetworkBroadcast) {
-
- // Store the last candidate we've seen in all cases so we can set the system clock
- // when/if time detection is enabled.
- mLastSystemClockTime = time;
- mLastSystemClockTimeSendNetworkBroadcast = sendNetworkBroadcast;
-
- if (!mCallback.isTimeDetectionEnabled()) {
- Slog.d(TAG, "setSystemClockIfRequired: Time detection is not enabled. time=" + time);
- return;
+ @Origin int origin, TimestampedValue<Long> time, Object cause) {
+ // Historically, Android has sent a TelephonyIntents.ACTION_NETWORK_SET_TIME broadcast only
+ // when setting the time using NITZ.
+ boolean sendNetworkBroadcast = origin == ORIGIN_PHONE;
+
+ boolean isOriginAutomatic = isOriginAutomatic(origin);
+ if (isOriginAutomatic) {
+ // Store the last auto time candidate we've seen in all cases so we can set the system
+ // clock when/if time detection is off but later enabled.
+ mLastAutoSystemClockTime = time;
+ mLastAutoSystemClockTimeSendNetworkBroadcast = sendNetworkBroadcast;
+
+ if (!mCallback.isAutoTimeDetectionEnabled()) {
+ Slog.d(TAG, "setSystemClockIfRequired: Auto time detection is not enabled."
+ + " time=" + time
+ + ", cause=" + cause);
+ return;
+ }
+ } else {
+ if (mCallback.isAutoTimeDetectionEnabled()) {
+ Slog.d(TAG, "setSystemClockIfRequired: Auto time detection is enabled."
+ + " time=" + time
+ + ", cause=" + cause);
+ return;
+ }
}
mCallback.acquireWakeLock();
@@ -122,37 +159,44 @@ public final class SimpleTimeDetectorStrategy implements TimeDetectorStrategy {
long elapsedRealtimeMillis = mCallback.elapsedRealtimeMillis();
long actualTimeMillis = mCallback.systemClockMillis();
- // CLOCK_PARANOIA : Check to see if this class owns the clock or if something else
- // may be setting the clock.
- if (mLastSystemClockTimeSet != null) {
- long expectedTimeMillis = TimeDetectorStrategy.getTimeAt(
- mLastSystemClockTimeSet, elapsedRealtimeMillis);
- long absSystemClockDifference = Math.abs(expectedTimeMillis - actualTimeMillis);
- if (absSystemClockDifference > SYSTEM_CLOCK_PARANOIA_THRESHOLD_MILLIS) {
- Slog.w(TAG, "System clock has not tracked elapsed real time clock. A clock may"
- + " be inaccurate or something unexpectedly set the system clock."
- + " elapsedRealtimeMillis=" + elapsedRealtimeMillis
- + " expectedTimeMillis=" + expectedTimeMillis
- + " actualTimeMillis=" + actualTimeMillis);
+ if (isOriginAutomatic) {
+ // CLOCK_PARANOIA : Check to see if this class owns the clock or if something else
+ // may be setting the clock.
+ if (mLastAutoSystemClockTimeSet != null) {
+ long expectedTimeMillis = TimeDetectorStrategy.getTimeAt(
+ mLastAutoSystemClockTimeSet, elapsedRealtimeMillis);
+ long absSystemClockDifference = Math.abs(expectedTimeMillis - actualTimeMillis);
+ if (absSystemClockDifference > SYSTEM_CLOCK_PARANOIA_THRESHOLD_MILLIS) {
+ Slog.w(TAG,
+ "System clock has not tracked elapsed real time clock. A clock may"
+ + " be inaccurate or something unexpectedly set the system"
+ + " clock."
+ + " elapsedRealtimeMillis=" + elapsedRealtimeMillis
+ + " expectedTimeMillis=" + expectedTimeMillis
+ + " actualTimeMillis=" + actualTimeMillis);
+ }
}
}
- final String reason = "New time signal";
adjustAndSetDeviceSystemClock(
- time, sendNetworkBroadcast, elapsedRealtimeMillis, actualTimeMillis, reason);
+ time, sendNetworkBroadcast, elapsedRealtimeMillis, actualTimeMillis, cause);
} finally {
mCallback.releaseWakeLock();
}
}
+ private static boolean isOriginAutomatic(@Origin int origin) {
+ return origin == ORIGIN_PHONE;
+ }
+
@Override
public void handleAutoTimeDetectionToggle(boolean enabled) {
// If automatic time detection is enabled we update the system clock instantly if we can.
// Conversely, if automatic time detection is disabled we leave the clock as it is.
if (enabled) {
- if (mLastSystemClockTime != null) {
+ if (mLastAutoSystemClockTime != null) {
// Only send the network broadcast if the last candidate would have caused one.
- final boolean sendNetworkBroadcast = mLastSystemClockTimeSendNetworkBroadcast;
+ final boolean sendNetworkBroadcast = mLastAutoSystemClockTimeSendNetworkBroadcast;
mCallback.acquireWakeLock();
try {
@@ -160,7 +204,7 @@ public final class SimpleTimeDetectorStrategy implements TimeDetectorStrategy {
long actualTimeMillis = mCallback.systemClockMillis();
final String reason = "Automatic time detection enabled.";
- adjustAndSetDeviceSystemClock(mLastSystemClockTime, sendNetworkBroadcast,
+ adjustAndSetDeviceSystemClock(mLastAutoSystemClockTime, sendNetworkBroadcast,
elapsedRealtimeMillis, actualTimeMillis, reason);
} finally {
mCallback.releaseWakeLock();
@@ -169,22 +213,22 @@ public final class SimpleTimeDetectorStrategy implements TimeDetectorStrategy {
} else {
// CLOCK_PARANOIA: We are losing "control" of the system clock so we cannot predict what
// it should be in future.
- mLastSystemClockTimeSet = null;
+ mLastAutoSystemClockTimeSet = null;
}
}
@Override
public void dump(@NonNull PrintWriter pw, @Nullable String[] args) {
pw.println("mLastPhoneSuggestion=" + mLastPhoneSuggestion);
- pw.println("mLastSystemClockTimeSet=" + mLastSystemClockTimeSet);
- pw.println("mLastSystemClockTime=" + mLastSystemClockTime);
- pw.println("mLastSystemClockTimeSendNetworkBroadcast="
- + mLastSystemClockTimeSendNetworkBroadcast);
+ pw.println("mLastAutoSystemClockTimeSet=" + mLastAutoSystemClockTimeSet);
+ pw.println("mLastAutoSystemClockTime=" + mLastAutoSystemClockTime);
+ pw.println("mLastAutoSystemClockTimeSendNetworkBroadcast="
+ + mLastAutoSystemClockTimeSendNetworkBroadcast);
}
private void adjustAndSetDeviceSystemClock(
TimestampedValue<Long> newTime, boolean sendNetworkBroadcast,
- long elapsedRealtimeMillis, long actualSystemClockMillis, String reason) {
+ long elapsedRealtimeMillis, long actualSystemClockMillis, Object cause) {
// Adjust for the time that has elapsed since the signal was received.
long newSystemClockMillis = TimeDetectorStrategy.getTimeAt(newTime, elapsedRealtimeMillis);
@@ -198,20 +242,20 @@ public final class SimpleTimeDetectorStrategy implements TimeDetectorStrategy {
+ " system clock are close enough."
+ " elapsedRealtimeMillis=" + elapsedRealtimeMillis
+ " newTime=" + newTime
- + " reason=" + reason
+ + " cause=" + cause
+ " systemClockUpdateThreshold=" + systemClockUpdateThreshold
+ " absTimeDifference=" + absTimeDifference);
return;
}
Slog.d(TAG, "Setting system clock using time=" + newTime
- + " reason=" + reason
+ + " cause=" + cause
+ " elapsedRealtimeMillis=" + elapsedRealtimeMillis
+ " newTimeMillis=" + newSystemClockMillis);
mCallback.setSystemClock(newSystemClockMillis);
// CLOCK_PARANOIA : Record the last time this class set the system clock.
- mLastSystemClockTimeSet = newTime;
+ mLastAutoSystemClockTimeSet = newTime;
if (sendNetworkBroadcast) {
// Send a broadcast that telephony code used to send after setting the clock.
diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorService.java b/services/core/java/com/android/server/timedetector/TimeDetectorService.java
index ee42279f7d50..7f5b4030306f 100644
--- a/services/core/java/com/android/server/timedetector/TimeDetectorService.java
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorService.java
@@ -19,6 +19,7 @@ package com.android.server.timedetector;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.timedetector.ITimeDetectorService;
+import android.app.timedetector.ManualTimeSuggestion;
import android.app.timedetector.PhoneTimeSuggestion;
import android.content.ContentResolver;
import android.content.Context;
@@ -97,7 +98,7 @@ public final class TimeDetectorService extends ITimeDetectorService.Stub {
@Override
public void suggestPhoneTime(@NonNull PhoneTimeSuggestion timeSignal) {
- enforceSetTimePermission();
+ enforceSuggestPhoneTimePermission();
Objects.requireNonNull(timeSignal);
long idToken = Binder.clearCallingIdentity();
@@ -110,10 +111,25 @@ public final class TimeDetectorService extends ITimeDetectorService.Stub {
}
}
+ @Override
+ public void suggestManualTime(@NonNull ManualTimeSuggestion timeSignal) {
+ enforceSuggestManualTimePermission();
+ Objects.requireNonNull(timeSignal);
+
+ long idToken = Binder.clearCallingIdentity();
+ try {
+ synchronized (mStrategyLock) {
+ mTimeDetectorStrategy.suggestManualTime(timeSignal);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(idToken);
+ }
+ }
+
@VisibleForTesting
public void handleAutoTimeDetectionToggle() {
synchronized (mStrategyLock) {
- final boolean timeDetectionEnabled = mCallback.isTimeDetectionEnabled();
+ final boolean timeDetectionEnabled = mCallback.isAutoTimeDetectionEnabled();
mTimeDetectorStrategy.handleAutoTimeDetectionToggle(timeDetectionEnabled);
}
}
@@ -128,7 +144,11 @@ public final class TimeDetectorService extends ITimeDetectorService.Stub {
}
}
- private void enforceSetTimePermission() {
+ private void enforceSuggestPhoneTimePermission() {
mContext.enforceCallingPermission(android.Manifest.permission.SET_TIME, "set time");
}
-} \ No newline at end of file
+
+ private void enforceSuggestManualTimePermission() {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.SET_TIME, "set time");
+ }
+}
diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java b/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java
index 7c2a945854f5..b60cebf57b45 100644
--- a/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java
@@ -18,6 +18,7 @@ package com.android.server.timedetector;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.app.timedetector.ManualTimeSuggestion;
import android.app.timedetector.PhoneTimeSuggestion;
import android.content.Intent;
import android.util.TimestampedValue;
@@ -47,7 +48,7 @@ public interface TimeDetectorStrategy {
int systemClockUpdateThresholdMillis();
/** Returns true if automatic time detection is enabled. */
- boolean isTimeDetectionEnabled();
+ boolean isAutoTimeDetectionEnabled();
/** Acquire a suitable wake lock. Must be followed by {@link #releaseWakeLock()} */
void acquireWakeLock();
@@ -71,9 +72,12 @@ public interface TimeDetectorStrategy {
/** Initialize the strategy. */
void initialize(@NonNull Callback callback);
- /** Process the suggested time. */
+ /** Process the suggested time from telephony sources. */
void suggestPhoneTime(@NonNull PhoneTimeSuggestion timeSuggestion);
+ /** Process the suggested manually entered time. */
+ void suggestManualTime(@NonNull ManualTimeSuggestion timeSuggestion);
+
/** Handle the auto-time setting being toggled on or off. */
void handleAutoTimeDetectionToggle(boolean enabled);
diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorStrategyCallbackImpl.java b/services/core/java/com/android/server/timedetector/TimeDetectorStrategyCallbackImpl.java
index 77b9e6281086..42d59d51c6af 100644
--- a/services/core/java/com/android/server/timedetector/TimeDetectorStrategyCallbackImpl.java
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorStrategyCallbackImpl.java
@@ -72,7 +72,7 @@ public final class TimeDetectorStrategyCallbackImpl implements TimeDetectorStrat
}
@Override
- public boolean isTimeDetectionEnabled() {
+ public boolean isAutoTimeDetectionEnabled() {
try {
return Settings.Global.getInt(mContentResolver, Settings.Global.AUTO_TIME) != 0;
} catch (Settings.SettingNotFoundException snfe) {
diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorCallbackImpl.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorCallbackImpl.java
new file mode 100644
index 000000000000..23746aca4c87
--- /dev/null
+++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorCallbackImpl.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.timezonedetector;
+
+import android.annotation.Nullable;
+import android.app.AlarmManager;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.os.SystemProperties;
+import android.os.UserHandle;
+import android.provider.Settings;
+
+import com.android.internal.telephony.TelephonyIntents;
+
+/**
+ * The real implementation of {@link TimeZoneDetectorStrategy.Callback}.
+ */
+public final class TimeZoneDetectorCallbackImpl implements TimeZoneDetectorStrategy.Callback {
+
+ private static final String TIMEZONE_PROPERTY = "persist.sys.timezone";
+
+ private final Context mContext;
+ private final ContentResolver mCr;
+
+ TimeZoneDetectorCallbackImpl(Context context) {
+ mContext = context;
+ mCr = context.getContentResolver();
+ }
+
+ @Override
+ public boolean isTimeZoneDetectionEnabled() {
+ return Settings.Global.getInt(mCr, Settings.Global.AUTO_TIME_ZONE, 1 /* default */) > 0;
+ }
+
+ @Override
+ public boolean isDeviceTimeZoneInitialized() {
+ // timezone.equals("GMT") will be true and only true if the time zone was
+ // set to a default value by the system server (when starting, system server
+ // sets the persist.sys.timezone to "GMT" if it's not set). "GMT" is not used by
+ // any code that sets it explicitly (in case where something sets GMT explicitly,
+ // "Etc/GMT" Olson ID would be used).
+
+ String timeZoneId = getDeviceTimeZone();
+ return timeZoneId != null && timeZoneId.length() > 0 && !timeZoneId.equals("GMT");
+ }
+
+ @Override
+ @Nullable
+ public String getDeviceTimeZone() {
+ return SystemProperties.get(TIMEZONE_PROPERTY);
+ }
+
+ @Override
+ public void setDeviceTimeZone(String zoneId) {
+ AlarmManager alarmManager = mContext.getSystemService(AlarmManager.class);
+ alarmManager.setTimeZone(zoneId);
+
+ // TODO Nothing in the platform appears to listen for this. Remove it.
+ Intent intent = new Intent(TelephonyIntents.ACTION_NETWORK_SET_TIMEZONE);
+ intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
+ intent.putExtra("time-zone", zoneId);
+ mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
+ }
+}
diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java
new file mode 100644
index 000000000000..558aa9e98f43
--- /dev/null
+++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.timezonedetector;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.timezonedetector.ITimeZoneDetectorService;
+import android.app.timezonedetector.PhoneTimeZoneSuggestion;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.database.ContentObserver;
+import android.os.Handler;
+import android.provider.Settings;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.DumpUtils;
+import com.android.internal.util.IndentingPrintWriter;
+import com.android.server.FgThread;
+import com.android.server.SystemService;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.Objects;
+
+/**
+ * The implementation of ITimeZoneDetectorService.aidl.
+ */
+public final class TimeZoneDetectorService extends ITimeZoneDetectorService.Stub {
+ private static final String TAG = "TimeZoneDetectorService";
+
+ /**
+ * Handles the lifecycle for {@link TimeZoneDetectorService}.
+ */
+ public static class Lifecycle extends SystemService {
+
+ public Lifecycle(@NonNull Context context) {
+ super(context);
+ }
+
+ @Override
+ public void onStart() {
+ TimeZoneDetectorService service = TimeZoneDetectorService.create(getContext());
+
+ // Publish the binder service so it can be accessed from other (appropriately
+ // permissioned) processes.
+ publishBinderService(Context.TIME_ZONE_DETECTOR_SERVICE, service);
+ }
+ }
+
+ @NonNull private final Context mContext;
+ @NonNull private final Handler mHandler;
+ @NonNull private final TimeZoneDetectorStrategy mTimeZoneDetectorStrategy;
+
+ private static TimeZoneDetectorService create(@NonNull Context context) {
+ final TimeZoneDetectorStrategy timeZoneDetectorStrategy =
+ TimeZoneDetectorStrategy.create(context);
+
+ Handler handler = FgThread.getHandler();
+ ContentResolver contentResolver = context.getContentResolver();
+ contentResolver.registerContentObserver(
+ Settings.Global.getUriFor(Settings.Global.AUTO_TIME_ZONE), true,
+ new ContentObserver(handler) {
+ public void onChange(boolean selfChange) {
+ timeZoneDetectorStrategy.handleTimeZoneDetectionChange();
+ }
+ });
+
+ return new TimeZoneDetectorService(context, handler, timeZoneDetectorStrategy);
+ }
+
+ @VisibleForTesting
+ public TimeZoneDetectorService(@NonNull Context context, @NonNull Handler handler,
+ @NonNull TimeZoneDetectorStrategy timeZoneDetectorStrategy) {
+ mContext = Objects.requireNonNull(context);
+ mHandler = Objects.requireNonNull(handler);
+ mTimeZoneDetectorStrategy = Objects.requireNonNull(timeZoneDetectorStrategy);
+ }
+
+ @Override
+ public void suggestPhoneTimeZone(@NonNull PhoneTimeZoneSuggestion timeZoneSuggestion) {
+ enforceSetTimeZonePermission();
+ Objects.requireNonNull(timeZoneSuggestion);
+
+ mHandler.post(() -> mTimeZoneDetectorStrategy.suggestPhoneTimeZone(timeZoneSuggestion));
+ }
+
+ @Override
+ protected void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw,
+ @Nullable String[] args) {
+ if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
+
+ mTimeZoneDetectorStrategy.dumpState(pw);
+ mTimeZoneDetectorStrategy.dumpLogs(new IndentingPrintWriter(pw, " "));
+ }
+
+ private void enforceSetTimeZonePermission() {
+ mContext.enforceCallingPermission(
+ android.Manifest.permission.SET_TIME_ZONE, "set time zone");
+ }
+}
+
diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java
new file mode 100644
index 000000000000..e24c089ae862
--- /dev/null
+++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java
@@ -0,0 +1,507 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.timezonedetector;
+
+import static android.app.timezonedetector.PhoneTimeZoneSuggestion.MATCH_TYPE_EMULATOR_ZONE_ID;
+import static android.app.timezonedetector.PhoneTimeZoneSuggestion.MATCH_TYPE_TEST_NETWORK_OFFSET_ONLY;
+import static android.app.timezonedetector.PhoneTimeZoneSuggestion.QUALITY_MULTIPLE_ZONES_WITH_DIFFERENT_OFFSETS;
+import static android.app.timezonedetector.PhoneTimeZoneSuggestion.QUALITY_MULTIPLE_ZONES_WITH_SAME_OFFSET;
+import static android.app.timezonedetector.PhoneTimeZoneSuggestion.QUALITY_SINGLE_ZONE;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.timezonedetector.PhoneTimeZoneSuggestion;
+import android.content.Context;
+import android.util.ArrayMap;
+import android.util.LocalLog;
+import android.util.Slog;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.IndentingPrintWriter;
+
+import java.io.PrintWriter;
+import java.util.LinkedList;
+import java.util.Map;
+import java.util.Objects;
+
+/**
+ * A singleton, stateful time zone detection strategy that is aware of multiple phone devices. It
+ * keeps track of the most recent suggestion from each phone and it uses the best based on a scoring
+ * algorithm. If several phones provide the same score then the phone with the lowest numeric ID
+ * "wins". If the situation changes and it is no longer possible to be confident about the time
+ * zone, phones must submit an empty suggestion in order to "withdraw" their previous suggestion.
+ */
+public class TimeZoneDetectorStrategy {
+
+ /**
+ * Used by {@link TimeZoneDetectorStrategy} to interact with the surrounding service. It can be
+ * faked for tests.
+ */
+ @VisibleForTesting
+ public interface Callback {
+
+ /**
+ * Returns true if automatic time zone detection is enabled in settings.
+ */
+ boolean isTimeZoneDetectionEnabled();
+
+ /**
+ * Returns true if the device has had an explicit time zone set.
+ */
+ boolean isDeviceTimeZoneInitialized();
+
+ /**
+ * Returns the device's currently configured time zone.
+ */
+ String getDeviceTimeZone();
+
+ /**
+ * Sets the device's time zone.
+ */
+ void setDeviceTimeZone(@NonNull String zoneId);
+ }
+
+ static final String LOG_TAG = "TimeZoneDetectorStrategy";
+ static final boolean DBG = false;
+
+ /**
+ * The abstract score for an empty or invalid suggestion.
+ *
+ * Used to score suggestions where there is no zone.
+ */
+ @VisibleForTesting
+ public static final int SCORE_NONE = 0;
+
+ /**
+ * The abstract score for a low quality suggestion.
+ *
+ * Used to score suggestions where:
+ * The suggested zone ID is one of several possibilities, and the possibilities have different
+ * offsets.
+ *
+ * You would have to be quite desperate to want to use this choice.
+ */
+ @VisibleForTesting
+ public static final int SCORE_LOW = 1;
+
+ /**
+ * The abstract score for a medium quality suggestion.
+ *
+ * Used for:
+ * The suggested zone ID is one of several possibilities but at least the possibilities have the
+ * same offset. Users would get the correct time but for the wrong reason. i.e. their device may
+ * switch to DST at the wrong time and (for example) their calendar events.
+ */
+ @VisibleForTesting
+ public static final int SCORE_MEDIUM = 2;
+
+ /**
+ * The abstract score for a high quality suggestion.
+ *
+ * Used for:
+ * The suggestion was for one zone ID and the answer was unambiguous and likely correct given
+ * the info available.
+ */
+ @VisibleForTesting
+ public static final int SCORE_HIGH = 3;
+
+ /**
+ * The abstract score for a highest quality suggestion.
+ *
+ * Used for:
+ * Suggestions that must "win" because they constitute test or emulator zone ID.
+ */
+ @VisibleForTesting
+ public static final int SCORE_HIGHEST = 4;
+
+ /** The threshold at which suggestions are good enough to use to set the device's time zone. */
+ @VisibleForTesting
+ public static final int SCORE_USAGE_THRESHOLD = SCORE_MEDIUM;
+
+ /** The number of previous phone suggestions to keep for each ID (for use during debugging). */
+ private static final int KEEP_SUGGESTION_HISTORY_SIZE = 30;
+
+ @NonNull
+ private final Callback mCallback;
+
+ /**
+ * A log that records the decisions / decision metadata that affected the device's time zone
+ * (for use during debugging).
+ */
+ @NonNull
+ private final LocalLog mTimeZoneChangesLog = new LocalLog(30);
+
+ /**
+ * A mapping from phoneId to a linked list of time zone suggestions (the head being the latest).
+ * We typically expect one or two entries in this Map: devices will have a small number
+ * of telephony devices and phoneIds are assumed to be stable. The LinkedList associated with
+ * the ID will not exceed {@link #KEEP_SUGGESTION_HISTORY_SIZE} in size.
+ */
+ @GuardedBy("this")
+ private ArrayMap<Integer, LinkedList<QualifiedPhoneTimeZoneSuggestion>> mSuggestionByPhoneId =
+ new ArrayMap<>();
+
+ /**
+ * The most recent best guess of time zone from all phones. Can be {@code null} to indicate
+ * there would be no current suggestion.
+ */
+ @GuardedBy("this")
+ @Nullable
+ private QualifiedPhoneTimeZoneSuggestion mCurrentSuggestion;
+
+ /**
+ * Creates a new instance of {@link TimeZoneDetectorStrategy}.
+ */
+ public static TimeZoneDetectorStrategy create(Context context) {
+ Callback timeZoneDetectionServiceHelper = new TimeZoneDetectorCallbackImpl(context);
+ return new TimeZoneDetectorStrategy(timeZoneDetectionServiceHelper);
+ }
+
+ @VisibleForTesting
+ public TimeZoneDetectorStrategy(Callback callback) {
+ mCallback = Objects.requireNonNull(callback);
+ }
+
+ /**
+ * Suggests a time zone for the device, or withdraws a previous suggestion if
+ * {@link PhoneTimeZoneSuggestion#getZoneId()} is {@code null}. The suggestion is scoped to a
+ * specific {@link PhoneTimeZoneSuggestion#getPhoneId() phone}.
+ * See {@link PhoneTimeZoneSuggestion} for an explanation of the metadata associated with a
+ * suggestion. The service uses suggestions to decide whether to modify the device's time zone
+ * setting and what to set it to.
+ */
+ public synchronized void suggestPhoneTimeZone(@NonNull PhoneTimeZoneSuggestion newSuggestion) {
+ if (DBG) {
+ Slog.d(LOG_TAG, "suggestPhoneTimeZone: newSuggestion=" + newSuggestion);
+ }
+ Objects.requireNonNull(newSuggestion);
+
+ int score = scoreSuggestion(newSuggestion);
+ QualifiedPhoneTimeZoneSuggestion scoredSuggestion =
+ new QualifiedPhoneTimeZoneSuggestion(newSuggestion, score);
+
+ // Record the suggestion against the correct phoneId.
+ LinkedList<QualifiedPhoneTimeZoneSuggestion> suggestions =
+ mSuggestionByPhoneId.get(newSuggestion.getPhoneId());
+ if (suggestions == null) {
+ suggestions = new LinkedList<>();
+ mSuggestionByPhoneId.put(newSuggestion.getPhoneId(), suggestions);
+ }
+ suggestions.addFirst(scoredSuggestion);
+ if (suggestions.size() > KEEP_SUGGESTION_HISTORY_SIZE) {
+ suggestions.removeLast();
+ }
+
+ // Now run the competition between the phones' suggestions.
+ doTimeZoneDetection();
+ }
+
+ private static int scoreSuggestion(@NonNull PhoneTimeZoneSuggestion suggestion) {
+ int score;
+ if (suggestion.getZoneId() == null) {
+ score = SCORE_NONE;
+ } else if (suggestion.getMatchType() == MATCH_TYPE_TEST_NETWORK_OFFSET_ONLY
+ || suggestion.getMatchType() == MATCH_TYPE_EMULATOR_ZONE_ID) {
+ // Handle emulator / test cases : These suggestions should always just be used.
+ score = SCORE_HIGHEST;
+ } else if (suggestion.getQuality() == QUALITY_SINGLE_ZONE) {
+ score = SCORE_HIGH;
+ } else if (suggestion.getQuality() == QUALITY_MULTIPLE_ZONES_WITH_SAME_OFFSET) {
+ // The suggestion may be wrong, but at least the offset should be correct.
+ score = SCORE_MEDIUM;
+ } else if (suggestion.getQuality() == QUALITY_MULTIPLE_ZONES_WITH_DIFFERENT_OFFSETS) {
+ // The suggestion has a good chance of being wrong.
+ score = SCORE_LOW;
+ } else {
+ throw new AssertionError();
+ }
+ return score;
+ }
+
+ /**
+ * Finds the best available time zone suggestion from all phones. If it is high-enough quality
+ * and automatic time zone detection is enabled then it will be set on the device. The outcome
+ * can be that this service becomes / remains un-opinionated and nothing is set.
+ */
+ @GuardedBy("this")
+ private void doTimeZoneDetection() {
+ QualifiedPhoneTimeZoneSuggestion bestSuggestion = findBestSuggestion();
+ boolean timeZoneDetectionEnabled = mCallback.isTimeZoneDetectionEnabled();
+
+ // Work out what to do with the best suggestion.
+ if (bestSuggestion == null) {
+ // There is no suggestion. Become un-opinionated.
+ if (DBG) {
+ Slog.d(LOG_TAG, "doTimeZoneDetection: No good suggestion."
+ + " bestSuggestion=null"
+ + ", timeZoneDetectionEnabled=" + timeZoneDetectionEnabled);
+ }
+ mCurrentSuggestion = null;
+ return;
+ }
+
+ // Special case handling for uninitialized devices. This should only happen once.
+ String newZoneId = bestSuggestion.suggestion.getZoneId();
+ if (newZoneId != null && !mCallback.isDeviceTimeZoneInitialized()) {
+ Slog.i(LOG_TAG, "doTimeZoneDetection: Device has no time zone set so might set the"
+ + " device to the best available suggestion."
+ + " bestSuggestion=" + bestSuggestion
+ + ", timeZoneDetectionEnabled=" + timeZoneDetectionEnabled);
+
+ mCurrentSuggestion = bestSuggestion;
+ if (timeZoneDetectionEnabled) {
+ setDeviceTimeZone(bestSuggestion.suggestion);
+ }
+ return;
+ }
+
+ boolean suggestionGoodEnough = bestSuggestion.score >= SCORE_USAGE_THRESHOLD;
+ if (!suggestionGoodEnough) {
+ if (DBG) {
+ Slog.d(LOG_TAG, "doTimeZoneDetection: Suggestion not good enough."
+ + " bestSuggestion=" + bestSuggestion);
+ }
+ mCurrentSuggestion = null;
+ return;
+ }
+
+ // Paranoia: Every suggestion above the SCORE_USAGE_THRESHOLD should have a non-null time
+ // zone ID.
+ if (newZoneId == null) {
+ Slog.w(LOG_TAG, "Empty zone suggestion scored higher than expected. This is an error:"
+ + " bestSuggestion=" + bestSuggestion);
+ mCurrentSuggestion = null;
+ return;
+ }
+
+ // There is a good suggestion. Store the suggestion and set the device time zone if
+ // settings allow.
+ mCurrentSuggestion = bestSuggestion;
+
+ // Only set the device time zone if time zone detection is enabled.
+ if (!timeZoneDetectionEnabled) {
+ if (DBG) {
+ Slog.d(LOG_TAG, "doTimeZoneDetection: Not setting the time zone because time zone"
+ + " detection is disabled."
+ + " bestSuggestion=" + bestSuggestion);
+ }
+ return;
+ }
+ PhoneTimeZoneSuggestion suggestion = bestSuggestion.suggestion;
+ setDeviceTimeZone(suggestion);
+ }
+
+ private void setDeviceTimeZone(@NonNull PhoneTimeZoneSuggestion suggestion) {
+ String currentZoneId = mCallback.getDeviceTimeZone();
+ String newZoneId = suggestion.getZoneId();
+
+ // Paranoia: This should never happen.
+ if (newZoneId == null) {
+ Slog.w(LOG_TAG, "setDeviceTimeZone: Suggested zone is null."
+ + " timeZoneSuggestion=" + suggestion);
+ return;
+ }
+
+ // Avoid unnecessary changes / intents.
+ if (newZoneId.equals(currentZoneId)) {
+ // No need to set the device time zone - the setting is already what we would be
+ // suggesting.
+ if (DBG) {
+ Slog.d(LOG_TAG, "setDeviceTimeZone: No need to change the time zone;"
+ + " device is already set to the suggested zone."
+ + " timeZoneSuggestion=" + suggestion);
+ }
+ return;
+ }
+
+ String msg = "Changing device time zone. currentZoneId=" + currentZoneId
+ + ", timeZoneSuggestion=" + suggestion;
+ if (DBG) {
+ Slog.d(LOG_TAG, msg);
+ }
+ mTimeZoneChangesLog.log(msg);
+ mCallback.setDeviceTimeZone(newZoneId);
+ }
+
+ @GuardedBy("this")
+ @Nullable
+ private QualifiedPhoneTimeZoneSuggestion findBestSuggestion() {
+ QualifiedPhoneTimeZoneSuggestion bestSuggestion = null;
+
+ // Iterate over the latest QualifiedPhoneTimeZoneSuggestion objects received for each phone
+ // and find the best. Note that we deliberately do not look at age: the caller can
+ // rate-limit so age is not a strong indicator of confidence. Instead, the callers are
+ // expected to withdraw suggestions they no longer have confidence in.
+ for (int i = 0; i < mSuggestionByPhoneId.size(); i++) {
+ LinkedList<QualifiedPhoneTimeZoneSuggestion> phoneSuggestions =
+ mSuggestionByPhoneId.valueAt(i);
+ if (phoneSuggestions == null) {
+ // Unexpected
+ continue;
+ }
+ QualifiedPhoneTimeZoneSuggestion candidateSuggestion = phoneSuggestions.getFirst();
+ if (candidateSuggestion == null) {
+ // Unexpected
+ continue;
+ }
+
+ if (bestSuggestion == null) {
+ bestSuggestion = candidateSuggestion;
+ } else if (candidateSuggestion.score > bestSuggestion.score) {
+ bestSuggestion = candidateSuggestion;
+ } else if (candidateSuggestion.score == bestSuggestion.score) {
+ // Tie! Use the suggestion with the lowest phoneId.
+ int candidatePhoneId = candidateSuggestion.suggestion.getPhoneId();
+ int bestPhoneId = bestSuggestion.suggestion.getPhoneId();
+ if (candidatePhoneId < bestPhoneId) {
+ bestSuggestion = candidateSuggestion;
+ }
+ }
+ }
+ return bestSuggestion;
+ }
+
+ /**
+ * Returns the current best suggestion. Not intended for general use: it is used during tests
+ * to check service behavior.
+ */
+ @VisibleForTesting
+ @Nullable
+ public synchronized QualifiedPhoneTimeZoneSuggestion findBestSuggestionForTests() {
+ return findBestSuggestion();
+ }
+
+ /**
+ * Called when the has been a change to the automatic time zone detection setting.
+ */
+ @VisibleForTesting
+ public synchronized void handleTimeZoneDetectionChange() {
+ if (DBG) {
+ Slog.d(LOG_TAG, "handleTimeZoneDetectionChange() called");
+ }
+ if (mCallback.isTimeZoneDetectionEnabled()) {
+ // When the user enabled time zone detection, run the time zone detection and change the
+ // device time zone if possible.
+ doTimeZoneDetection();
+ }
+ }
+
+ /**
+ * Dumps any logs held to the supplied writer.
+ */
+ public synchronized void dumpLogs(IndentingPrintWriter ipw) {
+ ipw.println("TimeZoneDetectorStrategy:");
+
+ ipw.increaseIndent(); // level 1
+
+ ipw.println("Time zone change log:");
+ ipw.increaseIndent(); // level 2
+ mTimeZoneChangesLog.dump(ipw);
+ ipw.decreaseIndent(); // level 2
+
+ ipw.println("Phone suggestion history:");
+ ipw.increaseIndent(); // level 2
+ for (Map.Entry<Integer, LinkedList<QualifiedPhoneTimeZoneSuggestion>> entry
+ : mSuggestionByPhoneId.entrySet()) {
+ ipw.println("Phone " + entry.getKey());
+
+ ipw.increaseIndent(); // level 3
+ for (QualifiedPhoneTimeZoneSuggestion suggestion : entry.getValue()) {
+ ipw.println(suggestion);
+ }
+ ipw.decreaseIndent(); // level 3
+ }
+ ipw.decreaseIndent(); // level 2
+ ipw.decreaseIndent(); // level 1
+ }
+
+ /**
+ * Dumps internal state such as field values.
+ */
+ public synchronized void dumpState(PrintWriter pw) {
+ pw.println("mCurrentSuggestion=" + mCurrentSuggestion);
+ pw.println("mCallback.isTimeZoneDetectionEnabled()="
+ + mCallback.isTimeZoneDetectionEnabled());
+ pw.println("mCallback.isDeviceTimeZoneInitialized()="
+ + mCallback.isDeviceTimeZoneInitialized());
+ pw.println("mCallback.getDeviceTimeZone()="
+ + mCallback.getDeviceTimeZone());
+ pw.flush();
+ }
+
+ /**
+ * A method used to inspect service state during tests. Not intended for general use.
+ */
+ @VisibleForTesting
+ public synchronized QualifiedPhoneTimeZoneSuggestion getLatestPhoneSuggestion(int phoneId) {
+ LinkedList<QualifiedPhoneTimeZoneSuggestion> suggestions =
+ mSuggestionByPhoneId.get(phoneId);
+ if (suggestions == null) {
+ return null;
+ }
+ return suggestions.getFirst();
+ }
+
+ /**
+ * A {@link PhoneTimeZoneSuggestion} with additional qualifying metadata.
+ */
+ @VisibleForTesting
+ public static class QualifiedPhoneTimeZoneSuggestion {
+
+ @VisibleForTesting
+ public final PhoneTimeZoneSuggestion suggestion;
+
+ /**
+ * The score the suggestion has been given. This can be used to rank against other
+ * suggestions of the same type.
+ */
+ @VisibleForTesting
+ public final int score;
+
+ @VisibleForTesting
+ public QualifiedPhoneTimeZoneSuggestion(PhoneTimeZoneSuggestion suggestion, int score) {
+ this.suggestion = suggestion;
+ this.score = score;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ QualifiedPhoneTimeZoneSuggestion that = (QualifiedPhoneTimeZoneSuggestion) o;
+ return score == that.score
+ && suggestion.equals(that.suggestion);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(score, suggestion);
+ }
+
+ @Override
+ public String toString() {
+ return "QualifiedPhoneTimeZoneSuggestion{"
+ + "suggestion=" + suggestion
+ + ", score=" + score
+ + '}';
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/wm/ActivityDisplay.java b/services/core/java/com/android/server/wm/ActivityDisplay.java
index be7dfe53c1c1..45e3c689e81e 100644
--- a/services/core/java/com/android/server/wm/ActivityDisplay.java
+++ b/services/core/java/com/android/server/wm/ActivityDisplay.java
@@ -74,7 +74,6 @@ import android.view.Display;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.function.pooled.PooledLambda;
-import com.android.server.am.EventLogTags;
import com.android.server.protolog.common.ProtoLog;
import java.io.PrintWriter;
@@ -299,7 +298,7 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> {
final ActivityStack currentFocusedStack = getFocusedStack();
if (currentFocusedStack != prevFocusedStack) {
mLastFocusedStack = prevFocusedStack;
- EventLogTags.writeAmFocusedStack(mRootActivityContainer.mCurrentUser, mDisplayId,
+ EventLogTags.writeWmFocusedStack(mRootActivityContainer.mCurrentUser, mDisplayId,
currentFocusedStack == null ? -1 : currentFocusedStack.getStackId(),
mLastFocusedStack == null ? -1 : mLastFocusedStack.getStackId(),
updateLastFocusedStackReason);
diff --git a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
index 0a861ade2900..9fa5d9f15f3e 100644
--- a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
@@ -56,13 +56,13 @@ import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_T
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_TRANSITION_REPORTED_DRAWN_NO_BUNDLE;
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_TRANSITION_REPORTED_DRAWN_WITH_BUNDLE;
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_TRANSITION_WARM_LAUNCH;
-import static com.android.server.am.EventLogTags.AM_ACTIVITY_LAUNCH_TIME;
import static com.android.server.am.MemoryStatUtil.MemoryStat;
import static com.android.server.am.MemoryStatUtil.readMemoryStatFromFilesystem;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_METRICS;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.ActivityTaskManagerInternal.APP_TRANSITION_TIMEOUT;
+import static com.android.server.wm.EventLogTags.WM_ACTIVITY_LAUNCH_TIME;
import android.app.WaitResult;
import android.app.WindowConfiguration.WindowingMode;
@@ -805,7 +805,7 @@ class ActivityMetricsLogger {
return;
}
- EventLog.writeEvent(AM_ACTIVITY_LAUNCH_TIME,
+ EventLog.writeEvent(WM_ACTIVITY_LAUNCH_TIME,
info.userId, info.activityRecordIdHashCode, info.launchedActivityShortComponentName,
info.windowsDrawnDelayMs);
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 0acab9cb74c5..b8b5efdea692 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -122,8 +122,6 @@ import static com.android.server.am.ActivityRecordProto.STATE;
import static com.android.server.am.ActivityRecordProto.TRANSLUCENT;
import static com.android.server.am.ActivityRecordProto.VISIBLE;
import static com.android.server.am.ActivityRecordProto.VISIBLE_REQUESTED;
-import static com.android.server.am.EventLogTags.AM_RELAUNCH_ACTIVITY;
-import static com.android.server.am.EventLogTags.AM_RELAUNCH_RESUME_ACTIVITY;
import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM;
import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
import static com.android.server.wm.ActivityStack.ActivityState.DESTROYED;
@@ -306,7 +304,6 @@ import com.android.internal.util.XmlUtils;
import com.android.server.AttributeCache;
import com.android.server.LocalServices;
import com.android.server.am.AppTimeTracker;
-import com.android.server.am.EventLogTags;
import com.android.server.am.PendingIntentRecord;
import com.android.server.display.color.ColorDisplayService;
import com.android.server.policy.WindowManagerPolicy;
@@ -1523,7 +1520,13 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
hasBeenLaunched = false;
mStackSupervisor = supervisor;
- taskAffinity = aInfo.taskAffinity;
+ // b/35954083: Limit task affinity to uid to avoid various issues associated with sharing
+ // affinity across uids.
+ final String uid = Integer.toString(info.applicationInfo.uid);
+ if (info.taskAffinity != null && !info.taskAffinity.startsWith(uid)) {
+ info.taskAffinity = uid + ":" + info.taskAffinity;
+ }
+ taskAffinity = info.taskAffinity;
stateNotNeeded = (aInfo.flags & FLAG_STATE_NOT_NEEDED) != 0;
nonLocalizedLabel = aInfo.nonLocalizedLabel;
labelRes = aInfo.labelRes;
@@ -1801,7 +1804,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// task snapshot starting window.
return STARTING_WINDOW_TYPE_SPLASH_SCREEN;
}
- return snapshot == null ? STARTING_WINDOW_TYPE_SPLASH_SCREEN
+ return snapshot == null ? STARTING_WINDOW_TYPE_NONE
: snapshotOrientationSameAsTask(snapshot) || fromRecents
? STARTING_WINDOW_TYPE_SNAPSHOT : STARTING_WINDOW_TYPE_SPLASH_SCREEN;
} else {
@@ -2379,8 +2382,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// Make a local reference to its task since this.task could be set to null once this
// activity is destroyed and detached from task.
final Task task = getTask();
- EventLog.writeEvent(EventLogTags.AM_FINISH_ACTIVITY,
- mUserId, System.identityHashCode(this),
+ EventLogTags.writeWmFinishActivity(mUserId, System.identityHashCode(this),
task.mTaskId, shortComponentName, reason);
final ArrayList<ActivityRecord> activities = task.mChildren;
final int index = activities.indexOf(this);
@@ -2655,8 +2657,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
return false;
}
- EventLog.writeEvent(EventLogTags.AM_DESTROY_ACTIVITY, mUserId,
- System.identityHashCode(this), task.mTaskId, shortComponentName, reason);
+ EventLogTags.writeWmDestroyActivity(mUserId, System.identityHashCode(this),
+ task.mTaskId, shortComponentName, reason);
final ActivityStack stack = getActivityStack();
if (hasProcess() && !stack.inLruList(this)) {
@@ -4741,7 +4743,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
if (!mVisibleRequested) {
setVisibility(false);
}
- EventLogTags.writeAmStopActivity(
+ EventLogTags.writeWmStopActivity(
mUserId, System.identityHashCode(this), shortComponentName);
mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), appToken,
StopActivityItem.obtain(mVisibleRequested, configChangeFlags));
@@ -4810,8 +4812,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
void addToStopping(boolean scheduleIdle, boolean idleDelayed, String reason) {
if (!mStackSupervisor.mStoppingActivities.contains(this)) {
- EventLog.writeEvent(EventLogTags.AM_ADD_TO_STOPPING, mUserId,
- System.identityHashCode(this), shortComponentName, reason);
+ EventLogTags.writeWmAddToStopping(mUserId, System.identityHashCode(this),
+ shortComponentName, reason);
mStackSupervisor.mStoppingActivities.add(this);
}
@@ -6942,9 +6944,13 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
"Relaunching: " + this + " with results=" + pendingResults
+ " newIntents=" + pendingNewIntents + " andResume=" + andResume
+ " preserveWindow=" + preserveWindow);
- EventLog.writeEvent(andResume ? AM_RELAUNCH_RESUME_ACTIVITY
- : AM_RELAUNCH_ACTIVITY, mUserId, System.identityHashCode(this),
- task.mTaskId, shortComponentName);
+ if (andResume) {
+ EventLogTags.writeWmRelaunchResumeActivity(mUserId, System.identityHashCode(this),
+ task.mTaskId, shortComponentName);
+ } else {
+ EventLogTags.writeWmRelaunchActivity(mUserId, System.identityHashCode(this),
+ task.mTaskId, shortComponentName);
+ }
startFreezingScreenLocked(0);
diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java
index f1c47eb8644c..6ddbb0df2ccc 100644
--- a/services/core/java/com/android/server/wm/ActivityStack.java
+++ b/services/core/java/com/android/server/wm/ActivityStack.java
@@ -84,7 +84,6 @@ import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_SWITCH;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_TASKS;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_TRANSITION;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_USER_LEAVING;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_VISIBILITY;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_ADD_REMOVE;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_APP;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_CLEANUP;
@@ -163,7 +162,6 @@ import android.os.UserHandle;
import android.service.voice.IVoiceInteractionSession;
import android.util.ArraySet;
import android.util.DisplayMetrics;
-import android.util.EventLog;
import android.util.IntArray;
import android.util.Log;
import android.util.Slog;
@@ -185,7 +183,6 @@ import com.android.server.Watchdog;
import com.android.server.am.ActivityManagerService;
import com.android.server.am.ActivityManagerService.ItemMatcher;
import com.android.server.am.AppTimeTracker;
-import com.android.server.am.EventLogTags;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -533,7 +530,7 @@ class ActivityStack extends WindowContainer<Task> implements BoundsAnimationTarg
mDockedStackMinimizeThickness =
supervisor.mService.mWindowManager.mContext.getResources().getDimensionPixelSize(
com.android.internal.R.dimen.docked_stack_minimize_thickness);
- EventLog.writeEvent(com.android.server.EventLogTags.WM_STACK_CREATED, stackId);
+ EventLogTags.writeWmStackCreated(stackId);
mStackSupervisor = supervisor;
mService = supervisor.mService;
mRootActivityContainer = mService.mRootActivityContainer;
@@ -1586,7 +1583,7 @@ class ActivityStack extends WindowContainer<Task> implements BoundsAnimationTarg
if (prev.attachedToProcess()) {
if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Enqueueing pending pause: " + prev);
try {
- EventLogTags.writeAmPauseActivity(prev.mUserId, System.identityHashCode(prev),
+ EventLogTags.writeWmPauseActivity(prev.mUserId, System.identityHashCode(prev),
prev.shortComponentName, "userLeaving=" + userLeaving);
mService.getLifecycleManager().scheduleTransaction(prev.app.getThread(),
@@ -1663,10 +1660,9 @@ class ActivityStack extends WindowContainer<Task> implements BoundsAnimationTarg
}
return;
} else {
- EventLog.writeEvent(EventLogTags.AM_FAILED_TO_PAUSE,
- r.mUserId, System.identityHashCode(r), r.shortComponentName,
- mPausingActivity != null
- ? mPausingActivity.shortComponentName : "(none)");
+ EventLogTags.writeWmFailedToPause(r.mUserId, System.identityHashCode(r),
+ r.shortComponentName, mPausingActivity != null
+ ? mPausingActivity.shortComponentName : "(none)");
if (r.isState(PAUSING)) {
r.setState(PAUSED, "activityPausedLocked");
if (r.finishing) {
@@ -2659,9 +2655,8 @@ class ActivityStack extends WindowContainer<Task> implements BoundsAnimationTarg
// Clear app token stopped state in window manager if needed.
next.notifyAppResumed(next.stopped);
- EventLog.writeEvent(EventLogTags.AM_RESUME_ACTIVITY, next.mUserId,
- System.identityHashCode(next), next.getTask().mTaskId,
- next.shortComponentName);
+ EventLogTags.writeWmResumeActivity(next.mUserId, System.identityHashCode(next),
+ next.getTask().mTaskId, next.shortComponentName);
next.sleeping = false;
mService.getAppWarningsLocked().onResumeActivity(next);
@@ -3519,10 +3514,9 @@ class ActivityStack extends WindowContainer<Task> implements BoundsAnimationTarg
+ " state=" + r.getState() + " callers=" + Debug.getCallers(5));
if (!r.finishing || isProcessRemoved) {
Slog.w(TAG, "Force removing " + r + ": app died, no saved state");
- EventLog.writeEvent(EventLogTags.AM_FINISH_ACTIVITY,
- r.mUserId, System.identityHashCode(r),
- r.getTask().mTaskId, r.shortComponentName,
- "proc died without state saved");
+ EventLogTags.writeWmFinishActivity(r.mUserId,
+ System.identityHashCode(r), r.getTask().mTaskId,
+ r.shortComponentName, "proc died without state saved");
}
} else {
// We have the current state for this activity, so
@@ -3634,7 +3628,7 @@ class ActivityStack extends WindowContainer<Task> implements BoundsAnimationTarg
}
mRootActivityContainer.resumeFocusedStacksTopActivities();
- EventLog.writeEvent(EventLogTags.AM_TASK_TO_FRONT, tr.mUserId, tr.mTaskId);
+ EventLogTags.writeWmTaskToFront(tr.mUserId, tr.mTaskId);
mService.getTaskChangeNotificationController().notifyTaskMovedToFront(tr.getTaskInfo());
} finally {
getDisplay().continueUpdateImeTarget();
@@ -4141,7 +4135,7 @@ class ActivityStack extends WindowContainer<Task> implements BoundsAnimationTarg
super.removeChild(child);
- EventLog.writeEvent(EventLogTags.AM_REMOVE_TASK, child.mTaskId, mStackId);
+ EventLogTags.writeWmRemoveTask(child.mTaskId, mStackId);
if (display.isSingleTaskInstance()) {
mService.notifySingleTaskDisplayEmpty(display.mDisplayId);
@@ -4820,9 +4814,7 @@ class ActivityStack extends WindowContainer<Task> implements BoundsAnimationTarg
}
final int toTop = targetPosition == mChildren.size() - 1 ? 1 : 0;
- EventLog.writeEvent(com.android.server.EventLogTags.WM_TASK_MOVED, child.mTaskId, toTop,
- targetPosition);
-
+ EventLogTags.writeWmTaskMoved(child.mTaskId, toTop, targetPosition);
return targetPosition;
}
@@ -4872,8 +4864,7 @@ class ActivityStack extends WindowContainer<Task> implements BoundsAnimationTarg
}
super.onParentChanged(newParent, oldParent);
if (getParent() == null && mDisplayContent != null) {
- EventLog.writeEvent(com.android.server.EventLogTags.WM_STACK_REMOVED, mStackId);
-
+ EventLogTags.writeWmStackRemoved(mStackId);
mDisplayContent = null;
mWmService.mWindowPlacerLocked.requestTraversal();
}
diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
index 304f2300e308..d088a5e286c1 100644
--- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
@@ -126,7 +126,6 @@ import android.os.WorkSource;
import android.provider.MediaStore;
import android.util.ArrayMap;
import android.util.ArraySet;
-import android.util.EventLog;
import android.util.MergedConfiguration;
import android.util.Slog;
import android.util.SparseArray;
@@ -141,7 +140,6 @@ import com.android.internal.os.logging.MetricsLoggerWrapper;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.function.pooled.PooledLambda;
import com.android.server.am.ActivityManagerService;
-import com.android.server.am.EventLogTags;
import com.android.server.am.UserState;
import java.io.FileDescriptor;
@@ -823,8 +821,8 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks {
"Launching: " + r + " savedState=" + r.getSavedState()
+ " with results=" + results + " newIntents=" + newIntents
+ " andResume=" + andResume);
- EventLog.writeEvent(EventLogTags.AM_RESTART_ACTIVITY, r.mUserId,
- System.identityHashCode(r), task.mTaskId, r.shortComponentName);
+ EventLogTags.writeWmRestartActivity(r.mUserId, System.identityHashCode(r),
+ task.mTaskId, r.shortComponentName);
if (r.isActivityTypeHome()) {
// Home process is the root process of the task.
updateHomeProcess(task.getChildAt(0).app);
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 8455c6d04b3d..7960842daf50 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -60,7 +60,6 @@ import static android.os.Process.INVALID_UID;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.INVALID_DISPLAY;
-import static com.android.server.am.EventLogTags.AM_NEW_INTENT;
import static com.android.server.wm.ActivityStack.ActivityState.RESUMED;
import static com.android.server.wm.ActivityStackSupervisor.DEFER_RESUME;
import static com.android.server.wm.ActivityStackSupervisor.ON_TOP;
@@ -114,14 +113,12 @@ import android.os.UserManager;
import android.service.voice.IVoiceInteractionSession;
import android.text.TextUtils;
import android.util.ArraySet;
-import android.util.EventLog;
import android.util.Pools.SynchronizedPool;
import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.HeavyWeightSwitcherActivity;
import com.android.internal.app.IVoiceInteractor;
-import com.android.server.am.EventLogTags;
import com.android.server.am.PendingIntentRecord;
import com.android.server.pm.InstantAppResolver;
import com.android.server.wm.ActivityStackSupervisor.PendingActivityLaunch;
@@ -152,7 +149,8 @@ class ActivityStarter {
private final ActivityStartController mController;
// Share state variable among methods when starting an activity.
- private ActivityRecord mStartActivity;
+ @VisibleForTesting
+ ActivityRecord mStartActivity;
private Intent mIntent;
private int mCallingUid;
private ActivityOptions mOptions;
@@ -176,7 +174,8 @@ class ActivityStarter {
private int mPreferredDisplayId;
private Task mInTask;
- private boolean mAddingToTask;
+ @VisibleForTesting
+ boolean mAddingToTask;
private Task mReuseTask;
private ActivityInfo mNewTaskInfo;
@@ -1550,11 +1549,12 @@ class ActivityStarter {
UserHandle.getAppId(mStartActivity.info.applicationInfo.uid)
);
if (newTask) {
- EventLog.writeEvent(EventLogTags.AM_CREATE_TASK, mStartActivity.mUserId,
+ EventLogTags.writeWmCreateTask(mStartActivity.mUserId,
mStartActivity.getTask().mTaskId);
}
mStartActivity.logStartActivity(
- EventLogTags.AM_CREATE_ACTIVITY, mStartActivity.getTask());
+ EventLogTags.WM_CREATE_ACTIVITY, mStartActivity.getTask());
+
mTargetStack.mLastPausedActivity = null;
mRootActivityContainer.sendPowerHintForLaunchStartIfNeeded(
@@ -1667,7 +1667,16 @@ class ActivityStarter {
* - Comply to the specified activity launch flags
* - Determine whether need to add a new activity on top or just brought the task to front.
*/
- private int recycleTask(Task targetTask, ActivityRecord targetTaskTop, Task reusedTask) {
+ @VisibleForTesting
+ int recycleTask(Task targetTask, ActivityRecord targetTaskTop, Task reusedTask) {
+ // Should not recycle task which is from a different user, just adding the starting
+ // activity to the task.
+ if (targetTask.mUserId != mStartActivity.mUserId) {
+ mTargetStack = targetTask.getStack();
+ mAddingToTask = true;
+ return START_SUCCESS;
+ }
+
// True if we are clearing top and resetting of a standard (default) launch mode
// ({@code LAUNCH_MULTIPLE}) activity. The existing activity will be finished.
final boolean clearTopAndResetStandardLaunchMode =
@@ -2405,7 +2414,7 @@ class ActivityStarter {
return;
}
- activity.logStartActivity(AM_NEW_INTENT, activity.getTask());
+ activity.logStartActivity(EventLogTags.WM_NEW_INTENT, activity.getTask());
activity.deliverNewIntentLocked(mCallingUid, mStartActivity.intent,
mStartActivity.launchedFromPackage);
mIntentDelivered = true;
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index bef4f5a847f3..bcd5d369ee0c 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -83,6 +83,8 @@ import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.PRE
import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.SCREEN_COMPAT_PACKAGES;
import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.ScreenCompatPackage.MODE;
import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.ScreenCompatPackage.PACKAGE;
+import static com.android.server.am.EventLogTags.writeBootProgressEnableScreen;
+import static com.android.server.am.EventLogTags.writeConfigurationChanged;
import static com.android.server.wm.ActivityStack.ActivityState.DESTROYED;
import static com.android.server.wm.ActivityStack.ActivityState.DESTROYING;
import static com.android.server.wm.ActivityStackSupervisor.DEFER_RESUME;
@@ -215,7 +217,6 @@ import android.text.TextUtils;
import android.text.format.TimeMigrationUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
-import android.util.EventLog;
import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
@@ -258,7 +259,6 @@ import com.android.server.am.ActivityManagerServiceDumpActivitiesProto;
import com.android.server.am.ActivityManagerServiceDumpProcessesProto;
import com.android.server.am.AppTimeTracker;
import com.android.server.am.BaseErrorDialog;
-import com.android.server.am.EventLogTags;
import com.android.server.am.PendingIntentController;
import com.android.server.am.PendingIntentRecord;
import com.android.server.am.UserState;
@@ -5195,8 +5195,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.i(TAG_CONFIGURATION,
"Updating global configuration to: " + values);
-
- EventLog.writeEvent(EventLogTags.CONFIGURATION_CHANGED, changes);
+ writeConfigurationChanged(changes);
StatsLog.write(StatsLog.RESOURCE_CONFIGURATION_CHANGED,
values.colorMode,
values.densityDpi,
@@ -5359,8 +5358,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
}
void enableScreenAfterBoot(boolean booted) {
- EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_ENABLE_SCREEN,
- SystemClock.uptimeMillis());
+ writeBootProgressEnableScreen(SystemClock.uptimeMillis());
mWindowManager.enableScreenAfterBoot();
synchronized (mGlobalLock) {
@@ -5491,7 +5489,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
applyUpdateLockStateLocked(r);
applyUpdateVrModeLocked(r);
- EventLogTags.writeAmSetResumedActivity(
+ EventLogTags.writeWmSetResumedActivity(
r == null ? -1 : r.mUserId,
r == null ? "NULL" : r.shortComponentName,
reason);
@@ -6419,8 +6417,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
@Override
public void enableScreenAfterBoot(boolean booted) {
synchronized (mGlobalLock) {
- EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_ENABLE_SCREEN,
- SystemClock.uptimeMillis());
+ writeBootProgressEnableScreen(SystemClock.uptimeMillis());
mWindowManager.enableScreenAfterBoot();
updateEventDispatchingLocked(booted);
}
diff --git a/services/core/java/com/android/server/wm/EventLogTags.logtags b/services/core/java/com/android/server/wm/EventLogTags.logtags
new file mode 100644
index 000000000000..aab901ebcdb6
--- /dev/null
+++ b/services/core/java/com/android/server/wm/EventLogTags.logtags
@@ -0,0 +1,77 @@
+# See system/core/logcat/event.logtags for a description of the format of this file.
+
+option java_package com.android.server.wm
+
+# Do not change these names without updating the checkin_events setting in
+# google3/googledata/wireless/android/provisioning/gservices.config !!
+#
+# An activity is being finished:
+30001 wm_finish_activity (User|1|5),(Token|1|5),(Task ID|1|5),(Component Name|3),(Reason|3)
+# A task is being brought to the front of the screen:
+30002 wm_task_to_front (User|1|5),(Task|1|5)
+# An existing activity is being given a new intent:
+30003 wm_new_intent (User|1|5),(Token|1|5),(Task ID|1|5),(Component Name|3),(Action|3),(MIME Type|3),(URI|3),(Flags|1|5)
+# A new task is being created:
+30004 wm_create_task (User|1|5),(Task ID|1|5)
+# A new activity is being created in an existing task:
+30005 wm_create_activity (User|1|5),(Token|1|5),(Task ID|1|5),(Component Name|3),(Action|3),(MIME Type|3),(URI|3),(Flags|1|5)
+# An activity has been resumed into the foreground but was not already running:
+30006 wm_restart_activity (User|1|5),(Token|1|5),(Task ID|1|5),(Component Name|3)
+# An activity has been resumed and is now in the foreground:
+30007 wm_resume_activity (User|1|5),(Token|1|5),(Task ID|1|5),(Component Name|3)
+
+# Activity launch time
+30009 wm_activity_launch_time (User|1|5),(Token|1|5),(Component Name|3),(time|2|3)
+
+# The Activity Manager failed to pause the given activity.
+30012 wm_failed_to_pause (User|1|5),(Token|1|5),(Wanting to pause|3),(Currently pausing|3)
+# Attempting to pause the current activity
+30013 wm_pause_activity (User|1|5),(Token|1|5),(Component Name|3),(User Leaving|3)
+# Application process has been started
+
+# An activity is being destroyed:
+30018 wm_destroy_activity (User|1|5),(Token|1|5),(Task ID|1|5),(Component Name|3),(Reason|3)
+# An activity has been relaunched, resumed, and is now in the foreground:
+30019 wm_relaunch_resume_activity (User|1|5),(Token|1|5),(Task ID|1|5),(Component Name|3)
+# An activity has been relaunched:
+30020 wm_relaunch_activity (User|1|5),(Token|1|5),(Task ID|1|5),(Component Name|3)
+# The activity's onPause has been called.
+30021 wm_on_paused_called (Token|1|5),(Component Name|3),(Reason|3)
+# The activity's onResume has been called.
+30022 wm_on_resume_called (Token|1|5),(Component Name|3),(Reason|3)
+
+# Activity set to resumed
+30043 wm_set_resumed_activity (User|1|5),(Component Name|3),(Reason|3)
+
+# Stack focus
+30044 wm_focused_stack (User|1|5),(Display Id|1|5),(Focused Stack Id|1|5),(Last Focused Stack Id|1|5),(Reason|3)
+
+# Attempting to stop an activity
+30048 wm_stop_activity (User|1|5),(Token|1|5),(Component Name|3)
+
+# The task is being removed from its parent stack
+30061 wm_remove_task (Task ID|1|5), (Stack ID|1|5)
+
+# An activity been add into stopping list
+30066 wm_add_to_stopping (User|1|5),(Token|1|5),(Component Name|3),(Reason|3)
+
+# Keyguard status changed
+30067 wm_set_keyguard_shown (keyguardShowing|1),(aodShowing|1),(keyguardGoingAway|1),(Reason|3)
+
+# Out of memory for surfaces.
+31000 wm_no_surface_memory (Window|3),(PID|1|5),(Operation|3)
+# Task created.
+31001 wm_task_created (TaskId|1|5),(StackId|1|5)
+# Task moved to top (1) or bottom (0).
+31002 wm_task_moved (TaskId|1|5),(ToTop|1),(Index|1)
+# Task removed with source explanation.
+31003 wm_task_removed (TaskId|1|5),(Reason|3)
+# Stack created.
+31004 wm_stack_created (StackId|1|5)
+# Home stack moved to top (1) or bottom (0).
+31005 wm_home_stack_moved (ToTop|1)
+# Stack removed.
+31006 wm_stack_removed (StackId|1|5)
+# bootanim finished:
+31007 wm_boot_animation_done (time|2|3)
+
diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java
index 52cc422f8c51..3b58eca2ecb9 100644
--- a/services/core/java/com/android/server/wm/KeyguardController.java
+++ b/services/core/java/com/android/server/wm/KeyguardController.java
@@ -43,13 +43,11 @@ import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLAS
import android.os.IBinder;
import android.os.RemoteException;
import android.os.Trace;
-import android.util.EventLog;
import android.util.Slog;
import android.util.SparseArray;
import android.util.proto.ProtoOutputStream;
import com.android.internal.policy.IKeyguardDismissCallback;
-import com.android.server.am.EventLogTags;
import com.android.server.policy.WindowManagerPolicy;
import com.android.server.wm.ActivityTaskManagerInternal.SleepToken;
@@ -143,7 +141,7 @@ class KeyguardController {
if (!keyguardChanged && !aodChanged) {
return;
}
- EventLog.writeEvent(EventLogTags.AM_SET_KEYGUARD_SHOWN,
+ EventLogTags.writeWmSetKeyguardShown(
keyguardShowing ? 1 : 0,
aodShowing ? 1 : 0,
mKeyguardGoingAway ? 1 : 0,
@@ -184,7 +182,7 @@ class KeyguardController {
mService.deferWindowLayout();
try {
setKeyguardGoingAway(true);
- EventLog.writeEvent(EventLogTags.AM_SET_KEYGUARD_SHOWN,
+ EventLogTags.writeWmSetKeyguardShown(
1 /* keyguardShowing */,
mAodShowing ? 1 : 0,
1 /* keyguardGoingAway */,
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 565f95e3681b..5ec9599cf7b1 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -68,7 +68,6 @@ import android.os.RemoteException;
import android.os.Trace;
import android.os.UserHandle;
import android.util.ArraySet;
-import android.util.EventLog;
import android.util.Slog;
import android.util.SparseIntArray;
import android.util.proto.ProtoOutputStream;
@@ -77,7 +76,6 @@ import android.view.DisplayInfo;
import android.view.SurfaceControl;
import android.view.WindowManager;
-import com.android.server.EventLogTags;
import com.android.server.protolog.common.ProtoLog;
import java.io.PrintWriter;
@@ -488,10 +486,8 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
final WindowSurfaceController surfaceController = winAnimator.mSurfaceController;
boolean leakedSurface = false;
boolean killedApps = false;
-
- EventLog.writeEvent(EventLogTags.WM_NO_SURFACE_MEMORY, winAnimator.mWin.toString(),
+ EventLogTags.writeWmNoSurfaceMemory(winAnimator.mWin.toString(),
winAnimator.mSession.mPid, operation);
-
final long callingIdentity = Binder.clearCallingIdentity();
try {
// There was some problem...first, do a sanity check of the window list to make sure
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 28c5575b604b..619b71cd751a 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -56,8 +56,6 @@ import static android.provider.Settings.Secure.USER_SETUP_COMPLETE;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.SurfaceControl.METADATA_TASK_ID;
-import static com.android.server.EventLogTags.WM_TASK_CREATED;
-import static com.android.server.EventLogTags.WM_TASK_REMOVED;
import static com.android.server.am.TaskRecordProto.ACTIVITIES;
import static com.android.server.am.TaskRecordProto.ACTIVITY_TYPE;
import static com.android.server.am.TaskRecordProto.FULLSCREEN;
@@ -128,7 +126,6 @@ import android.os.UserHandle;
import android.provider.Settings;
import android.service.voice.IVoiceInteractionSession;
import android.util.DisplayMetrics;
-import android.util.EventLog;
import android.util.Slog;
import android.util.proto.ProtoOutputStream;
import android.view.Display;
@@ -421,8 +418,7 @@ class Task extends WindowContainer<ActivityRecord> implements ConfigurationConta
ActivityStack stack) {
super(atmService.mWindowManager);
- EventLog.writeEvent(WM_TASK_CREATED, _taskId,
- stack != null ? stack.mStackId : INVALID_STACK_ID);
+ EventLogTags.writeWmTaskCreated(_taskId, stack != null ? stack.mStackId : INVALID_STACK_ID);
mAtmService = atmService;
mTaskId = _taskId;
mUserId = _userId;
@@ -1301,7 +1297,7 @@ class Task extends WindowContainer<ActivityRecord> implements ConfigurationConta
} else if (!mReuseTask) {
// Remove entire task if it doesn't have any activity left and it isn't marked for reuse
mStack.removeChild(this, reason);
- EventLog.writeEvent(WM_TASK_REMOVED, mTaskId,
+ EventLogTags.writeWmTaskRemoved(mTaskId,
"removeChild: last r=" + r + " in t=" + this);
removeIfPossible();
}
@@ -2311,7 +2307,7 @@ class Task extends WindowContainer<ActivityRecord> implements ConfigurationConta
@Override
void removeImmediately() {
if (DEBUG_STACK) Slog.i(TAG, "removeTask: removing taskId=" + mTaskId);
- EventLog.writeEvent(WM_TASK_REMOVED, mTaskId, "removeTask");
+ EventLogTags.writeWmTaskRemoved(mTaskId, "removeTask");
super.removeImmediately();
}
@@ -2319,7 +2315,7 @@ class Task extends WindowContainer<ActivityRecord> implements ConfigurationConta
void reparent(ActivityStack stack, int position, boolean moveParents, String reason) {
if (DEBUG_STACK) Slog.i(TAG, "reParentTask: removing taskId=" + mTaskId
+ " from stack=" + getTaskStack());
- EventLog.writeEvent(WM_TASK_REMOVED, mTaskId, "reParentTask");
+ EventLogTags.writeWmTaskRemoved(mTaskId, "reParentTask");
final ActivityStack prevStack = getTaskStack();
final boolean wasTopFocusedStack =
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 5afcab0cc11c..a6578f30d28e 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -193,7 +193,6 @@ import android.text.format.DateUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.DisplayMetrics;
-import android.util.EventLog;
import android.util.Log;
import android.util.MergedConfiguration;
import android.util.Slog;
@@ -265,7 +264,6 @@ import com.android.internal.util.function.pooled.PooledLambda;
import com.android.internal.view.WindowManagerPolicyThread;
import com.android.server.AnimationThread;
import com.android.server.DisplayThread;
-import com.android.server.EventLogTags;
import com.android.server.FgThread;
import com.android.server.LocalServices;
import com.android.server.UiThread;
@@ -1106,6 +1104,7 @@ public class WindowManagerService extends IWindowManager.Stub
com.android.internal.R.bool.config_hasPermanentDpad);
mInTouchMode = context.getResources().getBoolean(
com.android.internal.R.bool.config_defaultInTouchMode);
+ inputManager.setInTouchMode(mInTouchMode);
mDrawLockTimeoutMillis = context.getResources().getInteger(
com.android.internal.R.integer.config_drawLockTimeoutMillis);
mAllowAnimationsInLowPowerMode = context.getResources().getBoolean(
@@ -3327,7 +3326,7 @@ public class WindowManagerService extends IWindowManager.Stub
ProtoLog.e(WM_ERROR, "Boot completed: SurfaceFlinger is dead!");
}
- EventLog.writeEvent(EventLogTags.WM_BOOT_ANIMATION_DONE, SystemClock.uptimeMillis());
+ EventLogTags.writeWmBootAnimationDone(SystemClock.uptimeMillis());
Trace.asyncTraceEnd(TRACE_TAG_WINDOW_MANAGER, "Stop bootanim", 0);
mDisplayEnabled = true;
ProtoLog.i(WM_DEBUG_SCREEN_ON, "******************** ENABLING SCREEN!");
@@ -3404,6 +3403,7 @@ public class WindowManagerService extends IWindowManager.Stub
synchronized (mGlobalLock) {
mInTouchMode = mode;
}
+ mInputManager.setInTouchMode(mode);
}
public void showEmulatorDisplayOverlayIfNeeded() {
@@ -7692,7 +7692,9 @@ public class WindowManagerService extends IWindowManager.Stub
mInputManager.registerInputChannel(serverChannel);
mEmbeddedWindowController.add(serverChannel.getToken(), window, hostWindow, callingUid,
callingPid);
- if (hostWindow != null) {
+
+ if (hostWindow != null
+ && hostWindow.mInputWindowHandle.inputApplicationHandle != null) {
applicationHandle = new InputApplicationHandle(
hostWindow.mInputWindowHandle.inputApplicationHandle);
}
diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp
index dd2b27ddeef4..471164d16d49 100644
--- a/services/core/jni/Android.bp
+++ b/services/core/jni/Android.bp
@@ -53,7 +53,6 @@ cc_library_static {
"com_android_server_am_LowMemDetector.cpp",
"onload.cpp",
":lib_networkStatsFactory_native",
- ":tethering-jni-srcs",
],
include_dirs: [
@@ -133,7 +132,6 @@ cc_defaults {
"android.hardware.power@1.0",
"android.hardware.power@1.1",
"android.hardware.power.stats@1.0",
- "android.hardware.tetheroffload.config@1.0",
"android.hardware.thermal@1.0",
"android.hardware.tv.cec@1.0",
"android.hardware.tv.input@1.0",
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index b546a1d9ef4e..9344a9b7c849 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -1502,6 +1502,13 @@ static void nativeSetInputFilterEnabled(JNIEnv* /* env */, jclass /* clazz */,
im->getInputManager()->getDispatcher()->setInputFilterEnabled(enabled);
}
+static void nativeSetInTouchMode(JNIEnv* /* env */, jclass /* clazz */,
+ jlong ptr, jboolean inTouchMode) {
+ NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
+
+ im->getInputManager()->getDispatcher()->setInTouchMode(inTouchMode);
+}
+
static jint nativeInjectInputEvent(JNIEnv* env, jclass /* clazz */,
jlong ptr, jobject inputEventObj, jint injectorPid, jint injectorUid,
jint syncMode, jint timeoutMillis, jint policyFlags) {
@@ -1781,6 +1788,8 @@ static const JNINativeMethod gInputManagerMethods[] = {
(void*) nativePilferPointers },
{ "nativeSetInputFilterEnabled", "(JZ)V",
(void*) nativeSetInputFilterEnabled },
+ { "nativeSetInTouchMode", "(JZ)V",
+ (void*) nativeSetInTouchMode },
{ "nativeInjectInputEvent", "(JLandroid/view/InputEvent;IIIII)I",
(void*) nativeInjectInputEvent },
{ "nativeToggleCapsLock", "(JI)V",
diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
index 3bc28383cf29..a0f5628761fb 100644
--- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
+++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
@@ -704,20 +704,22 @@ Return<void> GnssCallback::gnssSvStatusCbImpl(const T& svStatus) {
jfloatArray elevArray = env->NewFloatArray(listSize);
jfloatArray azimArray = env->NewFloatArray(listSize);
jfloatArray carrierFreqArray = env->NewFloatArray(listSize);
+ jfloatArray basebandCn0Array = env->NewFloatArray(listSize);
jint* svidWithFlags = env->GetIntArrayElements(svidWithFlagArray, 0);
jfloat* cn0s = env->GetFloatArrayElements(cn0Array, 0);
jfloat* elev = env->GetFloatArrayElements(elevArray, 0);
jfloat* azim = env->GetFloatArrayElements(azimArray, 0);
jfloat* carrierFreq = env->GetFloatArrayElements(carrierFreqArray, 0);
+ jfloat* basebandCn0s = env->GetFloatArrayElements(basebandCn0Array, 0);
/*
* Read GNSS SV info.
*/
for (size_t i = 0; i < listSize; ++i) {
enum ShiftWidth: uint8_t {
- SVID_SHIFT_WIDTH = 8,
- CONSTELLATION_TYPE_SHIFT_WIDTH = 4
+ SVID_SHIFT_WIDTH = 12,
+ CONSTELLATION_TYPE_SHIFT_WIDTH = 8
};
const IGnssCallback_V1_0::GnssSvInfo& info = getGnssSvInfoOfIndex(svStatus, i);
@@ -728,6 +730,8 @@ Return<void> GnssCallback::gnssSvStatusCbImpl(const T& svStatus) {
elev[i] = info.elevationDegrees;
azim[i] = info.azimuthDegrees;
carrierFreq[i] = info.carrierFrequencyHz;
+ // TODO(b/144850155): fill svidWithFlags with hasBasebandCn0DbHz based on HAL versions
+ basebandCn0s[i] = 0.0;
}
env->ReleaseIntArrayElements(svidWithFlagArray, svidWithFlags, 0);
@@ -735,10 +739,11 @@ Return<void> GnssCallback::gnssSvStatusCbImpl(const T& svStatus) {
env->ReleaseFloatArrayElements(elevArray, elev, 0);
env->ReleaseFloatArrayElements(azimArray, azim, 0);
env->ReleaseFloatArrayElements(carrierFreqArray, carrierFreq, 0);
+ env->ReleaseFloatArrayElements(basebandCn0Array, basebandCn0s, 0);
env->CallVoidMethod(mCallbacksObj, method_reportSvStatus,
static_cast<jint>(listSize), svidWithFlagArray, cn0Array, elevArray, azimArray,
- carrierFreqArray);
+ carrierFreqArray, basebandCn0Array);
checkAndClearExceptionFromCallback(env, __FUNCTION__);
return Void();
@@ -1545,7 +1550,7 @@ static void android_location_GnssLocationProvider_class_init_native(JNIEnv* env,
method_reportLocation = env->GetMethodID(clazz, "reportLocation",
"(ZLandroid/location/Location;)V");
method_reportStatus = env->GetMethodID(clazz, "reportStatus", "(I)V");
- method_reportSvStatus = env->GetMethodID(clazz, "reportSvStatus", "(I[I[F[F[F[F)V");
+ method_reportSvStatus = env->GetMethodID(clazz, "reportSvStatus", "(I[I[F[F[F[F[F)V");
method_reportAGpsStatus = env->GetMethodID(clazz, "reportAGpsStatus", "(II[B)V");
method_reportNmea = env->GetMethodID(clazz, "reportNmea", "(J)V");
method_setTopHalCapabilities = env->GetMethodID(clazz, "setTopHalCapabilities", "(I)V");
diff --git a/services/core/jni/onload.cpp b/services/core/jni/onload.cpp
index efffa6ca735b..692c9d25baa9 100644
--- a/services/core/jni/onload.cpp
+++ b/services/core/jni/onload.cpp
@@ -40,7 +40,6 @@ int register_android_server_vr_VrManagerService(JNIEnv* env);
int register_android_server_VibratorService(JNIEnv* env);
int register_android_server_location_GnssLocationProvider(JNIEnv* env);
int register_android_server_connectivity_Vpn(JNIEnv* env);
-int register_android_server_connectivity_tethering_OffloadHardwareInterface(JNIEnv*);
int register_android_server_TestNetworkService(JNIEnv* env);
int register_android_server_devicepolicy_CryptoTestHelper(JNIEnv*);
int register_android_server_hdmi_HdmiCecController(JNIEnv* env);
@@ -88,7 +87,6 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */)
register_android_server_SystemServer(env);
register_android_server_location_GnssLocationProvider(env);
register_android_server_connectivity_Vpn(env);
- register_android_server_connectivity_tethering_OffloadHardwareInterface(env);
register_android_server_TestNetworkService(env);
register_android_server_devicepolicy_CryptoTestHelper(env);
register_android_server_ConsumerIrService(env);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index ea987c097527..b26468476b49 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -137,6 +137,8 @@ import android.app.admin.StartInstallingUpdateCallback;
import android.app.admin.SystemUpdateInfo;
import android.app.admin.SystemUpdatePolicy;
import android.app.backup.IBackupManager;
+import android.app.timedetector.ManualTimeSuggestion;
+import android.app.timedetector.TimeDetector;
import android.app.trust.TrustManager;
import android.app.usage.UsageStatsManagerInternal;
import android.compat.annotation.ChangeId;
@@ -1956,6 +1958,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return mContext.getSystemService(AlarmManager.class);
}
+ TimeDetector getTimeDetector() {
+ return mContext.getSystemService(TimeDetector.class);
+ }
+
ConnectivityManager getConnectivityManager() {
return mContext.getSystemService(ConnectivityManager.class);
}
@@ -5568,8 +5574,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
}
- private void enforceProfileOwnerOfCorpOwnedDevice(ActiveAdmin admin) {
- if (!isProfileOwnerOfOrganizationOwnedDevicte(admin)) {
+ private void enforceProfileOwnerOfOrganizationOwnedDevice(ActiveAdmin admin) {
+ if (!isProfileOwnerOfOrganizationOwnedDevice(admin)) {
throw new SecurityException(String.format("Provided admin %s is either not a profile "
+ "owner or not on a corporate-owned device.", admin));
}
@@ -6639,7 +6645,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
boolean calledByProfileOwnerOnOrgOwnedDevice =
- isProfileOwnerOfOrganizationOwnedDevicte(admin);
+ isProfileOwnerOfOrganizationOwnedDevice(admin);
if (calledOnParentInstance && !calledByProfileOwnerOnOrgOwnedDevice) {
throw new SecurityException("Wiping the entire device can only be done by a profile"
@@ -6679,6 +6685,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
mUserManager.setUserRestriction(
UserManager.DISALLOW_REMOVE_MANAGED_PROFILE, false,
UserHandle.SYSTEM);
+
+ // Device-wide policies set by the profile owner need to be cleaned up here.
+ mLockPatternUtils.setDeviceOwnerInfo(null);
} finally {
mInjector.binderRestoreCallingIdentity(ident);
}
@@ -8009,7 +8018,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
private boolean canProfileOwnerAccessDeviceIds(int userId) {
synchronized (getLockObject()) {
- return mOwners.canProfileOwnerAccessDeviceIds(userId);
+ return mOwners.isProfileOwnerOfOrganizationOwnedDevice(userId);
}
}
@@ -8020,7 +8029,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
* {@code getActiveAdminForCallerLocked} or one of the similar variants, not caller-supplied
* input.
*/
- private boolean isProfileOwnerOfOrganizationOwnedDevicte(@Nullable ActiveAdmin admin) {
+ private boolean isProfileOwnerOfOrganizationOwnedDevice(@Nullable ActiveAdmin admin) {
if (admin == null) {
return false;
}
@@ -8328,14 +8337,17 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
synchronized (getLockObject()) {
- getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
- long token = mInjector.binderClearCallingIdentity();
- try {
- mLockPatternUtils.setDeviceOwnerInfo(info != null ? info.toString() : null);
- } finally {
- mInjector.binderRestoreCallingIdentity(token);
+ ActiveAdmin admin = getActiveAdminForCallerLocked(who,
+ DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ if (!isProfileOwnerOfOrganizationOwnedDevice(admin) && !isDeviceOwner(admin)) {
+ throw new SecurityException("Only Device Owner or Profile Owner of"
+ + " organization-owned device can set screen lock info.");
}
}
+
+ mInjector.binderWithCleanCallingIdentity(() ->
+ mLockPatternUtils.setDeviceOwnerInfo(info != null ? info.toString() : null));
+
DevicePolicyEventLogger
.createEvent(DevicePolicyEnums.SET_DEVICE_OWNER_LOCK_SCREEN_INFO)
.setAdmin(who)
@@ -10223,8 +10235,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
synchronized (getLockObject()) {
final boolean isDeviceOwner = mOwners.isDeviceOwnerUserId(userId);
final Bundle userRestrictions;
- // Whether device owner enforces camera restriction.
- boolean disallowCameraGlobally = false;
+ final int restrictionOwnerType;
if (isDeviceOwner) {
final ActiveAdmin deviceOwner = getDeviceOwnerAdminLocked();
@@ -10232,33 +10243,45 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return; // Shouldn't happen.
}
userRestrictions = deviceOwner.userRestrictions;
- // DO can disable camera globally.
- disallowCameraGlobally = deviceOwner.disableCamera;
+ addOrRemoveDisableCameraRestriction(userRestrictions, deviceOwner);
+ restrictionOwnerType = UserManagerInternal.OWNER_TYPE_DEVICE_OWNER;
} else {
final ActiveAdmin profileOwner = getProfileOwnerAdminLocked(userId);
userRestrictions = profileOwner != null ? profileOwner.userRestrictions : null;
- }
+ addOrRemoveDisableCameraRestriction(userRestrictions, userId);
- // Whether any admin enforces camera restriction.
- final int cameraRestrictionScope =
- getCameraRestrictionScopeLocked(userId, disallowCameraGlobally);
+ if (isProfileOwnerOfOrganizationOwnedDevice(profileOwner)) {
+ restrictionOwnerType =
+ UserManagerInternal.OWNER_TYPE_PROFILE_OWNER_OF_ORGANIZATION_OWNED_DEVICE;
+ } else if (profileOwner != null) {
+ restrictionOwnerType = UserManagerInternal.OWNER_TYPE_PROFILE_OWNER;
+ } else {
+ restrictionOwnerType = UserManagerInternal.OWNER_TYPE_NO_OWNER;
+ }
+ }
mUserManagerInternal.setDevicePolicyUserRestrictions(userId, userRestrictions,
- isDeviceOwner, cameraRestrictionScope);
+ restrictionOwnerType);
}
}
- /**
- * Get the scope of camera restriction for a given user if any.
- */
- private int getCameraRestrictionScopeLocked(int userId, boolean disallowCameraGlobally) {
- if (disallowCameraGlobally) {
- return UserManagerInternal.CAMERA_DISABLED_GLOBALLY;
- } else if (getCameraDisabled(
- /* who= */ null, userId, /* mergeDeviceOwnerRestriction= */ false)) {
- return UserManagerInternal.CAMERA_DISABLED_LOCALLY;
+ private void addOrRemoveDisableCameraRestriction(Bundle userRestrictions, ActiveAdmin admin) {
+ if (userRestrictions == null) return;
+ if (admin.disableCamera) {
+ userRestrictions.putBoolean(UserManager.DISALLOW_CAMERA, true);
+ } else {
+ userRestrictions.remove(UserManager.DISALLOW_CAMERA);
+ }
+ }
+
+ private void addOrRemoveDisableCameraRestriction(Bundle userRestrictions, int userId) {
+ if (userRestrictions == null) return;
+ if (getCameraDisabled(/* who= */ null, userId, /* mergeDeviceOwnerRestriction= */
+ false)) {
+ userRestrictions.putBoolean(UserManager.DISALLOW_CAMERA, true);
+ } else {
+ userRestrictions.remove(UserManager.DISALLOW_CAMERA);
}
- return UserManagerInternal.CAMERA_NOT_DISABLED;
}
@Override
@@ -10987,31 +11010,20 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
@Override
public void setLocationEnabled(ComponentName who, boolean locationEnabled) {
Preconditions.checkNotNull(who, "ComponentName is null");
- int userId = mInjector.userHandleGetCallingUserId();
-
- synchronized (getLockObject()) {
- getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ enforceDeviceOwner(who);
- if (!isDeviceOwner(who, userId) && !isCurrentUserDemo()) {
- throw new SecurityException(
- "Permission denial: Profile owners cannot update location settings");
- }
- }
+ UserHandle userHandle = mInjector.binderGetCallingUserHandle();
+ mInjector.binderWithCleanCallingIdentity(
+ () -> mInjector.getLocationManager().setLocationEnabledForUser(locationEnabled,
+ userHandle));
- long ident = mInjector.binderClearCallingIdentity();
- try {
- mInjector.getLocationManager().setLocationEnabledForUser(
- locationEnabled, UserHandle.of(userId));
- DevicePolicyEventLogger
- .createEvent(DevicePolicyEnums.SET_SECURE_SETTING)
- .setAdmin(who)
- .setStrings(Settings.Secure.LOCATION_MODE, Integer.toString(
- locationEnabled ? Settings.Secure.LOCATION_MODE_ON
- : Settings.Secure.LOCATION_MODE_OFF))
- .write();
- } finally {
- mInjector.binderRestoreCallingIdentity(ident);
- }
+ DevicePolicyEventLogger
+ .createEvent(DevicePolicyEnums.SET_SECURE_SETTING)
+ .setAdmin(who)
+ .setStrings(Settings.Secure.LOCATION_MODE, Integer.toString(
+ locationEnabled ? Settings.Secure.LOCATION_MODE_ON
+ : Settings.Secure.LOCATION_MODE_OFF))
+ .write();
}
@Override
@@ -11022,7 +11034,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
if (mInjector.settingsGlobalGetInt(Global.AUTO_TIME, 0) == 1) {
return false;
}
- mInjector.binderWithCleanCallingIdentity(() -> mInjector.getAlarmManager().setTime(millis));
+ ManualTimeSuggestion manualTimeSuggestion = TimeDetector.createManualTimeSuggestion(
+ millis, "DevicePolicyManagerService: setTime");
+ mInjector.binderWithCleanCallingIdentity(
+ () -> mInjector.getTimeDetector().suggestManualTime(manualTimeSuggestion));
return true;
}
@@ -12661,14 +12676,14 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return false;
}
- private boolean hasGrantProfileOwnerDevcieIdAccessPermission() {
+ private boolean hasMarkProfileOwnerOnOrganizationOwnedDevicePermission() {
return mContext.checkCallingPermission(
- android.Manifest.permission.GRANT_PROFILE_OWNER_DEVICE_IDS_ACCESS)
+ permission.MARK_DEVICE_ORGANIZATION_OWNED)
== PackageManager.PERMISSION_GRANTED;
}
@Override
- public void grantDeviceIdsAccessToProfileOwner(ComponentName who, int userId) {
+ public void markProfileOwnerOnOrganizationOwnedDevice(ComponentName who, int userId) {
// As the caller is the system, it must specify the component name of the profile owner
// as a sanity / safety check.
Preconditions.checkNotNull(who);
@@ -12677,16 +12692,24 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return;
}
- // Only privileged system apps can grant the Profile Owner access to Device IDs.
- if (!(isCallerWithSystemUid() || isAdb()
- || hasGrantProfileOwnerDevcieIdAccessPermission())) {
+ // Only adb or system apps with the right permission can mark a profile owner on
+ // organization-owned device.
+ if (!(isAdb() || hasMarkProfileOwnerOnOrganizationOwnedDevicePermission())) {
throw new SecurityException(
- "Only the system can grant Device IDs access for a profile owner.");
+ "Only the system can mark a profile owner of organization-owned device.");
}
- if (isAdb() && hasIncompatibleAccountsOrNonAdbNoLock(userId, who)) {
- throw new SecurityException(
- "Can only be called from ADB if the device has no accounts.");
+ if (isAdb()) {
+ if (hasIncompatibleAccountsOrNonAdbNoLock(userId, who)) {
+ throw new SecurityException(
+ "Can only be called from ADB if the device has no accounts.");
+ }
+ } else {
+ if (hasUserSetupCompleted(UserHandle.USER_SYSTEM)) {
+ throw new IllegalStateException(
+ "Cannot mark profile owner as managing an organization-owned device after"
+ + " set-up");
+ }
}
// Grant access under lock.
@@ -12699,8 +12722,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
who.flattenToString(), userId));
}
- Slog.i(LOG_TAG, String.format("Granting Device ID access to %s, for user %d",
- who.flattenToString(), userId));
+ Slog.i(LOG_TAG, String.format(
+ "Marking %s as profile owner on organization-owned device for user %d",
+ who.flattenToString(), userId));
// First, set restriction on removing the profile.
final long ident = mInjector.binderClearCallingIdentity();
@@ -12720,9 +12744,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
mInjector.binderRestoreCallingIdentity(ident);
}
- // setProfileOwnerCanAccessDeviceIds will trigger writing of the profile owner
+ // markProfileOwnerOfOrganizationOwnedDevice will trigger writing of the profile owner
// data, no need to do it manually.
- mOwners.setProfileOwnerCanAccessDeviceIds(userId);
+ mOwners.markProfileOwnerOfOrganizationOwnedDevice(userId);
}
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
index 65bf86feb88f..f70fe909b459 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
@@ -101,7 +101,12 @@ class Owners {
private static final String ATTR_USER_RESTRICTIONS_MIGRATED = "userRestrictionsMigrated";
private static final String ATTR_FREEZE_RECORD_START = "start";
private static final String ATTR_FREEZE_RECORD_END = "end";
+ // Legacy attribute, its presence would mean the profile owner associated with it is
+ // managing a profile on an organization-owned device.
private static final String ATTR_CAN_ACCESS_DEVICE_IDS = "canAccessDeviceIds";
+ // New attribute for profile owner of organization-owned device.
+ private static final String ATTR_PROFILE_OWNER_OF_ORG_OWNED_DEVICE =
+ "isPoOrganizationOwnedDevice";
private final UserManager mUserManager;
private final UserManagerInternal mUserManagerInternal;
@@ -286,7 +291,7 @@ class Owners {
// semantically compatible with the meaning of this flag.
mDeviceOwner = new OwnerInfo(ownerName, admin, userRestrictionsMigrated,
/* remoteBugreportUri =*/ null, /* remoteBugreportHash =*/
- null, /* canAccessDeviceIds =*/true);
+ null, /* isOrganizationOwnedDevice =*/true);
mDeviceOwnerUserId = userId;
mUserManagerInternal.setDeviceManaged(true);
@@ -313,7 +318,7 @@ class Owners {
// For a newly set PO, there's no need for migration.
mProfileOwners.put(userId, new OwnerInfo(ownerName, admin,
/* userRestrictionsMigrated =*/ true, /* remoteBugreportUri =*/ null,
- /* remoteBugreportHash =*/ null, /* canAccessDeviceIds =*/ false));
+ /* remoteBugreportHash =*/ null, /* isOrganizationOwnedDevice =*/ false));
mUserManagerInternal.setUserManaged(userId, true);
pushToPackageManagerLocked();
pushToAppOpsLocked();
@@ -334,8 +339,8 @@ class Owners {
final OwnerInfo ownerInfo = mProfileOwners.get(userId);
final OwnerInfo newOwnerInfo = new OwnerInfo(target.getPackageName(), target,
ownerInfo.userRestrictionsMigrated, ownerInfo.remoteBugreportUri,
- ownerInfo.remoteBugreportHash, /* canAccessDeviceIds =*/
- ownerInfo.canAccessDeviceIds);
+ ownerInfo.remoteBugreportHash, /* isOrganizationOwnedDevice =*/
+ ownerInfo.isOrganizationOwnedDevice);
mProfileOwners.put(userId, newOwnerInfo);
pushToPackageManagerLocked();
pushToAppOpsLocked();
@@ -348,8 +353,8 @@ class Owners {
// See DevicePolicyManagerService#getDeviceOwnerName
mDeviceOwner = new OwnerInfo(null, target,
mDeviceOwner.userRestrictionsMigrated, mDeviceOwner.remoteBugreportUri,
- mDeviceOwner.remoteBugreportHash, /* canAccessDeviceIds =*/
- mDeviceOwner.canAccessDeviceIds);
+ mDeviceOwner.remoteBugreportHash, /* isOrganizationOwnedDevice =*/
+ mDeviceOwner.isOrganizationOwnedDevice);
pushToPackageManagerLocked();
pushToActivityTaskManagerLocked();
pushToAppOpsLocked();
@@ -378,13 +383,13 @@ class Owners {
}
/**
- * Returns true if {@code userId} has a profile owner and that profile owner was granted
- * the ability to access device identifiers.
+ * Returns true if {@code userId} has a profile owner and that profile owner is on an
+ * organization-owned device, as indicated by the provisioning flow.
*/
- boolean canProfileOwnerAccessDeviceIds(int userId) {
+ boolean isProfileOwnerOfOrganizationOwnedDevice(int userId) {
synchronized (mLock) {
OwnerInfo profileOwner = mProfileOwners.get(userId);
- return profileOwner != null ? profileOwner.canAccessDeviceIds : false;
+ return profileOwner != null ? profileOwner.isOrganizationOwnedDevice : false;
}
}
@@ -523,15 +528,16 @@ class Owners {
}
}
- /** Sets the grant to access device IDs, and also writes to file. */
- void setProfileOwnerCanAccessDeviceIds(int userId) {
+ /** Sets the indicator that the profile owner manages an organization-owned device,
+ * then write to file. */
+ void markProfileOwnerOfOrganizationOwnedDevice(int userId) {
synchronized (mLock) {
OwnerInfo profileOwner = mProfileOwners.get(userId);
if (profileOwner != null) {
- profileOwner.canAccessDeviceIds = true;
+ profileOwner.isOrganizationOwnedDevice = true;
} else {
Slog.e(TAG, String.format(
- "Cannot grant Device IDs access for user %d, no profile owner.", userId));
+ "No profile owner for user %d to set as org-owned.", userId));
}
writeProfileOwner(userId);
}
@@ -558,7 +564,7 @@ class Owners {
String packageName = parser.getAttributeValue(null, ATTR_PACKAGE);
mDeviceOwner = new OwnerInfo(name, packageName,
/* userRestrictionsMigrated =*/ false, /* remoteBugreportUri =*/ null,
- /* remoteBugreportHash =*/ null, /* canAccessDeviceIds =*/ true);
+ /* remoteBugreportHash =*/ null, /* isOrganizationOwnedDevice =*/ true);
mDeviceOwnerUserId = UserHandle.USER_SYSTEM;
} else if (tag.equals(TAG_DEVICE_INITIALIZER)) {
// Deprecated tag
@@ -575,7 +581,7 @@ class Owners {
if (admin != null) {
profileOwnerInfo = new OwnerInfo(profileOwnerName, admin,
/* userRestrictionsMigrated =*/ false, null,
- null, /* canAccessDeviceIds =*/ false);
+ null, /* isOrganizationOwnedDevice =*/ false);
} else {
// This shouldn't happen but switch from package name -> component name
// might have written bad device owner files. b/17652534
@@ -587,7 +593,7 @@ class Owners {
profileOwnerInfo = new OwnerInfo(profileOwnerName, profileOwnerPackageName,
/* userRestrictionsMigrated =*/ false,
/* remoteBugreportUri =*/ null, /* remoteBugreportHash =*/
- null, /* canAccessDeviceIds =*/ false);
+ null, /* isOrganizationOwnedDevice =*/ false);
}
mProfileOwners.put(userId, profileOwnerInfo);
} else if (TAG_SYSTEM_UPDATE_POLICY.equals(tag)) {
@@ -947,28 +953,30 @@ class Owners {
public boolean userRestrictionsMigrated;
public String remoteBugreportUri;
public String remoteBugreportHash;
- public boolean canAccessDeviceIds;
+ public boolean isOrganizationOwnedDevice;
public OwnerInfo(String name, String packageName, boolean userRestrictionsMigrated,
- String remoteBugreportUri, String remoteBugreportHash, boolean canAccessDeviceIds) {
+ String remoteBugreportUri, String remoteBugreportHash,
+ boolean isOrganizationOwnedDevice) {
this.name = name;
this.packageName = packageName;
this.admin = new ComponentName(packageName, "");
this.userRestrictionsMigrated = userRestrictionsMigrated;
this.remoteBugreportUri = remoteBugreportUri;
this.remoteBugreportHash = remoteBugreportHash;
- this.canAccessDeviceIds = canAccessDeviceIds;
+ this.isOrganizationOwnedDevice = isOrganizationOwnedDevice;
}
public OwnerInfo(String name, ComponentName admin, boolean userRestrictionsMigrated,
- String remoteBugreportUri, String remoteBugreportHash, boolean canAccessDeviceIds) {
+ String remoteBugreportUri, String remoteBugreportHash,
+ boolean isOrganizationOwnedDevice) {
this.name = name;
this.admin = admin;
this.packageName = admin.getPackageName();
this.userRestrictionsMigrated = userRestrictionsMigrated;
this.remoteBugreportUri = remoteBugreportUri;
this.remoteBugreportHash = remoteBugreportHash;
- this.canAccessDeviceIds = canAccessDeviceIds;
+ this.isOrganizationOwnedDevice = isOrganizationOwnedDevice;
}
public void writeToXml(XmlSerializer out, String tag) throws IOException {
@@ -988,9 +996,9 @@ class Owners {
if (remoteBugreportHash != null) {
out.attribute(null, ATTR_REMOTE_BUGREPORT_HASH, remoteBugreportHash);
}
- if (canAccessDeviceIds) {
- out.attribute(null, ATTR_CAN_ACCESS_DEVICE_IDS,
- String.valueOf(canAccessDeviceIds));
+ if (isOrganizationOwnedDevice) {
+ out.attribute(null, ATTR_PROFILE_OWNER_OF_ORG_OWNED_DEVICE,
+ String.valueOf(isOrganizationOwnedDevice));
}
out.endTag(null, tag);
}
@@ -1012,13 +1020,17 @@ class Owners {
parser.getAttributeValue(null, ATTR_CAN_ACCESS_DEVICE_IDS);
final boolean canAccessDeviceIds =
("true".equals(canAccessDeviceIdsStr));
+ final String isOrgOwnedDeviceStr =
+ parser.getAttributeValue(null, ATTR_PROFILE_OWNER_OF_ORG_OWNED_DEVICE);
+ final boolean isOrgOwnedDevice =
+ ("true".equals(isOrgOwnedDeviceStr)) | canAccessDeviceIds;
// Has component name? If so, return [name, component]
if (componentName != null) {
final ComponentName admin = ComponentName.unflattenFromString(componentName);
if (admin != null) {
return new OwnerInfo(name, admin, userRestrictionsMigrated,
- remoteBugreportUri, remoteBugreportHash, canAccessDeviceIds);
+ remoteBugreportUri, remoteBugreportHash, isOrgOwnedDevice);
} else {
// This shouldn't happen but switch from package name -> component name
// might have written bad device owner files. b/17652534
@@ -1029,14 +1041,14 @@ class Owners {
// Else, build with [name, package]
return new OwnerInfo(name, packageName, userRestrictionsMigrated, remoteBugreportUri,
- remoteBugreportHash, canAccessDeviceIds);
+ remoteBugreportHash, isOrgOwnedDevice);
}
public void dump(IndentingPrintWriter pw) {
pw.println("admin=" + admin);
pw.println("name=" + name);
pw.println("package=" + packageName);
- pw.println("canAccessDeviceIds=" + canAccessDeviceIds);
+ pw.println("isOrganizationOwnedDevice=" + isOrganizationOwnedDevice);
}
}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index cb4e377c0110..66f01f367493 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -43,7 +43,7 @@ import android.database.sqlite.SQLiteGlobal;
import android.hardware.display.DisplayManagerInternal;
import android.net.ConnectivityModuleConnector;
import android.net.NetworkStackClient;
-import android.net.wifi.WifiStackClient;
+import android.net.TetheringManager;
import android.os.BaseBundle;
import android.os.Binder;
import android.os.Build;
@@ -269,6 +269,8 @@ public final class SystemServer {
"com.android.internal.car.CarServiceHelperService";
private static final String TIME_DETECTOR_SERVICE_CLASS =
"com.android.server.timedetector.TimeDetectorService$Lifecycle";
+ private static final String TIME_ZONE_DETECTOR_SERVICE_CLASS =
+ "com.android.server.timezonedetector.TimeZoneDetectorService$Lifecycle";
private static final String ACCESSIBILITY_MANAGER_SERVICE_CLASS =
"com.android.server.accessibility.AccessibilityManagerService$Lifecycle";
private static final String ADB_SERVICE_CLASS =
@@ -1112,9 +1114,10 @@ public final class SystemServer {
SignedConfigService.registerUpdateReceiver(mSystemContext);
t.traceEnd();
- } catch (RuntimeException e) {
+ } catch (Throwable e) {
Slog.e("System", "******************************************");
- Slog.e("System", "************ Failure starting core service", e);
+ Slog.e("System", "************ Failure starting core service");
+ throw e;
}
// Before things start rolling, be sure we have decided whether
@@ -1360,6 +1363,40 @@ public final class SystemServer {
t.traceEnd();
if (context.getPackageManager().hasSystemFeature(
+ PackageManager.FEATURE_WIFI)) {
+ // Wifi Service must be started first for wifi-related services.
+ t.traceBegin("StartWifi");
+ mSystemServiceManager.startService(WIFI_SERVICE_CLASS);
+ t.traceEnd();
+ t.traceBegin("StartWifiScanning");
+ mSystemServiceManager.startService(
+ "com.android.server.wifi.scanner.WifiScanningService");
+ t.traceEnd();
+ }
+
+ if (context.getPackageManager().hasSystemFeature(
+ PackageManager.FEATURE_WIFI_RTT)) {
+ t.traceBegin("StartRttService");
+ mSystemServiceManager.startService(
+ "com.android.server.wifi.rtt.RttService");
+ t.traceEnd();
+ }
+
+ if (context.getPackageManager().hasSystemFeature(
+ PackageManager.FEATURE_WIFI_AWARE)) {
+ t.traceBegin("StartWifiAware");
+ mSystemServiceManager.startService(WIFI_AWARE_SERVICE_CLASS);
+ t.traceEnd();
+ }
+
+ if (context.getPackageManager().hasSystemFeature(
+ PackageManager.FEATURE_WIFI_DIRECT)) {
+ t.traceBegin("StartWifiP2P");
+ mSystemServiceManager.startService(WIFI_P2P_SERVICE_CLASS);
+ t.traceEnd();
+ }
+
+ if (context.getPackageManager().hasSystemFeature(
PackageManager.FEATURE_LOWPAN)) {
t.traceBegin("StartLowpan");
mSystemServiceManager.startService(LOWPAN_SERVICE_CLASS);
@@ -1447,6 +1484,14 @@ public final class SystemServer {
}
t.traceEnd();
+ t.traceBegin("StartTimeZoneDetectorService");
+ try {
+ mSystemServiceManager.startService(TIME_ZONE_DETECTOR_SERVICE_CLASS);
+ } catch (Throwable e) {
+ reportWtf("starting StartTimeZoneDetectorService service", e);
+ }
+ t.traceEnd();
+
if (!isWatch) {
t.traceBegin("StartSearchManagerService");
try {
@@ -2171,11 +2216,12 @@ public final class SystemServer {
}
t.traceEnd();
- t.traceBegin("StartWifiStack");
+ t.traceBegin("StartTethering");
try {
- WifiStackClient.getInstance().start();
+ // Tethering must start after ConnectivityService and NetworkStack.
+ TetheringManager.getInstance().start();
} catch (Throwable e) {
- reportWtf("starting Wifi Stack", e);
+ reportWtf("starting Tethering", e);
}
t.traceEnd();
diff --git a/services/net/Android.bp b/services/net/Android.bp
index 7ef9f448f7ce..3babb0b0a133 100644
--- a/services/net/Android.bp
+++ b/services/net/Android.bp
@@ -9,8 +9,8 @@ java_library_static {
name: "services.net",
srcs: [
":net-module-utils-srcs",
- ":tethering-servicesnet-srcs",
":services.net-sources",
+ ":tethering-manager",
],
static_libs: [
"dnsresolver_aidl_interface-V2-java",
diff --git a/services/robotests/src/com/android/server/testing/shadows/ShadowPerformUnifiedRestoreTask.java b/services/robotests/src/com/android/server/testing/shadows/ShadowPerformUnifiedRestoreTask.java
index 2cebbebfbaf4..223a98b6c8f6 100644
--- a/services/robotests/src/com/android/server/testing/shadows/ShadowPerformUnifiedRestoreTask.java
+++ b/services/robotests/src/com/android/server/testing/shadows/ShadowPerformUnifiedRestoreTask.java
@@ -29,6 +29,9 @@ import com.android.server.backup.transport.TransportClient;
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
+import java.util.Map;
+import java.util.Set;
+
@Implements(PerformUnifiedRestoreTask.class)
public class ShadowPerformUnifiedRestoreTask {
@Nullable private static ShadowPerformUnifiedRestoreTask sLastShadow;
@@ -64,7 +67,8 @@ public class ShadowPerformUnifiedRestoreTask {
int pmToken,
boolean isFullSystemRestore,
@Nullable String[] filterSet,
- OnTaskFinishedListener listener) {
+ OnTaskFinishedListener listener,
+ Map<String, Set<String>> excludedKeys) {
mBackupManagerService = backupManagerService;
mPackage = targetPackage;
mIsFullSystemRestore = isFullSystemRestore;
diff --git a/services/tests/servicestests/Android.bp b/services/tests/servicestests/Android.bp
index 0be5fe02f0fe..cf7919b38f2e 100644
--- a/services/tests/servicestests/Android.bp
+++ b/services/tests/servicestests/Android.bp
@@ -41,6 +41,7 @@ android_test {
"hamcrest-library",
"servicestests-utils",
"xml-writer-device-lib",
+ "service-appsearch",
"service-jobscheduler",
],
diff --git a/services/tests/servicestests/src/com/android/server/appsearch/impl/FakeIcingTest.java b/services/tests/servicestests/src/com/android/server/appsearch/impl/FakeIcingTest.java
new file mode 100644
index 000000000000..adef02ee55d7
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/appsearch/impl/FakeIcingTest.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.appsearch.impl;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import com.google.android.icing.proto.DocumentProto;
+import com.google.android.icing.proto.PropertyProto;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@RunWith(AndroidJUnit4.class)
+public class FakeIcingTest {
+ @Test
+ public void query() {
+ FakeIcing icing = new FakeIcing();
+ icing.put(createDoc("uri:cat", "The cat said meow"));
+ icing.put(createDoc("uri:dog", "The dog said woof"));
+
+ assertThat(queryGetUris(icing, "meow")).containsExactly("uri:cat");
+ assertThat(queryGetUris(icing, "said")).containsExactly("uri:cat", "uri:dog");
+ assertThat(queryGetUris(icing, "fred")).isEmpty();
+ }
+
+ @Test
+ public void queryNorm() {
+ FakeIcing icing = new FakeIcing();
+ icing.put(createDoc("uri:cat", "The cat said meow"));
+ icing.put(createDoc("uri:dog", "The dog said woof"));
+
+ assertThat(queryGetUris(icing, "the")).containsExactly("uri:cat", "uri:dog");
+ assertThat(queryGetUris(icing, "The")).containsExactly("uri:cat", "uri:dog");
+ assertThat(queryGetUris(icing, "tHe")).containsExactly("uri:cat", "uri:dog");
+ }
+
+ @Test
+ public void get() {
+ DocumentProto cat = createDoc("uri:cat", "The cat said meow");
+ FakeIcing icing = new FakeIcing();
+ icing.put(cat);
+ assertThat(icing.get("uri:cat")).isEqualTo(cat);
+ }
+
+ @Test
+ public void replace() {
+ DocumentProto cat = createDoc("uri:cat", "The cat said meow");
+ DocumentProto dog = createDoc("uri:dog", "The dog said woof");
+
+ FakeIcing icing = new FakeIcing();
+ icing.put(cat);
+ icing.put(dog);
+
+ assertThat(queryGetUris(icing, "meow")).containsExactly("uri:cat");
+ assertThat(queryGetUris(icing, "said")).containsExactly("uri:cat", "uri:dog");
+ assertThat(icing.get("uri:cat")).isEqualTo(cat);
+
+ // Replace
+ DocumentProto cat2 = createDoc("uri:cat", "The cat said purr");
+ DocumentProto bird = createDoc("uri:bird", "The cat said tweet");
+ icing.put(cat2);
+ icing.put(bird);
+
+ assertThat(queryGetUris(icing, "meow")).isEmpty();
+ assertThat(queryGetUris(icing, "said")).containsExactly("uri:cat", "uri:dog", "uri:bird");
+ assertThat(icing.get("uri:cat")).isEqualTo(cat2);
+ }
+
+ @Test
+ public void delete() {
+ DocumentProto cat = createDoc("uri:cat", "The cat said meow");
+ DocumentProto dog = createDoc("uri:dog", "The dog said woof");
+
+ FakeIcing icing = new FakeIcing();
+ icing.put(cat);
+ icing.put(dog);
+
+ assertThat(queryGetUris(icing, "meow")).containsExactly("uri:cat");
+ assertThat(queryGetUris(icing, "said")).containsExactly("uri:cat", "uri:dog");
+ assertThat(icing.get("uri:cat")).isEqualTo(cat);
+
+ // Delete
+ icing.delete("uri:cat");
+ icing.delete("uri:notreal");
+
+ assertThat(queryGetUris(icing, "meow")).isEmpty();
+ assertThat(queryGetUris(icing, "said")).containsExactly("uri:dog");
+ assertThat(icing.get("uri:cat")).isNull();
+ }
+
+ private static DocumentProto createDoc(String uri, String body) {
+ return DocumentProto.newBuilder()
+ .setUri(uri)
+ .addProperties(PropertyProto.newBuilder().addStringValues(body))
+ .build();
+ }
+
+ private static List<String> queryGetUris(FakeIcing icing, String term) {
+ List<String> uris = new ArrayList<>();
+ for (DocumentProto result : icing.query(term)) {
+ uris.add(result.getUri());
+ }
+ return uris;
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/backup/DataChangedJournalTest.java b/services/tests/servicestests/src/com/android/server/backup/DataChangedJournalTest.java
index f588c4fdb060..4e7fe44b2b76 100644
--- a/services/tests/servicestests/src/com/android/server/backup/DataChangedJournalTest.java
+++ b/services/tests/servicestests/src/com/android/server/backup/DataChangedJournalTest.java
@@ -18,6 +18,9 @@ package com.android.server.backup;
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.when;
+import static org.testng.Assert.assertEquals;
+
import android.platform.test.annotations.Presubmit;
import androidx.test.filters.SmallTest;
@@ -50,6 +53,7 @@ public class DataChangedJournalTest {
@Rule public TemporaryFolder mTemporaryFolder = new TemporaryFolder();
@Mock private Consumer<String> mConsumer;
+ @Mock private File invalidFile;
private File mFile;
private DataChangedJournal mJournal;
@@ -131,4 +135,10 @@ public class DataChangedJournalTest {
public void toString_isSameAsFileToString() throws Exception {
assertThat(mJournal.toString()).isEqualTo(mFile.toString());
}
+
+ public void listJournals_invalidJournalFile_returnsEmptyList() throws Exception {
+ when(invalidFile.listFiles()).thenReturn(null);
+
+ assertEquals(0, DataChangedJournal.listJournals(invalidFile).size());
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/backup/UserBackupPreferencesTest.java b/services/tests/servicestests/src/com/android/server/backup/UserBackupPreferencesTest.java
new file mode 100644
index 000000000000..d6efe35723db
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/backup/UserBackupPreferencesTest.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.backup;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import android.platform.test.annotations.Presubmit;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.junit.runner.RunWith;
+import org.mockito.MockitoAnnotations;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+public class UserBackupPreferencesTest {
+ private static final String EXCLUDED_PACKAGE_1 = "package1";
+ private static final String EXCLUDED_PACKAGE_2 = "package2";
+ private static final List<String> EXCLUDED_KEYS_1 = Arrays.asList("key1", "key2");
+ private static final List<String> EXCLUDED_KEYS_2 = Arrays.asList("key1");
+
+ @Rule public TemporaryFolder mTemporaryFolder = new TemporaryFolder();
+
+ private UserBackupPreferences mExcludedRestoreKeysStorage;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+
+ mExcludedRestoreKeysStorage =
+ new UserBackupPreferences(
+ InstrumentationRegistry.getContext(), mTemporaryFolder.newFolder());
+ }
+
+ @Test
+ public void testGetExcludedKeysForPackages_returnsExcludedKeys() {
+ mExcludedRestoreKeysStorage.addExcludedKeys(EXCLUDED_PACKAGE_1, EXCLUDED_KEYS_1);
+ mExcludedRestoreKeysStorage.addExcludedKeys(EXCLUDED_PACKAGE_2, EXCLUDED_KEYS_2);
+
+ Map<String, Set<String>> excludedKeys =
+ mExcludedRestoreKeysStorage.getExcludedRestoreKeysForPackages(EXCLUDED_PACKAGE_1);
+ assertTrue(excludedKeys.containsKey(EXCLUDED_PACKAGE_1));
+ assertFalse(excludedKeys.containsKey(EXCLUDED_PACKAGE_2));
+ assertEquals(new HashSet<>(EXCLUDED_KEYS_1), excludedKeys.get(EXCLUDED_PACKAGE_1));
+ }
+
+ @Test
+ public void testGetExcludedKeysForPackages_withEmpty_list_returnsAllExcludedKeys() {
+ mExcludedRestoreKeysStorage.addExcludedKeys(EXCLUDED_PACKAGE_1, EXCLUDED_KEYS_1);
+ mExcludedRestoreKeysStorage.addExcludedKeys(EXCLUDED_PACKAGE_2, EXCLUDED_KEYS_2);
+
+ Map<String, Set<String>> excludedKeys =
+ mExcludedRestoreKeysStorage.getAllExcludedRestoreKeys();
+ assertTrue(excludedKeys.containsKey(EXCLUDED_PACKAGE_1));
+ assertTrue(excludedKeys.containsKey(EXCLUDED_PACKAGE_2));
+ assertEquals(new HashSet<>(EXCLUDED_KEYS_1), excludedKeys.get(EXCLUDED_PACKAGE_1));
+ assertEquals(new HashSet<>(EXCLUDED_KEYS_2), excludedKeys.get(EXCLUDED_PACKAGE_2));
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/backup/restore/PerformUnifiedRestoreTaskTest.java b/services/tests/servicestests/src/com/android/server/backup/restore/PerformUnifiedRestoreTaskTest.java
new file mode 100644
index 000000000000..6359edf190b0
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/backup/restore/PerformUnifiedRestoreTaskTest.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.backup.restore;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.when;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import android.app.backup.BackupDataInput;
+import android.app.backup.BackupDataOutput;
+import android.platform.test.annotations.Presubmit;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+import java.util.ArrayDeque;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Queue;
+import java.util.Set;
+
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+public class PerformUnifiedRestoreTaskTest {
+ private static final String PACKAGE_NAME = "package";
+ private static final String INCLUDED_KEY = "included_key";
+ private static final String EXCLUDED_KEY_1 = "excluded_key_1";
+ private static final String EXCLUDED_KEY_2 = "excluded_key_2";
+
+ @Mock private BackupDataInput mBackupDataInput;
+ @Mock private BackupDataOutput mBackupDataOutput;
+
+ private Set<String> mExcludedkeys = new HashSet<>();
+ private Map<String, String> mBackupData = new HashMap<>();
+ // Mock BackupDataInput reads backup data from here.
+ private Queue<String> mBackupDataSource;
+ // Mock BackupDataOutput will write backup data here.
+ private Set<String> mBackupDataDump;
+ private PerformUnifiedRestoreTask mRestoreTask;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+
+ populateTestData();
+
+ mBackupDataSource = new ArrayDeque<>(mBackupData.keySet());
+ when(mBackupDataInput.readNextHeader()).then(new Answer<Boolean>() {
+ @Override
+ public Boolean answer(InvocationOnMock invocation) throws Throwable {
+ return !mBackupDataSource.isEmpty();
+ }
+ });
+ when(mBackupDataInput.getKey()).then(new Answer<String>() {
+ @Override
+ public String answer(InvocationOnMock invocation) throws Throwable {
+ return mBackupDataSource.poll();
+ }
+ });
+ when(mBackupDataInput.getDataSize()).thenReturn(0);
+
+ mBackupDataDump = new HashSet<>();
+ ArgumentCaptor<String> keyCaptor = ArgumentCaptor.forClass(String.class);
+ when(mBackupDataOutput.writeEntityHeader(keyCaptor.capture(), anyInt())).then(
+ new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ mBackupDataDump.add(keyCaptor.getValue());
+ return null;
+ }
+ });
+
+ mRestoreTask = new PerformUnifiedRestoreTask(Collections.singletonMap(
+ PACKAGE_NAME, mExcludedkeys));
+ }
+
+ private void populateTestData() {
+ mBackupData = new HashMap<>();
+ mBackupData.put(INCLUDED_KEY, "1");
+ mBackupData.put(EXCLUDED_KEY_1, "2");
+ mBackupData.put(EXCLUDED_KEY_2, "3");
+
+ mExcludedkeys = new HashSet<>();
+ mExcludedkeys.add(EXCLUDED_KEY_1);
+ mExcludedkeys.add(EXCLUDED_KEY_2);
+ }
+
+ @Test
+ public void testFilterExcludedKeys() throws Exception {
+ mRestoreTask.filterExcludedKeys(PACKAGE_NAME, mBackupDataInput, mBackupDataOutput);
+
+ // Verify only the correct were written into BackupDataOutput object.
+ Set<String> allowedBackupKeys = new HashSet<>(mBackupData.keySet());
+ allowedBackupKeys.removeAll(mExcludedkeys);
+ assertEquals(allowedBackupKeys, mBackupDataDump);
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java b/services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java
new file mode 100644
index 000000000000..c406876c5cee
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java
@@ -0,0 +1,272 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.compat;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.mockito.internal.verification.VerificationModeFactory.times;
+import static org.testng.Assert.assertThrows;
+
+import android.compat.Compatibility;
+import android.content.Context;
+import android.content.pm.PackageManager;
+
+import com.android.internal.compat.CompatibilityChangeConfig;
+
+import com.google.common.collect.ImmutableSet;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+
+@RunWith(MockitoJUnitRunner.class)
+public class PlatformCompatTest {
+ private static final String PACKAGE_NAME = "my.package";
+
+ @Mock
+ private Context mContext;
+ @Mock
+ private PackageManager mPackageManager;
+ @Mock
+ CompatChange.ChangeListener mListener1, mListener2;
+
+
+ @Before
+ public void setUp() throws Exception {
+ when(mContext.getPackageManager()).thenReturn(mPackageManager);
+ when(mPackageManager.getPackageUid(eq(PACKAGE_NAME), eq(0))).thenThrow(
+ new PackageManager.NameNotFoundException());
+ CompatConfig.get().clearChanges();
+ }
+
+ @Test
+ public void testRegisterListenerToSameIdThrows() {
+ PlatformCompat pc = new PlatformCompat(mContext);
+
+ // Registering a listener to change 1 is successful.
+ pc.registerListener(1, mListener1);
+ // Registering a listener to change 2 is successful.
+ pc.registerListener(2, mListener1);
+ // Trying to register another listener to change id 1 fails.
+ assertThrows(IllegalStateException.class, () -> pc.registerListener(1, mListener1));
+ }
+
+ @Test
+ public void testRegisterListenerReturn() {
+ PlatformCompat pc = new PlatformCompat(mContext);
+
+ pc.setOverrides(
+ new CompatibilityChangeConfig(
+ new Compatibility.ChangeConfig(ImmutableSet.of(1L), ImmutableSet.of())),
+ PACKAGE_NAME);
+
+ // Change id 1 is known (added in setOverrides).
+ assertThat(pc.registerListener(1, mListener1)).isTrue();
+ // Change 2 is unknown.
+ assertThat(pc.registerListener(2, mListener1)).isFalse();
+ }
+
+ @Test
+ public void testListenerCalledOnSetOverrides() {
+ PlatformCompat pc = new PlatformCompat(mContext);
+
+ pc.registerListener(1, mListener1);
+ pc.registerListener(2, mListener1);
+
+ pc.setOverrides(
+ new CompatibilityChangeConfig(
+ new Compatibility.ChangeConfig(ImmutableSet.of(1L), ImmutableSet.of(2L))),
+ PACKAGE_NAME);
+
+ verify(mListener1, times(2)).onCompatChange(PACKAGE_NAME);
+ }
+
+ @Test
+ public void testListenerNotCalledOnWrongPackage() {
+ PlatformCompat pc = new PlatformCompat(mContext);
+
+ pc.registerListener(1, mListener1);
+ pc.registerListener(2, mListener1);
+
+ pc.setOverridesForTest(
+ new CompatibilityChangeConfig(
+ new Compatibility.ChangeConfig(ImmutableSet.of(1L), ImmutableSet.of(2L))),
+ PACKAGE_NAME);
+
+ verify(mListener1, never()).onCompatChange("other.package");
+ }
+
+ @Test
+ public void testListenerCalledOnSetOverridesTwoListeners() {
+ PlatformCompat pc = new PlatformCompat(mContext);
+ pc.registerListener(1, mListener1);
+
+ final ImmutableSet<Long> enabled = ImmutableSet.of(1L);
+ final ImmutableSet<Long> disabled = ImmutableSet.of(2L);
+
+ pc.setOverrides(
+ new CompatibilityChangeConfig(
+ new Compatibility.ChangeConfig(enabled, disabled)),
+ PACKAGE_NAME);
+
+ verify(mListener1, times(1)).onCompatChange(PACKAGE_NAME);
+ verify(mListener2, never()).onCompatChange(PACKAGE_NAME);
+
+ reset(mListener1);
+ reset(mListener2);
+
+ pc.registerListener(2, mListener2);
+
+ pc.setOverrides(
+ new CompatibilityChangeConfig(
+ new Compatibility.ChangeConfig(enabled, disabled)),
+ PACKAGE_NAME);
+
+ verify(mListener1, times(1)).onCompatChange(PACKAGE_NAME);
+ verify(mListener2, times(1)).onCompatChange(PACKAGE_NAME);
+ }
+
+ @Test
+ public void testListenerCalledOnSetOverridesForTest() {
+ PlatformCompat pc = new PlatformCompat(mContext);
+
+ pc.registerListener(1, mListener1);
+ pc.registerListener(2, mListener1);
+
+ pc.setOverridesForTest(
+ new CompatibilityChangeConfig(
+ new Compatibility.ChangeConfig(ImmutableSet.of(1L), ImmutableSet.of(2L))),
+ PACKAGE_NAME);
+
+ verify(mListener1, times(2)).onCompatChange(PACKAGE_NAME);
+ }
+
+ @Test
+ public void testListenerCalledOnSetOverridesTwoListenersForTest() {
+ PlatformCompat pc = new PlatformCompat(mContext);
+ pc.registerListener(1, mListener1);
+
+ final ImmutableSet<Long> enabled = ImmutableSet.of(1L);
+ final ImmutableSet<Long> disabled = ImmutableSet.of(2L);
+
+ pc.setOverridesForTest(
+ new CompatibilityChangeConfig(
+ new Compatibility.ChangeConfig(enabled, disabled)),
+ PACKAGE_NAME);
+
+ verify(mListener1, times(1)).onCompatChange(PACKAGE_NAME);
+ verify(mListener2, never()).onCompatChange(PACKAGE_NAME);
+
+ reset(mListener1);
+ reset(mListener2);
+
+ pc.registerListener(2, mListener2);
+ pc.setOverridesForTest(
+ new CompatibilityChangeConfig(
+ new Compatibility.ChangeConfig(enabled, disabled)),
+ PACKAGE_NAME);
+
+ verify(mListener1, times(1)).onCompatChange(PACKAGE_NAME);
+ verify(mListener2, times(1)).onCompatChange(PACKAGE_NAME);
+ }
+
+ @Test
+ public void testListenerCalledOnClearOverrides() {
+ PlatformCompat pc = new PlatformCompat(mContext);
+
+ pc.registerListener(1, mListener1);
+ pc.registerListener(2, mListener2);
+
+ pc.setOverrides(
+ new CompatibilityChangeConfig(
+ new Compatibility.ChangeConfig(ImmutableSet.of(1L), ImmutableSet.of())),
+ PACKAGE_NAME);
+ verify(mListener1, times(1)).onCompatChange(PACKAGE_NAME);
+ verify(mListener2, never()).onCompatChange(PACKAGE_NAME);
+
+ reset(mListener1);
+ reset(mListener2);
+
+ pc.clearOverrides(PACKAGE_NAME);
+ verify(mListener1, times(1)).onCompatChange(PACKAGE_NAME);
+ verify(mListener2, never()).onCompatChange(PACKAGE_NAME);
+ }
+
+ @Test
+ public void testListenerCalledOnClearOverridesMultipleOverrides() {
+ PlatformCompat pc = new PlatformCompat(mContext);
+
+ pc.registerListener(1, mListener1);
+ pc.registerListener(2, mListener2);
+
+ pc.setOverrides(
+ new CompatibilityChangeConfig(
+ new Compatibility.ChangeConfig(ImmutableSet.of(1L), ImmutableSet.of(2L))),
+ PACKAGE_NAME);
+ verify(mListener1, times(1)).onCompatChange(PACKAGE_NAME);
+ verify(mListener2, times(1)).onCompatChange(PACKAGE_NAME);
+
+ reset(mListener1);
+ reset(mListener2);
+
+ pc.clearOverrides(PACKAGE_NAME);
+ verify(mListener1, times(1)).onCompatChange(PACKAGE_NAME);
+ verify(mListener2, times(1)).onCompatChange(PACKAGE_NAME);
+ }
+
+ @Test
+ public void testListenerCalledOnClearOverrideExists() {
+ PlatformCompat pc = new PlatformCompat(mContext);
+
+ pc.registerListener(1, mListener1);
+ pc.registerListener(2, mListener2);
+
+ pc.setOverrides(
+ new CompatibilityChangeConfig(
+ new Compatibility.ChangeConfig(ImmutableSet.of(1L), ImmutableSet.of())),
+ PACKAGE_NAME);
+ verify(mListener1, times(1)).onCompatChange(PACKAGE_NAME);
+ verify(mListener2, never()).onCompatChange(PACKAGE_NAME);
+
+ reset(mListener1);
+ reset(mListener2);
+
+ pc.clearOverride(1, PACKAGE_NAME);
+ verify(mListener1, times(1)).onCompatChange(PACKAGE_NAME);
+ verify(mListener2, never()).onCompatChange(PACKAGE_NAME);
+ }
+
+ @Test
+ public void testListenerCalledOnClearOverrideDoesntExist() {
+ PlatformCompat pc = new PlatformCompat(mContext);
+
+ pc.registerListener(1, mListener1);
+
+ pc.clearOverride(1, PACKAGE_NAME);
+ // Listener not called when a non existing override is removed.
+ verify(mListener1, never()).onCompatChange(PACKAGE_NAME);
+ }
+
+
+}
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
index 64ea59d2fa2d..f86bacf67901 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
@@ -22,6 +22,7 @@ import android.app.IActivityTaskManager;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.backup.IBackupManager;
+import android.app.timedetector.TimeDetector;
import android.app.usage.UsageStatsManagerInternal;
import android.content.Context;
import android.content.Intent;
@@ -229,6 +230,11 @@ public class DevicePolicyManagerServiceTestable extends DevicePolicyManagerServi
AlarmManager getAlarmManager() {return services.alarmManager;}
@Override
+ TimeDetector getTimeDetector() {
+ return services.timeDetector;
+ }
+
+ @Override
LockPatternUtils newLockPatternUtils() {
return services.lockPatternUtils;
}
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index eef77ee1fed0..162e7669cbc0 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -26,9 +26,6 @@ import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_MEDIUM;
import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_NONE;
import static android.app.admin.DevicePolicyManager.WIPE_EUICC;
import static android.app.admin.PasswordMetrics.computeForPassword;
-import static android.os.UserManagerInternal.CAMERA_DISABLED_GLOBALLY;
-import static android.os.UserManagerInternal.CAMERA_DISABLED_LOCALLY;
-import static android.os.UserManagerInternal.CAMERA_NOT_DISABLED;
import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_NONE;
import static com.android.internal.widget.LockPatternUtils.EscrowTokenStateChangeCallback;
@@ -66,6 +63,7 @@ import android.app.admin.DeviceAdminReceiver;
import android.app.admin.DevicePolicyManager;
import android.app.admin.DevicePolicyManagerInternal;
import android.app.admin.PasswordMetrics;
+import android.app.timedetector.ManualTimeSuggestion;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Intent;
@@ -82,6 +80,7 @@ import android.os.Bundle;
import android.os.Process;
import android.os.UserHandle;
import android.os.UserManager;
+import android.os.UserManagerInternal;
import android.platform.test.annotations.Presubmit;
import android.provider.Settings;
import android.security.KeyChain;
@@ -1154,9 +1153,8 @@ public class DevicePolicyManagerTest extends DpmTestBase {
MockUtils.checkUserHandle(UserHandle.USER_SYSTEM));
verify(getServices().userManagerInternal).setDevicePolicyUserRestrictions(
- eq(UserHandle.USER_SYSTEM),
- eq(null),
- eq(true), eq(CAMERA_NOT_DISABLED));
+ eq(UserHandle.USER_SYSTEM), eq(null),
+ eq(UserManagerInternal.OWNER_TYPE_DEVICE_OWNER));
verify(getServices().usageStatsManagerInternal).setActiveAdminApps(
null, UserHandle.USER_SYSTEM);
@@ -1725,8 +1723,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
verify(getServices().userManagerInternal).setDevicePolicyUserRestrictions(
eq(UserHandle.USER_SYSTEM),
MockUtils.checkUserRestrictions(defaultRestrictions),
- eq(true) /* isDeviceOwner */,
- eq(CAMERA_NOT_DISABLED)
+ eq(UserManagerInternal.OWNER_TYPE_DEVICE_OWNER)
);
reset(getServices().userManagerInternal);
@@ -1741,7 +1738,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
verify(getServices().userManagerInternal).setDevicePolicyUserRestrictions(
eq(UserHandle.USER_SYSTEM),
MockUtils.checkUserRestrictions(UserManager.DISALLOW_ADD_USER),
- eq(true), eq(CAMERA_NOT_DISABLED));
+ eq(UserManagerInternal.OWNER_TYPE_DEVICE_OWNER));
reset(getServices().userManagerInternal);
dpm.addUserRestriction(admin1, UserManager.DISALLOW_OUTGOING_CALLS);
@@ -1749,7 +1746,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
eq(UserHandle.USER_SYSTEM),
MockUtils.checkUserRestrictions(UserManager.DISALLOW_OUTGOING_CALLS,
UserManager.DISALLOW_ADD_USER),
- eq(true), eq(CAMERA_NOT_DISABLED));
+ eq(UserManagerInternal.OWNER_TYPE_DEVICE_OWNER));
reset(getServices().userManagerInternal);
DpmTestUtils.assertRestrictions(
@@ -1767,7 +1764,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
verify(getServices().userManagerInternal).setDevicePolicyUserRestrictions(
eq(UserHandle.USER_SYSTEM),
MockUtils.checkUserRestrictions(UserManager.DISALLOW_OUTGOING_CALLS),
- eq(true), eq(CAMERA_NOT_DISABLED));
+ eq(UserManagerInternal.OWNER_TYPE_DEVICE_OWNER));
reset(getServices().userManagerInternal);
DpmTestUtils.assertRestrictions(
@@ -1783,7 +1780,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
verify(getServices().userManagerInternal).setDevicePolicyUserRestrictions(
eq(UserHandle.USER_SYSTEM),
MockUtils.checkUserRestrictions(),
- eq(true), eq(CAMERA_NOT_DISABLED));
+ eq(UserManagerInternal.OWNER_TYPE_DEVICE_OWNER));
reset(getServices().userManagerInternal);
assertNoDeviceOwnerRestrictions();
@@ -1797,7 +1794,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
eq(UserHandle.USER_SYSTEM),
MockUtils.checkUserRestrictions(UserManager.DISALLOW_ADJUST_VOLUME,
UserManager.DISALLOW_UNMUTE_MICROPHONE),
- eq(true), eq(CAMERA_NOT_DISABLED));
+ eq(UserManagerInternal.OWNER_TYPE_DEVICE_OWNER));
reset(getServices().userManagerInternal);
dpm.clearUserRestriction(admin1, UserManager.DISALLOW_ADJUST_VOLUME);
@@ -1809,7 +1806,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
verify(getServices().userManagerInternal).setDevicePolicyUserRestrictions(
eq(UserHandle.USER_SYSTEM),
MockUtils.checkUserRestrictions(UserManager.DISALLOW_ADD_USER),
- eq(true), eq(CAMERA_NOT_DISABLED));
+ eq(UserManagerInternal.OWNER_TYPE_DEVICE_OWNER));
reset(getServices().userManagerInternal);
dpm.addUserRestriction(admin1, UserManager.DISALLOW_FUN);
@@ -1817,16 +1814,16 @@ public class DevicePolicyManagerTest extends DpmTestBase {
eq(UserHandle.USER_SYSTEM),
MockUtils.checkUserRestrictions(UserManager.DISALLOW_FUN,
UserManager.DISALLOW_ADD_USER),
- eq(true), eq(CAMERA_NOT_DISABLED));
+ eq(UserManagerInternal.OWNER_TYPE_DEVICE_OWNER));
reset(getServices().userManagerInternal);
dpm.setCameraDisabled(admin1, true);
verify(getServices().userManagerInternal).setDevicePolicyUserRestrictions(
eq(UserHandle.USER_SYSTEM),
- // DISALLOW_CAMERA will be applied to both local and global.
+ // DISALLOW_CAMERA will be applied globally.
MockUtils.checkUserRestrictions(UserManager.DISALLOW_FUN,
- UserManager.DISALLOW_ADD_USER),
- eq(true), eq(CAMERA_DISABLED_GLOBALLY));
+ UserManager.DISALLOW_ADD_USER, UserManager.DISALLOW_CAMERA),
+ eq(UserManagerInternal.OWNER_TYPE_DEVICE_OWNER));
reset(getServices().userManagerInternal);
}
@@ -1872,7 +1869,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
verify(getServices().userManagerInternal).setDevicePolicyUserRestrictions(
eq(DpmMockContext.CALLER_USER_HANDLE),
MockUtils.checkUserRestrictions(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES),
- eq(false), eq(CAMERA_NOT_DISABLED));
+ eq(UserManagerInternal.OWNER_TYPE_PROFILE_OWNER));
reset(getServices().userManagerInternal);
dpm.addUserRestriction(admin1, UserManager.DISALLOW_OUTGOING_CALLS);
@@ -1880,7 +1877,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
eq(DpmMockContext.CALLER_USER_HANDLE),
MockUtils.checkUserRestrictions(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES,
UserManager.DISALLOW_OUTGOING_CALLS),
- eq(false), eq(CAMERA_NOT_DISABLED));
+ eq(UserManagerInternal.OWNER_TYPE_PROFILE_OWNER));
reset(getServices().userManagerInternal);
DpmTestUtils.assertRestrictions(
@@ -1903,7 +1900,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
verify(getServices().userManagerInternal).setDevicePolicyUserRestrictions(
eq(DpmMockContext.CALLER_USER_HANDLE),
MockUtils.checkUserRestrictions(UserManager.DISALLOW_OUTGOING_CALLS),
- eq(false), eq(CAMERA_NOT_DISABLED));
+ eq(UserManagerInternal.OWNER_TYPE_PROFILE_OWNER));
reset(getServices().userManagerInternal);
DpmTestUtils.assertRestrictions(
@@ -1924,7 +1921,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
verify(getServices().userManagerInternal).setDevicePolicyUserRestrictions(
eq(DpmMockContext.CALLER_USER_HANDLE),
MockUtils.checkUserRestrictions(),
- eq(false), eq(CAMERA_NOT_DISABLED));
+ eq(UserManagerInternal.OWNER_TYPE_PROFILE_OWNER));
reset(getServices().userManagerInternal);
DpmTestUtils.assertRestrictions(
@@ -1946,20 +1943,52 @@ public class DevicePolicyManagerTest extends DpmTestBase {
eq(DpmMockContext.CALLER_USER_HANDLE),
MockUtils.checkUserRestrictions(UserManager.DISALLOW_ADJUST_VOLUME,
UserManager.DISALLOW_UNMUTE_MICROPHONE),
- eq(false), eq(CAMERA_NOT_DISABLED));
+ eq(UserManagerInternal.OWNER_TYPE_PROFILE_OWNER));
reset(getServices().userManagerInternal);
dpm.setCameraDisabled(admin1, true);
verify(getServices().userManagerInternal).setDevicePolicyUserRestrictions(
eq(DpmMockContext.CALLER_USER_HANDLE),
MockUtils.checkUserRestrictions(UserManager.DISALLOW_ADJUST_VOLUME,
- UserManager.DISALLOW_UNMUTE_MICROPHONE),
- eq(false), eq(CAMERA_DISABLED_LOCALLY));
+ UserManager.DISALLOW_UNMUTE_MICROPHONE, UserManager.DISALLOW_CAMERA),
+ eq(UserManagerInternal.OWNER_TYPE_PROFILE_OWNER));
reset(getServices().userManagerInternal);
// TODO Make sure restrictions are written to the file.
}
+ public void testSetUserRestriction_asPoOfOrgOwnedDevice() throws Exception {
+ setupProfileOwner();
+
+ final long ident = mServiceContext.binder.clearCallingIdentity();
+ configureContextForAccess(mServiceContext, true);
+
+ mServiceContext.binder.callingUid =
+ UserHandle.getUid(DpmMockContext.CALLER_USER_HANDLE,
+ DpmMockContext.CALLER_MANAGED_PROVISIONING_UID);
+ try {
+ runAsCaller(mServiceContext, dpms, dpm -> {
+ dpm.markProfileOwnerOnOrganizationOwnedDevice(admin1);
+ });
+ } finally {
+ mServiceContext.binder.restoreCallingIdentity(ident);
+ }
+
+ dpm.addUserRestriction(admin1, UserManager.DISALLOW_CONFIG_DATE_TIME);
+ verify(getServices().userManagerInternal).setDevicePolicyUserRestrictions(
+ eq(DpmMockContext.CALLER_USER_HANDLE),
+ MockUtils.checkUserRestrictions(UserManager.DISALLOW_CONFIG_DATE_TIME),
+ eq(UserManagerInternal.OWNER_TYPE_PROFILE_OWNER_OF_ORGANIZATION_OWNED_DEVICE));
+ reset(getServices().userManagerInternal);
+
+ dpm.setCameraDisabled(admin1, true);
+ verify(getServices().userManagerInternal).setDevicePolicyUserRestrictions(
+ eq(DpmMockContext.CALLER_USER_HANDLE),
+ MockUtils.checkUserRestrictions(UserManager.DISALLOW_CONFIG_DATE_TIME,
+ UserManager.DISALLOW_CAMERA),
+ eq(UserManagerInternal.OWNER_TYPE_PROFILE_OWNER_OF_ORGANIZATION_OWNED_DEVICE));
+ reset(getServices().userManagerInternal);
+ }
public void testDefaultEnabledUserRestrictions() throws Exception {
mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS);
@@ -1994,8 +2023,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
verify(getServices().userManagerInternal).setDevicePolicyUserRestrictions(
eq(UserHandle.USER_SYSTEM),
MockUtils.checkUserRestrictions(defaultRestrictions),
- eq(true) /* isDeviceOwner */,
- eq(CAMERA_NOT_DISABLED)
+ eq(UserManagerInternal.OWNER_TYPE_DEVICE_OWNER)
);
reset(getServices().userManagerInternal);
@@ -2035,10 +2063,9 @@ public class DevicePolicyManagerTest extends DpmTestBase {
dpm.getUserRestrictions(admin1)
);
verify(getServices().userManagerInternal, atLeast(1)).setDevicePolicyUserRestrictions(
- eq(UserHandle.USER_SYSTEM),
- MockUtils.checkUserRestrictions(newDefaultEnabledRestriction),
- eq(true) /* isDeviceOwner */,
- eq(CAMERA_NOT_DISABLED)
+ eq(UserHandle.USER_SYSTEM),
+ MockUtils.checkUserRestrictions(newDefaultEnabledRestriction),
+ eq(UserManagerInternal.OWNER_TYPE_DEVICE_OWNER)
);
reset(getServices().userManagerInternal);
@@ -3588,7 +3615,19 @@ public class DevicePolicyManagerTest extends DpmTestBase {
mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
setupDeviceOwner();
dpm.setTime(admin1, 0);
- verify(getServices().alarmManager).setTime(0);
+
+ BaseMatcher<ManualTimeSuggestion> hasZeroTime = new BaseMatcher<ManualTimeSuggestion>() {
+ @Override
+ public boolean matches(Object item) {
+ final ManualTimeSuggestion suggestion = (ManualTimeSuggestion) item;
+ return suggestion.getUtcTime().getValue() == 0;
+ }
+ @Override
+ public void describeTo(Description description) {
+ description.appendText("ManualTimeSuggestion{utcTime.value=0}");
+ }
+ };
+ verify(getServices().timeDetector).suggestManualTime(argThat(hasZeroTime));
}
public void testSetTimeFailWithPO() throws Exception {
@@ -5143,7 +5182,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
configureContextForAccess(mContext, false);
assertExpectException(SecurityException.class, /* messageRegex= */ null,
- () -> dpm.setProfileOwnerCanAccessDeviceIds(admin2));
+ () -> dpm.markProfileOwnerOnOrganizationOwnedDevice(admin2));
}
public void testGrantDeviceIdsAccess_notByAuthorizedCaller() throws Exception {
@@ -5151,20 +5190,20 @@ public class DevicePolicyManagerTest extends DpmTestBase {
configureContextForAccess(mContext, false);
assertExpectException(SecurityException.class, /* messageRegex= */ null,
- () -> dpm.setProfileOwnerCanAccessDeviceIds(admin1));
+ () -> dpm.markProfileOwnerOnOrganizationOwnedDevice(admin1));
}
public void testGrantDeviceIdsAccess_byAuthorizedSystemCaller() throws Exception {
setupProfileOwner();
// This method will throw if the system context could not call
- // setProfileOwnerCanAccessDeviceIds successfully.
- configureProfileOwnerForDeviceIdAccess(admin1, DpmMockContext.CALLER_USER_HANDLE);
+ // markProfileOwnerOfOrganizationOwnedDevice successfully.
+ configureProfileOwnerOfOrgOwnedDevice(admin1, DpmMockContext.CALLER_USER_HANDLE);
}
private void configureContextForAccess(DpmMockContext context, boolean granted) {
when(context.spiedContext.checkCallingPermission(
- android.Manifest.permission.GRANT_PROFILE_OWNER_DEVICE_IDS_ACCESS))
+ permission.MARK_DEVICE_ORGANIZATION_OWNED))
.thenReturn(granted ? PackageManager.PERMISSION_GRANTED
: PackageManager.PERMISSION_DENIED);
@@ -5183,7 +5222,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
DpmMockContext.CALLER_MANAGED_PROVISIONING_UID);
try {
runAsCaller(mServiceContext, dpms, dpm -> {
- dpm.setProfileOwnerCanAccessDeviceIds(admin1);
+ dpm.markProfileOwnerOnOrganizationOwnedDevice(admin1);
});
} finally {
mServiceContext.binder.restoreCallingIdentity(ident);
@@ -5221,7 +5260,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
admin1.getPackageName(), DpmMockContext.CALLER_SYSTEM_USER_UID));
setupProfileOwner();
- configureProfileOwnerForDeviceIdAccess(admin1, DpmMockContext.CALLER_USER_HANDLE);
+ configureProfileOwnerOfOrgOwnedDevice(admin1, DpmMockContext.CALLER_USER_HANDLE);
// The profile owner is allowed to request Device ID attestation.
mServiceContext.binder.callingUid = DpmMockContext.CALLER_UID;
@@ -5258,7 +5297,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
dpm -> dpm.setDelegatedScopes(admin1, DpmMockContext.DELEGATE_PACKAGE_NAME,
Arrays.asList(DELEGATION_CERT_INSTALL)));
- configureProfileOwnerForDeviceIdAccess(admin1, DpmMockContext.CALLER_USER_HANDLE);
+ configureProfileOwnerOfOrgOwnedDevice(admin1, DpmMockContext.CALLER_USER_HANDLE);
// Make sure that the profile owner can still request Device ID attestation.
mServiceContext.binder.callingUid = DpmMockContext.CALLER_UID;
@@ -5435,15 +5474,16 @@ public class DevicePolicyManagerTest extends DpmTestBase {
assertTrue(dpm.isPackageAllowedToAccessCalendar(testPackage));
}
- private void configureProfileOwnerForDeviceIdAccess(ComponentName who, int userId) {
+ private void configureProfileOwnerOfOrgOwnedDevice(ComponentName who, int userId) {
when(getServices().userManager.getProfileParent(eq(UserHandle.of(userId))))
.thenReturn(UserHandle.SYSTEM);
-
final long ident = mServiceContext.binder.clearCallingIdentity();
mServiceContext.binder.callingUid =
UserHandle.getUid(DpmMockContext.CALLER_USER_HANDLE, DpmMockContext.SYSTEM_UID);
+
+ configureContextForAccess(mServiceContext, true);
runAsCaller(mServiceContext, dpms, dpm -> {
- dpm.setProfileOwnerCanAccessDeviceIds(who);
+ dpm.markProfileOwnerOnOrganizationOwnedDevice(who);
});
mServiceContext.binder.restoreCallingIdentity(ident);
}
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
index bd513dc083be..1a67576c218f 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
@@ -207,6 +207,8 @@ public class DpmMockContext extends MockContext {
switch (name) {
case Context.ALARM_SERVICE:
return mMockSystemServices.alarmManager;
+ case Context.TIME_DETECTOR_SERVICE:
+ return mMockSystemServices.timeDetector;
case Context.USER_SERVICE:
return mMockSystemServices.userManager;
case Context.POWER_SERVICE:
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java b/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java
index b0d0303a82d9..c9273642635e 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java
@@ -31,6 +31,7 @@ import android.app.IActivityManager;
import android.app.IActivityTaskManager;
import android.app.NotificationManager;
import android.app.backup.IBackupManager;
+import android.app.timedetector.TimeDetector;
import android.app.usage.UsageStatsManagerInternal;
import android.content.BroadcastReceiver;
import android.content.ContentValues;
@@ -111,6 +112,7 @@ public class MockSystemServices {
public final TelephonyManager telephonyManager;
public final AccountManager accountManager;
public final AlarmManager alarmManager;
+ public final TimeDetector timeDetector;
public final KeyChain.KeyChainConnection keyChainConnection;
/** Note this is a partial mock, not a real mock. */
public final PackageManager packageManager;
@@ -152,6 +154,7 @@ public class MockSystemServices {
telephonyManager = mock(TelephonyManager.class);
accountManager = mock(AccountManager.class);
alarmManager = mock(AlarmManager.class);
+ timeDetector = mock(TimeDetector.class);
keyChainConnection = mock(KeyChain.KeyChainConnection.class, RETURNS_DEEP_STUBS);
// Package manager is huge, so we use a partial mock instead.
diff --git a/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java b/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java
new file mode 100644
index 000000000000..269f9180d8a6
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.display;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import android.content.Context;
+import android.os.Handler;
+import android.os.Looper;
+import android.util.SparseArray;
+import android.view.Display;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class DisplayModeDirectorTest {
+ private Context mContext;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ mContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
+ }
+
+ private DisplayModeDirector createDisplayModeDirectorWithDisplayFpsRange(
+ int minFps, int maxFps) {
+ DisplayModeDirector director =
+ new DisplayModeDirector(mContext, new Handler(Looper.getMainLooper()));
+ int displayId = 0;
+ int numModes = maxFps - minFps + 1;
+ Display.Mode[] modes = new Display.Mode[numModes];
+ for (int i = minFps; i <= maxFps; i++) {
+ modes[i - minFps] = new Display.Mode(
+ /*modeId=*/i, /*width=*/1000, /*height=*/1000, /*refreshRate=*/i);
+ }
+ SparseArray<Display.Mode[]> supportedModesByDisplay = new SparseArray<Display.Mode[]>();
+ supportedModesByDisplay.put(displayId, modes);
+ director.injectSupportedModesByDisplay(supportedModesByDisplay);
+ SparseArray<Display.Mode> defaultModesByDisplay = new SparseArray<Display.Mode>();
+ defaultModesByDisplay.put(displayId, modes[0]);
+ director.injectDefaultModeByDisplay(defaultModesByDisplay);
+ return director;
+ }
+
+ private int[] intRange(int min, int max) {
+ int[] range = new int[max - min + 1];
+ for (int i = min; i <= max; i++) {
+ range[i - min] = i;
+ }
+ return range;
+ }
+
+ @Test
+ public void testDisplayModeVoting() {
+ int displayId = 0;
+
+ // With no votes present, DisplayModeDirector should allow any refresh rate.
+ assertEquals(new DisplayModeDirector.DesiredDisplayConfigSpecs(/*defaultModeId=*/60,
+ new DisplayModeDirector.RefreshRateRange(0f, Float.POSITIVE_INFINITY),
+ intRange(60, 90)),
+ createDisplayModeDirectorWithDisplayFpsRange(60, 90).getDesiredDisplayConfigSpecs(
+ displayId));
+
+ int numPriorities =
+ DisplayModeDirector.Vote.MAX_PRIORITY - DisplayModeDirector.Vote.MIN_PRIORITY + 1;
+
+ // Ensure vote priority works as expected. As we add new votes with higher priority, they
+ // should take precedence over lower priority votes.
+ {
+ int minFps = 60;
+ int maxFps = 90;
+ DisplayModeDirector director = createDisplayModeDirectorWithDisplayFpsRange(60, 90);
+ assertTrue(2 * numPriorities < maxFps - minFps + 1);
+ SparseArray<DisplayModeDirector.Vote> votes =
+ new SparseArray<DisplayModeDirector.Vote>();
+ SparseArray<SparseArray<DisplayModeDirector.Vote>> votesByDisplay =
+ new SparseArray<SparseArray<DisplayModeDirector.Vote>>();
+ votesByDisplay.put(displayId, votes);
+ for (int i = 0; i < numPriorities; i++) {
+ int priority = DisplayModeDirector.Vote.MIN_PRIORITY + i;
+ votes.put(
+ priority, DisplayModeDirector.Vote.forRefreshRates(minFps + i, maxFps - i));
+ director.injectVotesByDisplay(votesByDisplay);
+ assertEquals(
+ new DisplayModeDirector.DesiredDisplayConfigSpecs(
+ /*defaultModeId=*/minFps + i,
+ new DisplayModeDirector.RefreshRateRange(minFps + i, maxFps - i),
+ intRange(minFps + i, maxFps - i)),
+ director.getDesiredDisplayConfigSpecs(displayId));
+ }
+ }
+
+ // Ensure lower priority votes are able to influence the final decision, even in the
+ // presence of higher priority votes.
+ {
+ assertTrue(numPriorities >= 2);
+ DisplayModeDirector director = createDisplayModeDirectorWithDisplayFpsRange(60, 90);
+ SparseArray<DisplayModeDirector.Vote> votes =
+ new SparseArray<DisplayModeDirector.Vote>();
+ SparseArray<SparseArray<DisplayModeDirector.Vote>> votesByDisplay =
+ new SparseArray<SparseArray<DisplayModeDirector.Vote>>();
+ votesByDisplay.put(displayId, votes);
+ votes.put(DisplayModeDirector.Vote.MAX_PRIORITY,
+ DisplayModeDirector.Vote.forRefreshRates(65, 85));
+ votes.put(DisplayModeDirector.Vote.MIN_PRIORITY,
+ DisplayModeDirector.Vote.forRefreshRates(70, 80));
+ director.injectVotesByDisplay(votesByDisplay);
+ assertEquals(
+ new DisplayModeDirector.DesiredDisplayConfigSpecs(/*defaultModeId=*/70,
+ new DisplayModeDirector.RefreshRateRange(70, 80), intRange(70, 80)),
+ director.getDesiredDisplayConfigSpecs(displayId));
+ }
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/integrity/engine/RuleEvaluatorTest.java b/services/tests/servicestests/src/com/android/server/integrity/engine/RuleEvaluatorTest.java
index d6773d45c5ed..7a070ee72b5d 100644
--- a/services/tests/servicestests/src/com/android/server/integrity/engine/RuleEvaluatorTest.java
+++ b/services/tests/servicestests/src/com/android/server/integrity/engine/RuleEvaluatorTest.java
@@ -21,12 +21,13 @@ import static com.android.server.integrity.model.IntegrityCheckResult.Effect.DEN
import static org.junit.Assert.assertEquals;
-import com.android.server.integrity.model.AppInstallMetadata;
-import com.android.server.integrity.model.AtomicFormula;
-import com.android.server.integrity.model.AtomicFormula.StringAtomicFormula;
+import android.content.integrity.AppInstallMetadata;
+import android.content.integrity.AtomicFormula;
+import android.content.integrity.AtomicFormula.StringAtomicFormula;
+import android.content.integrity.CompoundFormula;
+import android.content.integrity.Rule;
+
import com.android.server.integrity.model.IntegrityCheckResult;
-import com.android.server.integrity.model.OpenFormula;
-import com.android.server.integrity.model.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -63,7 +64,9 @@ public class RuleEvaluatorTest {
public void testEvaluateRules_noMatchedRules_allow() {
Rule rule1 =
new Rule(
- new StringAtomicFormula(AtomicFormula.PACKAGE_NAME, PACKAGE_NAME_2,
+ new StringAtomicFormula(
+ AtomicFormula.PACKAGE_NAME,
+ PACKAGE_NAME_2,
/* isHashedValue= */ false),
Rule.DENY);
@@ -77,12 +80,16 @@ public class RuleEvaluatorTest {
public void testEvaluateRules_oneMatch_deny() {
Rule rule1 =
new Rule(
- new StringAtomicFormula(AtomicFormula.PACKAGE_NAME, PACKAGE_NAME_1,
+ new StringAtomicFormula(
+ AtomicFormula.PACKAGE_NAME,
+ PACKAGE_NAME_1,
/* isHashedValue= */ false),
Rule.DENY);
Rule rule2 =
new Rule(
- new StringAtomicFormula(AtomicFormula.PACKAGE_NAME, PACKAGE_NAME_2,
+ new StringAtomicFormula(
+ AtomicFormula.PACKAGE_NAME,
+ PACKAGE_NAME_2,
/* isHashedValue= */ false),
Rule.DENY);
@@ -97,19 +104,24 @@ public class RuleEvaluatorTest {
public void testEvaluateRules_multipleMatches_deny() {
Rule rule1 =
new Rule(
- new StringAtomicFormula(AtomicFormula.PACKAGE_NAME, PACKAGE_NAME_1,
+ new StringAtomicFormula(
+ AtomicFormula.PACKAGE_NAME,
+ PACKAGE_NAME_1,
/* isHashedValue= */ false),
Rule.DENY);
- OpenFormula openFormula2 =
- new OpenFormula(
- OpenFormula.AND,
+ CompoundFormula compoundFormula2 =
+ new CompoundFormula(
+ CompoundFormula.AND,
Arrays.asList(
- new StringAtomicFormula(AtomicFormula.PACKAGE_NAME, PACKAGE_NAME_1,
+ new StringAtomicFormula(
+ AtomicFormula.PACKAGE_NAME,
+ PACKAGE_NAME_1,
/* isHashedValue= */ false),
new StringAtomicFormula(
- AtomicFormula.APP_CERTIFICATE, APP_CERTIFICATE,
+ AtomicFormula.APP_CERTIFICATE,
+ APP_CERTIFICATE,
/* isHashedValue= */ false)));
- Rule rule2 = new Rule(openFormula2, Rule.DENY);
+ Rule rule2 = new Rule(compoundFormula2, Rule.DENY);
IntegrityCheckResult result =
RuleEvaluator.evaluateRules(Arrays.asList(rule1, rule2), APP_INSTALL_METADATA);
@@ -120,14 +132,15 @@ public class RuleEvaluatorTest {
@Test
public void testEvaluateRules_ruleWithNot_deny() {
- OpenFormula openFormula =
- new OpenFormula(
- OpenFormula.NOT,
+ CompoundFormula compoundFormula =
+ new CompoundFormula(
+ CompoundFormula.NOT,
Collections.singletonList(
new StringAtomicFormula(
AtomicFormula.PACKAGE_NAME,
- PACKAGE_NAME_2, /* isHashedValue= */ false)));
- Rule rule = new Rule(openFormula, Rule.DENY);
+ PACKAGE_NAME_2,
+ /* isHashedValue= */ false)));
+ Rule rule = new Rule(compoundFormula, Rule.DENY);
IntegrityCheckResult result =
RuleEvaluator.evaluateRules(Collections.singletonList(rule), APP_INSTALL_METADATA);
@@ -153,16 +166,19 @@ public class RuleEvaluatorTest {
@Test
public void testEvaluateRules_validForm_deny() {
- OpenFormula openFormula =
- new OpenFormula(
- OpenFormula.AND,
+ CompoundFormula compoundFormula =
+ new CompoundFormula(
+ CompoundFormula.AND,
Arrays.asList(
- new StringAtomicFormula(AtomicFormula.PACKAGE_NAME, PACKAGE_NAME_1,
+ new StringAtomicFormula(
+ AtomicFormula.PACKAGE_NAME,
+ PACKAGE_NAME_1,
/* isHashedValue= */ false),
new StringAtomicFormula(
- AtomicFormula.APP_CERTIFICATE, APP_CERTIFICATE,
+ AtomicFormula.APP_CERTIFICATE,
+ APP_CERTIFICATE,
/* isHashedValue= */ false)));
- Rule rule = new Rule(openFormula, Rule.DENY);
+ Rule rule = new Rule(compoundFormula, Rule.DENY);
IntegrityCheckResult result =
RuleEvaluator.evaluateRules(Collections.singletonList(rule), APP_INSTALL_METADATA);
@@ -173,16 +189,19 @@ public class RuleEvaluatorTest {
@Test
public void testEvaluateRules_ruleNotInDNF_ignoreAndAllow() {
- OpenFormula openFormula =
- new OpenFormula(
- OpenFormula.OR,
+ CompoundFormula compoundFormula =
+ new CompoundFormula(
+ CompoundFormula.OR,
Arrays.asList(
- new StringAtomicFormula(AtomicFormula.PACKAGE_NAME, PACKAGE_NAME_1,
+ new StringAtomicFormula(
+ AtomicFormula.PACKAGE_NAME,
+ PACKAGE_NAME_1,
/* isHashedValue= */ false),
new StringAtomicFormula(
- AtomicFormula.APP_CERTIFICATE, APP_CERTIFICATE,
+ AtomicFormula.APP_CERTIFICATE,
+ APP_CERTIFICATE,
/* isHashedValue= */ false)));
- Rule rule = new Rule(openFormula, Rule.DENY);
+ Rule rule = new Rule(compoundFormula, Rule.DENY);
IntegrityCheckResult result =
RuleEvaluator.evaluateRules(Collections.singletonList(rule), APP_INSTALL_METADATA);
@@ -191,19 +210,22 @@ public class RuleEvaluatorTest {
}
@Test
- public void testEvaluateRules_openFormulaWithNot_allow() {
- OpenFormula openSubFormula =
- new OpenFormula(
- OpenFormula.AND,
+ public void testEvaluateRules_compoundFormulaWithNot_allow() {
+ CompoundFormula openSubFormula =
+ new CompoundFormula(
+ CompoundFormula.AND,
Arrays.asList(
- new StringAtomicFormula(AtomicFormula.PACKAGE_NAME, PACKAGE_NAME_2,
+ new StringAtomicFormula(
+ AtomicFormula.PACKAGE_NAME,
+ PACKAGE_NAME_2,
/* isHashedValue= */ false),
new StringAtomicFormula(
- AtomicFormula.APP_CERTIFICATE, APP_CERTIFICATE,
+ AtomicFormula.APP_CERTIFICATE,
+ APP_CERTIFICATE,
/* isHashedValue= */ false)));
- OpenFormula openFormula =
- new OpenFormula(OpenFormula.NOT, Collections.singletonList(openSubFormula));
- Rule rule = new Rule(openFormula, Rule.DENY);
+ CompoundFormula compoundFormula =
+ new CompoundFormula(CompoundFormula.NOT, Collections.singletonList(openSubFormula));
+ Rule rule = new Rule(compoundFormula, Rule.DENY);
IntegrityCheckResult result =
RuleEvaluator.evaluateRules(Collections.singletonList(rule), APP_INSTALL_METADATA);
@@ -215,19 +237,24 @@ public class RuleEvaluatorTest {
public void testEvaluateRules_forceAllow() {
Rule rule1 =
new Rule(
- new StringAtomicFormula(AtomicFormula.PACKAGE_NAME, PACKAGE_NAME_1,
+ new StringAtomicFormula(
+ AtomicFormula.PACKAGE_NAME,
+ PACKAGE_NAME_1,
/* isHashedValue= */ false),
Rule.FORCE_ALLOW);
- OpenFormula openFormula2 =
- new OpenFormula(
- OpenFormula.AND,
+ CompoundFormula compoundFormula2 =
+ new CompoundFormula(
+ CompoundFormula.AND,
Arrays.asList(
- new StringAtomicFormula(AtomicFormula.PACKAGE_NAME, PACKAGE_NAME_1,
+ new StringAtomicFormula(
+ AtomicFormula.PACKAGE_NAME,
+ PACKAGE_NAME_1,
/* isHashedValue= */ false),
new StringAtomicFormula(
- AtomicFormula.APP_CERTIFICATE, APP_CERTIFICATE,
+ AtomicFormula.APP_CERTIFICATE,
+ APP_CERTIFICATE,
/* isHashedValue= */ false)));
- Rule rule2 = new Rule(openFormula2, Rule.DENY);
+ Rule rule2 = new Rule(compoundFormula2, Rule.DENY);
IntegrityCheckResult result =
RuleEvaluator.evaluateRules(Arrays.asList(rule1, rule2), APP_INSTALL_METADATA);
diff --git a/services/tests/servicestests/src/com/android/server/integrity/parser/RuleXmlParserTest.java b/services/tests/servicestests/src/com/android/server/integrity/parser/RuleXmlParserTest.java
index 7d71cd4c1b7f..495923d9ccf9 100644
--- a/services/tests/servicestests/src/com/android/server/integrity/parser/RuleXmlParserTest.java
+++ b/services/tests/servicestests/src/com/android/server/integrity/parser/RuleXmlParserTest.java
@@ -20,9 +20,9 @@ import static com.android.server.testutils.TestUtils.assertExpectException;
import static com.google.common.truth.Truth.assertThat;
-import com.android.server.integrity.model.AtomicFormula;
-import com.android.server.integrity.model.OpenFormula;
-import com.android.server.integrity.model.Rule;
+import android.content.integrity.AtomicFormula;
+import android.content.integrity.CompoundFormula;
+import android.content.integrity.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -40,27 +40,37 @@ import java.util.Map;
public class RuleXmlParserTest {
@Test
- public void testXmlStream_validOpenFormula() throws Exception {
+ public void testXmlStream_validCompoundFormula() throws Exception {
Map<String, String> atomicFormulaAttrs = new HashMap<>();
atomicFormulaAttrs.put("K", String.valueOf(AtomicFormula.PACKAGE_NAME));
atomicFormulaAttrs.put("V", "com.app.test");
- String ruleXmlOpenFormula = "<RL>"
- + generateTagWithAttribute(/* tag= */ "R",
- Collections.singletonMap("E", String.valueOf(Rule.DENY)),
- /* closed= */ false)
- + generateTagWithAttribute(/* tag= */ "OF",
- Collections.singletonMap("C", String.valueOf(OpenFormula.NOT)),
- /* closed= */ false)
- + generateTagWithAttribute(/* tag= */ "AF", atomicFormulaAttrs, /* closed= */ true)
- + "</OF>"
- + "</R>"
- + "</RL>";
+ String ruleXmlCompoundFormula =
+ "<RL>"
+ + generateTagWithAttribute(
+ /* tag= */ "R",
+ Collections.singletonMap("E", String.valueOf(Rule.DENY)),
+ /* closed= */ false)
+ + generateTagWithAttribute(
+ /* tag= */ "OF",
+ Collections.singletonMap("C", String.valueOf(CompoundFormula.NOT)),
+ /* closed= */ false)
+ + generateTagWithAttribute(
+ /* tag= */ "AF", atomicFormulaAttrs, /* closed= */ true)
+ + "</OF>"
+ + "</R>"
+ + "</RL>";
RuleParser xmlParser = new RuleXmlParser();
- InputStream inputStream = new ByteArrayInputStream(ruleXmlOpenFormula.getBytes());
- Rule expectedRule = new Rule(new OpenFormula(OpenFormula.NOT, Collections.singletonList(
- new AtomicFormula.StringAtomicFormula(AtomicFormula.PACKAGE_NAME, "com.app.test",
- /* isHashedValue= */ false))),
- Rule.DENY);
+ InputStream inputStream = new ByteArrayInputStream(ruleXmlCompoundFormula.getBytes());
+ Rule expectedRule =
+ new Rule(
+ new CompoundFormula(
+ CompoundFormula.NOT,
+ Collections.singletonList(
+ new AtomicFormula.StringAtomicFormula(
+ AtomicFormula.PACKAGE_NAME,
+ "com.app.test",
+ /* isHashedValue= */ false))),
+ Rule.DENY);
List<Rule> rules = xmlParser.parse(inputStream);
@@ -68,127 +78,172 @@ public class RuleXmlParserTest {
}
@Test
- public void testXmlString_validOpenFormula_notConnector() throws Exception {
+ public void testXmlString_validCompoundFormula_notConnector() throws Exception {
Map<String, String> packageNameAttrs = new HashMap<>();
packageNameAttrs.put("K", String.valueOf(AtomicFormula.PACKAGE_NAME));
packageNameAttrs.put("V", "com.app.test");
- String ruleXmlOpenFormula = "<RL>"
- + generateTagWithAttribute(/* tag= */ "R",
- Collections.singletonMap("E", String.valueOf(Rule.DENY)),
- /* closed= */ false)
- + generateTagWithAttribute(/* tag= */ "OF",
- Collections.singletonMap("C", String.valueOf(OpenFormula.NOT)),
- /* closed= */ false)
- + generateTagWithAttribute(/* tag= */ "AF", packageNameAttrs, /* closed= */ true)
- + "</OF>"
- + "</R>"
- + "</RL>";
+ String ruleXmlCompoundFormula =
+ "<RL>"
+ + generateTagWithAttribute(
+ /* tag= */ "R",
+ Collections.singletonMap("E", String.valueOf(Rule.DENY)),
+ /* closed= */ false)
+ + generateTagWithAttribute(
+ /* tag= */ "OF",
+ Collections.singletonMap("C", String.valueOf(CompoundFormula.NOT)),
+ /* closed= */ false)
+ + generateTagWithAttribute(
+ /* tag= */ "AF", packageNameAttrs, /* closed= */ true)
+ + "</OF>"
+ + "</R>"
+ + "</RL>";
RuleParser xmlParser = new RuleXmlParser();
- Rule expectedRule = new Rule(new OpenFormula(OpenFormula.NOT, Collections.singletonList(
- new AtomicFormula.StringAtomicFormula(AtomicFormula.PACKAGE_NAME, "com.app.test",
- /* isHashedValue= */ false))),
- Rule.DENY);
-
- List<Rule> rules = xmlParser.parse(ruleXmlOpenFormula);
+ Rule expectedRule =
+ new Rule(
+ new CompoundFormula(
+ CompoundFormula.NOT,
+ Collections.singletonList(
+ new AtomicFormula.StringAtomicFormula(
+ AtomicFormula.PACKAGE_NAME,
+ "com.app.test",
+ /* isHashedValue= */ false))),
+ Rule.DENY);
+
+ List<Rule> rules = xmlParser.parse(ruleXmlCompoundFormula);
assertThat(rules).isEqualTo(Collections.singletonList(expectedRule));
}
@Test
- public void testXmlString_validOpenFormula_andConnector() throws Exception {
+ public void testXmlString_validCompoundFormula_andConnector() throws Exception {
Map<String, String> packageNameAttrs = new HashMap<>();
packageNameAttrs.put("K", String.valueOf(AtomicFormula.PACKAGE_NAME));
packageNameAttrs.put("V", "com.app.test");
Map<String, String> appCertificateAttrs = new HashMap<>();
appCertificateAttrs.put("K", String.valueOf(AtomicFormula.APP_CERTIFICATE));
appCertificateAttrs.put("V", "test_cert");
- String ruleXmlOpenFormula = "<RL>"
- + generateTagWithAttribute(/* tag= */ "R",
- Collections.singletonMap("E", String.valueOf(Rule.DENY)),
- /* closed= */ false)
- + generateTagWithAttribute(/* tag= */ "OF",
- Collections.singletonMap("C", String.valueOf(OpenFormula.AND)),
- /* closed= */ false)
- + generateTagWithAttribute(/* tag= */ "AF", packageNameAttrs, /* closed= */ true)
- + generateTagWithAttribute(/* tag= */ "AF", appCertificateAttrs, /* closed= */ true)
- + "</OF>"
- + "</R>"
- + "</RL>";
+ String ruleXmlCompoundFormula =
+ "<RL>"
+ + generateTagWithAttribute(
+ /* tag= */ "R",
+ Collections.singletonMap("E", String.valueOf(Rule.DENY)),
+ /* closed= */ false)
+ + generateTagWithAttribute(
+ /* tag= */ "OF",
+ Collections.singletonMap("C", String.valueOf(CompoundFormula.AND)),
+ /* closed= */ false)
+ + generateTagWithAttribute(
+ /* tag= */ "AF", packageNameAttrs, /* closed= */ true)
+ + generateTagWithAttribute(
+ /* tag= */ "AF", appCertificateAttrs, /* closed= */ true)
+ + "</OF>"
+ + "</R>"
+ + "</RL>";
RuleParser xmlParser = new RuleXmlParser();
- Rule expectedRule = new Rule(new OpenFormula(OpenFormula.AND, Arrays.asList(
- new AtomicFormula.StringAtomicFormula(AtomicFormula.PACKAGE_NAME, "com.app.test",
- /* isHashedValue= */ false),
- new AtomicFormula.StringAtomicFormula(AtomicFormula.APP_CERTIFICATE, "test_cert",
- /* isHashedValue= */ false))),
- Rule.DENY);
-
- List<Rule> rules = xmlParser.parse(ruleXmlOpenFormula);
+ Rule expectedRule =
+ new Rule(
+ new CompoundFormula(
+ CompoundFormula.AND,
+ Arrays.asList(
+ new AtomicFormula.StringAtomicFormula(
+ AtomicFormula.PACKAGE_NAME,
+ "com.app.test",
+ /* isHashedValue= */ false),
+ new AtomicFormula.StringAtomicFormula(
+ AtomicFormula.APP_CERTIFICATE,
+ "test_cert",
+ /* isHashedValue= */ false))),
+ Rule.DENY);
+ List<Rule> rules = xmlParser.parse(ruleXmlCompoundFormula);
assertThat(rules).isEqualTo(Collections.singletonList(expectedRule));
}
@Test
- public void testXmlString_validOpenFormula_orConnector() throws Exception {
+ public void testXmlString_validCompoundFormula_orConnector() throws Exception {
Map<String, String> packageNameAttrs = new HashMap<>();
packageNameAttrs.put("K", String.valueOf(AtomicFormula.PACKAGE_NAME));
packageNameAttrs.put("V", "com.app.test");
Map<String, String> appCertificateAttrs = new HashMap<>();
appCertificateAttrs.put("K", String.valueOf(AtomicFormula.APP_CERTIFICATE));
appCertificateAttrs.put("V", "test_cert");
- String ruleXmlOpenFormula = "<RL>"
- + generateTagWithAttribute(/* tag= */ "R",
- Collections.singletonMap("E", String.valueOf(Rule.DENY)),
- /* closed= */ false)
- + generateTagWithAttribute(/* tag= */ "OF",
- Collections.singletonMap("C", String.valueOf(OpenFormula.OR)),
- /* closed= */ false)
- + generateTagWithAttribute(/* tag= */ "AF", packageNameAttrs, /* closed= */ true)
- + generateTagWithAttribute(/* tag= */ "AF", appCertificateAttrs, /* closed= */ true)
- + "</OF>"
- + "</R>"
- + "</RL>";
+ String ruleXmlCompoundFormula =
+ "<RL>"
+ + generateTagWithAttribute(
+ /* tag= */ "R",
+ Collections.singletonMap("E", String.valueOf(Rule.DENY)),
+ /* closed= */ false)
+ + generateTagWithAttribute(
+ /* tag= */ "OF",
+ Collections.singletonMap("C", String.valueOf(CompoundFormula.OR)),
+ /* closed= */ false)
+ + generateTagWithAttribute(
+ /* tag= */ "AF", packageNameAttrs, /* closed= */ true)
+ + generateTagWithAttribute(
+ /* tag= */ "AF", appCertificateAttrs, /* closed= */ true)
+ + "</OF>"
+ + "</R>"
+ + "</RL>";
RuleParser xmlParser = new RuleXmlParser();
- Rule expectedRule = new Rule(new OpenFormula(OpenFormula.OR, Arrays.asList(
- new AtomicFormula.StringAtomicFormula(AtomicFormula.PACKAGE_NAME, "com.app.test",
- /* isHashedValue= */ false),
- new AtomicFormula.StringAtomicFormula(AtomicFormula.APP_CERTIFICATE, "test_cert",
- /* isHashedValue= */ false))),
- Rule.DENY);
-
- List<Rule> rules = xmlParser.parse(ruleXmlOpenFormula);
+ Rule expectedRule =
+ new Rule(
+ new CompoundFormula(
+ CompoundFormula.OR,
+ Arrays.asList(
+ new AtomicFormula.StringAtomicFormula(
+ AtomicFormula.PACKAGE_NAME,
+ "com.app.test",
+ /* isHashedValue= */ false),
+ new AtomicFormula.StringAtomicFormula(
+ AtomicFormula.APP_CERTIFICATE,
+ "test_cert",
+ /* isHashedValue= */ false))),
+ Rule.DENY);
+
+ List<Rule> rules = xmlParser.parse(ruleXmlCompoundFormula);
assertThat(rules).isEqualTo(Collections.singletonList(expectedRule));
}
@Test
- public void testXmlString_validOpenFormula_differentTagOrder() throws Exception {
+ public void testXmlString_validCompoundFormula_differentTagOrder() throws Exception {
Map<String, String> packageNameAttrs = new HashMap<>();
packageNameAttrs.put("K", String.valueOf(AtomicFormula.PACKAGE_NAME));
packageNameAttrs.put("V", "com.app.test");
- String ruleXmlOpenFormula = "<RL>"
- + generateTagWithAttribute(/* tag= */ "R",
- Collections.singletonMap("E", String.valueOf(Rule.DENY)),
- /* closed= */ false)
- + generateTagWithAttribute(/* tag= */ "OF",
- Collections.singletonMap("C", String.valueOf(OpenFormula.NOT)),
- /* closed= */ false)
- + generateTagWithAttribute(/* tag= */ "AF", packageNameAttrs, /* closed= */ true)
- + "</OF>"
- + "</R>"
- + "</RL>";
+ String ruleXmlCompoundFormula =
+ "<RL>"
+ + generateTagWithAttribute(
+ /* tag= */ "R",
+ Collections.singletonMap("E", String.valueOf(Rule.DENY)),
+ /* closed= */ false)
+ + generateTagWithAttribute(
+ /* tag= */ "OF",
+ Collections.singletonMap("C", String.valueOf(CompoundFormula.NOT)),
+ /* closed= */ false)
+ + generateTagWithAttribute(
+ /* tag= */ "AF", packageNameAttrs, /* closed= */ true)
+ + "</OF>"
+ + "</R>"
+ + "</RL>";
RuleParser xmlParser = new RuleXmlParser();
- Rule expectedRule = new Rule(new OpenFormula(OpenFormula.NOT, Collections.singletonList(
- new AtomicFormula.StringAtomicFormula(AtomicFormula.PACKAGE_NAME, "com.app.test",
- /* isHashedValue= */ false))),
- Rule.DENY);
-
- List<Rule> rules = xmlParser.parse(ruleXmlOpenFormula);
+ Rule expectedRule =
+ new Rule(
+ new CompoundFormula(
+ CompoundFormula.NOT,
+ Collections.singletonList(
+ new AtomicFormula.StringAtomicFormula(
+ AtomicFormula.PACKAGE_NAME,
+ "com.app.test",
+ /* isHashedValue= */ false))),
+ Rule.DENY);
+
+ List<Rule> rules = xmlParser.parse(ruleXmlCompoundFormula);
assertThat(rules).isEqualTo(Collections.singletonList(expectedRule));
}
@Test
- public void testXmlString_invalidOpenFormula_invalidNumberOfFormulas() throws Exception {
+ public void testXmlString_invalidCompoundFormula_invalidNumberOfFormulas() throws Exception {
Map<String, String> packageNameAttrs = new HashMap<>();
packageNameAttrs.put("K", String.valueOf(AtomicFormula.PACKAGE_NAME));
packageNameAttrs.put("V", "com.app.test");
@@ -196,98 +251,116 @@ public class RuleXmlParserTest {
versionCodeAttrs.put("K", String.valueOf(AtomicFormula.VERSION_CODE));
versionCodeAttrs.put("O", String.valueOf(AtomicFormula.EQ));
versionCodeAttrs.put("V", "1");
- String ruleXmlOpenFormula = "<RL>"
- + generateTagWithAttribute(/* tag= */ "R",
- Collections.singletonMap("E", String.valueOf(Rule.DENY)),
- /* closed= */ false)
- + generateTagWithAttribute(/* tag= */ "OF",
- Collections.singletonMap("C", String.valueOf(OpenFormula.NOT)),
- /* closed= */ false)
- + generateTagWithAttribute(/* tag= */ "AF", packageNameAttrs, /* closed= */ true)
- + generateTagWithAttribute(/* tag= */ "AF", versionCodeAttrs, /* closed= */ true)
- + "</OF>"
- + "</R>"
- + "</RL>";
+ String ruleXmlCompoundFormula =
+ "<RL>"
+ + generateTagWithAttribute(
+ /* tag= */ "R",
+ Collections.singletonMap("E", String.valueOf(Rule.DENY)),
+ /* closed= */ false)
+ + generateTagWithAttribute(
+ /* tag= */ "OF",
+ Collections.singletonMap("C", String.valueOf(CompoundFormula.NOT)),
+ /* closed= */ false)
+ + generateTagWithAttribute(
+ /* tag= */ "AF", packageNameAttrs, /* closed= */ true)
+ + generateTagWithAttribute(
+ /* tag= */ "AF", versionCodeAttrs, /* closed= */ true)
+ + "</OF>"
+ + "</R>"
+ + "</RL>";
RuleParser xmlParser = new RuleXmlParser();
assertExpectException(
RuleParseException.class,
/* expectedExceptionMessageRegex */ "Connector NOT must have 1 formula only",
- () -> xmlParser.parse(ruleXmlOpenFormula));
+ () -> xmlParser.parse(ruleXmlCompoundFormula));
}
@Test
- public void testXmlString_invalidOpenFormula_invalidOperator() throws Exception {
+ public void testXmlString_invalidCompoundFormula_invalidOperator() throws Exception {
Map<String, String> packageNameAttrs = new HashMap<>();
packageNameAttrs.put("K", String.valueOf(AtomicFormula.PACKAGE_NAME));
packageNameAttrs.put("O", "INVALID_OPERATOR");
packageNameAttrs.put("V", "com.app.test");
- String ruleXmlOpenFormula = "<RL>"
- + generateTagWithAttribute(/* tag= */ "R",
- Collections.singletonMap("E", String.valueOf(Rule.DENY)),
- /* closed= */ false)
- + generateTagWithAttribute(/* tag= */ "OF",
- Collections.singletonMap("C", String.valueOf(OpenFormula.NOT)),
- /* closed= */ false)
- + generateTagWithAttribute(/* tag= */ "AF", packageNameAttrs, /* closed= */ true)
- + "</OF>"
- + "</R>"
- + "</RL>";
+ String ruleXmlCompoundFormula =
+ "<RL>"
+ + generateTagWithAttribute(
+ /* tag= */ "R",
+ Collections.singletonMap("E", String.valueOf(Rule.DENY)),
+ /* closed= */ false)
+ + generateTagWithAttribute(
+ /* tag= */ "OF",
+ Collections.singletonMap("C", String.valueOf(CompoundFormula.NOT)),
+ /* closed= */ false)
+ + generateTagWithAttribute(
+ /* tag= */ "AF", packageNameAttrs, /* closed= */ true)
+ + "</OF>"
+ + "</R>"
+ + "</RL>";
RuleParser xmlParser = new RuleXmlParser();
assertExpectException(
RuleParseException.class,
/* expectedExceptionMessageRegex */ "For input string: \"INVALID_OPERATOR\"",
- () -> xmlParser.parse(ruleXmlOpenFormula));
+ () -> xmlParser.parse(ruleXmlCompoundFormula));
}
@Test
- public void testXmlString_invalidOpenFormula_invalidEffect() throws Exception {
+ public void testXmlString_invalidCompoundFormula_invalidEffect() throws Exception {
Map<String, String> packageNameAttrs = new HashMap<>();
packageNameAttrs.put("K", String.valueOf(AtomicFormula.PACKAGE_NAME));
packageNameAttrs.put("V", "com.app.test");
- String ruleXmlOpenFormula = "<RL>"
- + generateTagWithAttribute(/* tag= */ "R",
- Collections.singletonMap("E", "INVALID_EFFECT"),
- /* closed= */ false)
- + generateTagWithAttribute(/* tag= */ "OF",
- Collections.singletonMap("C", String.valueOf(OpenFormula.NOT)),
- /* closed= */ false)
- + generateTagWithAttribute(/* tag= */ "AF", packageNameAttrs, /* closed= */ true)
- + "</OF>"
- + "</R>"
- + "</RL>";
+ String ruleXmlCompoundFormula =
+ "<RL>"
+ + generateTagWithAttribute(
+ /* tag= */ "R",
+ Collections.singletonMap("E", "INVALID_EFFECT"),
+ /* closed= */ false)
+ + generateTagWithAttribute(
+ /* tag= */ "OF",
+ Collections.singletonMap("C", String.valueOf(CompoundFormula.NOT)),
+ /* closed= */ false)
+ + generateTagWithAttribute(
+ /* tag= */ "AF", packageNameAttrs, /* closed= */ true)
+ + "</OF>"
+ + "</R>"
+ + "</RL>";
RuleParser xmlParser = new RuleXmlParser();
assertExpectException(
RuleParseException.class,
/* expectedExceptionMessageRegex */ "For input string: \"INVALID_EFFECT\"",
- () -> xmlParser.parse(ruleXmlOpenFormula));
+ () -> xmlParser.parse(ruleXmlCompoundFormula));
}
@Test
- public void testXmlString_invalidOpenFormula_invalidTags() throws Exception {
+ public void testXmlString_invalidCompoundFormula_invalidTags() throws Exception {
Map<String, String> packageNameAttrs = new HashMap<>();
packageNameAttrs.put("K", String.valueOf(AtomicFormula.PACKAGE_NAME));
packageNameAttrs.put("V", "com.app.test");
- String ruleXmlOpenFormula = "<RL>"
- + generateTagWithAttribute(/* tag= */ "R",
- Collections.singletonMap("E", String.valueOf(Rule.DENY)),
- /* closed= */ false)
- + generateTagWithAttribute(/* tag= */ "OF",
- Collections.singletonMap("C", String.valueOf(OpenFormula.NOT)),
- /* closed= */ false)
- + generateTagWithAttribute(/* tag= */ "InvalidAtomicFormula",
- packageNameAttrs, /* closed= */ true)
- + "</OF>"
- + "</R>"
- + "</RL>";
+ String ruleXmlCompoundFormula =
+ "<RL>"
+ + generateTagWithAttribute(
+ /* tag= */ "R",
+ Collections.singletonMap("E", String.valueOf(Rule.DENY)),
+ /* closed= */ false)
+ + generateTagWithAttribute(
+ /* tag= */ "OF",
+ Collections.singletonMap("C", String.valueOf(CompoundFormula.NOT)),
+ /* closed= */ false)
+ + generateTagWithAttribute(
+ /* tag= */ "InvalidAtomicFormula",
+ packageNameAttrs,
+ /* closed= */ true)
+ + "</OF>"
+ + "</R>"
+ + "</RL>";
RuleParser xmlParser = new RuleXmlParser();
assertExpectException(
RuleParseException.class,
/* expectedExceptionMessageRegex */ "Found unexpected tag: InvalidAtomicFormula",
- () -> xmlParser.parse(ruleXmlOpenFormula));
+ () -> xmlParser.parse(ruleXmlCompoundFormula));
}
@Test
@@ -295,18 +368,24 @@ public class RuleXmlParserTest {
Map<String, String> packageNameAttrs = new HashMap<>();
packageNameAttrs.put("K", String.valueOf(AtomicFormula.PACKAGE_NAME));
packageNameAttrs.put("V", "com.app.test");
- String ruleXmlAtomicFormula = "<RL>"
- + generateTagWithAttribute(/* tag= */ "R",
- Collections.singletonMap("E", String.valueOf(Rule.DENY)),
- /* closed= */ false)
- + generateTagWithAttribute(/* tag= */ "AF", packageNameAttrs, /* closed= */ true)
- + "</R>"
- + "</RL>";
+ String ruleXmlAtomicFormula =
+ "<RL>"
+ + generateTagWithAttribute(
+ /* tag= */ "R",
+ Collections.singletonMap("E", String.valueOf(Rule.DENY)),
+ /* closed= */ false)
+ + generateTagWithAttribute(
+ /* tag= */ "AF", packageNameAttrs, /* closed= */ true)
+ + "</R>"
+ + "</RL>";
RuleParser xmlParser = new RuleXmlParser();
- Rule expectedRule = new Rule(
- new AtomicFormula.StringAtomicFormula(AtomicFormula.PACKAGE_NAME, "com.app.test",
- /* isHashedValue= */ false),
- Rule.DENY);
+ Rule expectedRule =
+ new Rule(
+ new AtomicFormula.StringAtomicFormula(
+ AtomicFormula.PACKAGE_NAME,
+ "com.app.test",
+ /* isHashedValue= */ false),
+ Rule.DENY);
List<Rule> rules = xmlParser.parse(ruleXmlAtomicFormula);
@@ -319,17 +398,22 @@ public class RuleXmlParserTest {
versionCodeAttrs.put("K", String.valueOf(AtomicFormula.VERSION_CODE));
versionCodeAttrs.put("O", String.valueOf(AtomicFormula.EQ));
versionCodeAttrs.put("V", "1");
- String ruleXmlAtomicFormula = "<RL>"
- + generateTagWithAttribute(/* tag= */ "R",
- Collections.singletonMap("E", String.valueOf(Rule.DENY)),
- /* closed= */ false)
- + generateTagWithAttribute(/* tag= */ "AF", versionCodeAttrs, /* closed= */ true)
- + "</R>"
- + "</RL>";
+ String ruleXmlAtomicFormula =
+ "<RL>"
+ + generateTagWithAttribute(
+ /* tag= */ "R",
+ Collections.singletonMap("E", String.valueOf(Rule.DENY)),
+ /* closed= */ false)
+ + generateTagWithAttribute(
+ /* tag= */ "AF", versionCodeAttrs, /* closed= */ true)
+ + "</R>"
+ + "</RL>";
RuleParser xmlParser = new RuleXmlParser();
- Rule expectedRule = new Rule(
- new AtomicFormula.IntAtomicFormula(AtomicFormula.VERSION_CODE, AtomicFormula.EQ, 1),
- Rule.DENY);
+ Rule expectedRule =
+ new Rule(
+ new AtomicFormula.IntAtomicFormula(
+ AtomicFormula.VERSION_CODE, AtomicFormula.EQ, 1),
+ Rule.DENY);
List<Rule> rules = xmlParser.parse(ruleXmlAtomicFormula);
@@ -341,17 +425,21 @@ public class RuleXmlParserTest {
Map<String, String> preInstalledAttrs = new HashMap<>();
preInstalledAttrs.put("K", String.valueOf(AtomicFormula.PRE_INSTALLED));
preInstalledAttrs.put("V", "true");
- String ruleXmlAtomicFormula = "<RL>"
- + generateTagWithAttribute(/* tag= */ "R",
- Collections.singletonMap("E", String.valueOf(Rule.DENY)),
- /* closed= */ false)
- + generateTagWithAttribute(/* tag= */ "AF", preInstalledAttrs, /* closed= */ true)
- + "</R>"
- + "</RL>";
+ String ruleXmlAtomicFormula =
+ "<RL>"
+ + generateTagWithAttribute(
+ /* tag= */ "R",
+ Collections.singletonMap("E", String.valueOf(Rule.DENY)),
+ /* closed= */ false)
+ + generateTagWithAttribute(
+ /* tag= */ "AF", preInstalledAttrs, /* closed= */ true)
+ + "</R>"
+ + "</RL>";
RuleParser xmlParser = new RuleXmlParser();
- Rule expectedRule = new Rule(
- new AtomicFormula.BooleanAtomicFormula(AtomicFormula.PRE_INSTALLED, true),
- Rule.DENY);
+ Rule expectedRule =
+ new Rule(
+ new AtomicFormula.BooleanAtomicFormula(AtomicFormula.PRE_INSTALLED, true),
+ Rule.DENY);
List<Rule> rules = xmlParser.parse(ruleXmlAtomicFormula);
@@ -363,18 +451,24 @@ public class RuleXmlParserTest {
Map<String, String> packageNameAttrs = new HashMap<>();
packageNameAttrs.put("K", String.valueOf(AtomicFormula.PACKAGE_NAME));
packageNameAttrs.put("V", "com.app.test");
- String ruleXmlAtomicFormula = "<RL>"
- + generateTagWithAttribute(/* tag= */ "R",
- Collections.singletonMap("E", String.valueOf(Rule.DENY)),
- /* closed= */ false)
- + generateTagWithAttribute(/* tag= */ "AF", packageNameAttrs, /* closed= */ true)
- + "</R>"
- + "</RL>";
+ String ruleXmlAtomicFormula =
+ "<RL>"
+ + generateTagWithAttribute(
+ /* tag= */ "R",
+ Collections.singletonMap("E", String.valueOf(Rule.DENY)),
+ /* closed= */ false)
+ + generateTagWithAttribute(
+ /* tag= */ "AF", packageNameAttrs, /* closed= */ true)
+ + "</R>"
+ + "</RL>";
RuleParser xmlParser = new RuleXmlParser();
- Rule expectedRule = new Rule(
- new AtomicFormula.StringAtomicFormula(AtomicFormula.PACKAGE_NAME, "com.app.test",
- /* isHashedValue= */ false),
- Rule.DENY);
+ Rule expectedRule =
+ new Rule(
+ new AtomicFormula.StringAtomicFormula(
+ AtomicFormula.PACKAGE_NAME,
+ "com.app.test",
+ /* isHashedValue= */ false),
+ Rule.DENY);
List<Rule> rules = xmlParser.parse(ruleXmlAtomicFormula);
@@ -386,13 +480,16 @@ public class RuleXmlParserTest {
Map<String, String> packageNameAttrs = new HashMap<>();
packageNameAttrs.put("BadKey", String.valueOf(AtomicFormula.PACKAGE_NAME));
packageNameAttrs.put("V", "com.app.test");
- String ruleXmlAtomicFormula = "<RL>"
- + generateTagWithAttribute(/* tag= */ "R",
- Collections.singletonMap("E", String.valueOf(Rule.DENY)),
- /* closed= */ false)
- + generateTagWithAttribute(/* tag= */ "AF", packageNameAttrs, /* closed= */ true)
- + "</R>"
- + "</RL>";
+ String ruleXmlAtomicFormula =
+ "<RL>"
+ + generateTagWithAttribute(
+ /* tag= */ "R",
+ Collections.singletonMap("E", String.valueOf(Rule.DENY)),
+ /* closed= */ false)
+ + generateTagWithAttribute(
+ /* tag= */ "AF", packageNameAttrs, /* closed= */ true)
+ + "</R>"
+ + "</RL>";
RuleParser xmlParser = new RuleXmlParser();
assertExpectException(
@@ -406,13 +503,16 @@ public class RuleXmlParserTest {
Map<String, String> packageNameAttrs = new HashMap<>();
packageNameAttrs.put("K", String.valueOf(AtomicFormula.PACKAGE_NAME));
packageNameAttrs.put("V", "com.app.test");
- String ruleXmlAtomicFormula = "<RL>"
- + generateTagWithAttribute(/* tag= */ "R",
- Collections.singletonMap("BadEffect", String.valueOf(Rule.DENY)),
- /* closed= */ false)
- + generateTagWithAttribute(/* tag= */ "AF", packageNameAttrs, /* closed= */ true)
- + "</R>"
- + "</RL>";
+ String ruleXmlAtomicFormula =
+ "<RL>"
+ + generateTagWithAttribute(
+ /* tag= */ "R",
+ Collections.singletonMap("BadEffect", String.valueOf(Rule.DENY)),
+ /* closed= */ false)
+ + generateTagWithAttribute(
+ /* tag= */ "AF", packageNameAttrs, /* closed= */ true)
+ + "</R>"
+ + "</RL>";
RuleParser xmlParser = new RuleXmlParser();
assertExpectException(
RuleParseException.class,
@@ -421,26 +521,31 @@ public class RuleXmlParserTest {
}
@Test
- public void testXmlString_invalidOpenFormula_invalidAttribute() throws Exception {
+ public void testXmlString_invalidCompoundFormula_invalidAttribute() throws Exception {
Map<String, String> packageNameAttrs = new HashMap<>();
packageNameAttrs.put("K", String.valueOf(AtomicFormula.PACKAGE_NAME));
packageNameAttrs.put("V", "com.app.test");
- String ruleXmlOpenFormula = "<RL>"
- + generateTagWithAttribute(/* tag= */ "R",
- Collections.singletonMap("E", String.valueOf(Rule.DENY)),
- /* closed= */ false)
- + generateTagWithAttribute(/* tag= */ "OF",
- Collections.singletonMap("BadConnector", String.valueOf(OpenFormula.NOT)),
- /* closed= */ false)
- + generateTagWithAttribute(/* tag= */ "AF", packageNameAttrs, /* closed= */ true)
- + "</OF>"
- + "</R>"
- + "</RL>";
+ String ruleXmlCompoundFormula =
+ "<RL>"
+ + generateTagWithAttribute(
+ /* tag= */ "R",
+ Collections.singletonMap("E", String.valueOf(Rule.DENY)),
+ /* closed= */ false)
+ + generateTagWithAttribute(
+ /* tag= */ "OF",
+ Collections.singletonMap(
+ "BadConnector", String.valueOf(CompoundFormula.NOT)),
+ /* closed= */ false)
+ + generateTagWithAttribute(
+ /* tag= */ "AF", packageNameAttrs, /* closed= */ true)
+ + "</OF>"
+ + "</R>"
+ + "</RL>";
RuleParser xmlParser = new RuleXmlParser();
assertExpectException(
RuleParseException.class,
/* expectedExceptionMessageRegex */ "Unknown connector: -1",
- () -> xmlParser.parse(ruleXmlOpenFormula));
+ () -> xmlParser.parse(ruleXmlCompoundFormula));
}
@Test
@@ -449,13 +554,16 @@ public class RuleXmlParserTest {
packageNameAttrs.put("K", String.valueOf(AtomicFormula.VERSION_CODE));
packageNameAttrs.put("O", String.valueOf(AtomicFormula.EQ));
packageNameAttrs.put("V", "com.app.test");
- String ruleXmlAtomicFormula = "<RL>"
- + generateTagWithAttribute(/* tag= */ "R",
- Collections.singletonMap("E", String.valueOf(Rule.DENY)),
- /* closed= */ false)
- + generateTagWithAttribute(/* tag= */ "AF", packageNameAttrs, /* closed= */ true)
- + "</R>"
- + "</RL>";
+ String ruleXmlAtomicFormula =
+ "<RL>"
+ + generateTagWithAttribute(
+ /* tag= */ "R",
+ Collections.singletonMap("E", String.valueOf(Rule.DENY)),
+ /* closed= */ false)
+ + generateTagWithAttribute(
+ /* tag= */ "AF", packageNameAttrs, /* closed= */ true)
+ + "</R>"
+ + "</RL>";
RuleParser xmlParser = new RuleXmlParser();
assertExpectException(
@@ -469,15 +577,19 @@ public class RuleXmlParserTest {
Map<String, String> atomicFormulaAttrs = new HashMap<>();
atomicFormulaAttrs.put("K", String.valueOf(AtomicFormula.PACKAGE_NAME));
atomicFormulaAttrs.put("V", "com.app.test");
- String ruleXmlWithNoRuleList = generateTagWithAttribute(/* tag= */ "R",
- Collections.singletonMap("E", String.valueOf(Rule.DENY)),
- /* closed= */ false)
- + generateTagWithAttribute(/* tag= */ "OF",
- Collections.singletonMap("C", String.valueOf(OpenFormula.NOT)),
- /* closed= */ false)
- + generateTagWithAttribute(/* tag= */ "AF", atomicFormulaAttrs, /* closed= */ true)
- + "</OF>"
- + "</R>";
+ String ruleXmlWithNoRuleList =
+ generateTagWithAttribute(
+ /* tag= */ "R",
+ Collections.singletonMap("E", String.valueOf(Rule.DENY)),
+ /* closed= */ false)
+ + generateTagWithAttribute(
+ /* tag= */ "OF",
+ Collections.singletonMap("C", String.valueOf(CompoundFormula.NOT)),
+ /* closed= */ false)
+ + generateTagWithAttribute(
+ /* tag= */ "AF", atomicFormulaAttrs, /* closed= */ true)
+ + "</OF>"
+ + "</R>";
RuleParser xmlParser = new RuleXmlParser();
assertExpectException(
@@ -491,15 +603,19 @@ public class RuleXmlParserTest {
Map<String, String> atomicFormulaAttrs = new HashMap<>();
atomicFormulaAttrs.put("K", String.valueOf(AtomicFormula.PACKAGE_NAME));
atomicFormulaAttrs.put("V", "com.app.test");
- String ruleXmlWithNoRuleList = generateTagWithAttribute(/* tag= */ "R",
- Collections.singletonMap("E", String.valueOf(Rule.DENY)),
- /* closed= */ false)
- + generateTagWithAttribute(/* tag= */ "OF",
- Collections.singletonMap("C", String.valueOf(OpenFormula.NOT)),
- /* closed= */ false)
- + generateTagWithAttribute(/* tag= */ "AF", atomicFormulaAttrs, /* closed= */ true)
- + "</OF>"
- + "</R>";
+ String ruleXmlWithNoRuleList =
+ generateTagWithAttribute(
+ /* tag= */ "R",
+ Collections.singletonMap("E", String.valueOf(Rule.DENY)),
+ /* closed= */ false)
+ + generateTagWithAttribute(
+ /* tag= */ "OF",
+ Collections.singletonMap("C", String.valueOf(CompoundFormula.NOT)),
+ /* closed= */ false)
+ + generateTagWithAttribute(
+ /* tag= */ "AF", atomicFormulaAttrs, /* closed= */ true)
+ + "</OF>"
+ + "</R>";
InputStream inputStream = new ByteArrayInputStream(ruleXmlWithNoRuleList.getBytes());
RuleParser xmlParser = new RuleXmlParser();
@@ -509,8 +625,8 @@ public class RuleXmlParserTest {
() -> xmlParser.parse(inputStream));
}
- private String generateTagWithAttribute(String tag, Map<String, String> attributeValues,
- boolean closed) {
+ private String generateTagWithAttribute(
+ String tag, Map<String, String> attributeValues, boolean closed) {
StringBuilder res = new StringBuilder("<");
res.append(tag);
for (String attribute : attributeValues.keySet()) {
diff --git a/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleXmlSerializerTest.java b/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleXmlSerializerTest.java
index 7eac0b912bf8..180de2f09f09 100644
--- a/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleXmlSerializerTest.java
+++ b/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleXmlSerializerTest.java
@@ -20,13 +20,13 @@ import static com.android.server.testutils.TestUtils.assertExpectException;
import static org.junit.Assert.assertEquals;
-import androidx.annotation.NonNull;
+import android.content.integrity.AppInstallMetadata;
+import android.content.integrity.AtomicFormula;
+import android.content.integrity.CompoundFormula;
+import android.content.integrity.Formula;
+import android.content.integrity.Rule;
-import com.android.server.integrity.model.AppInstallMetadata;
-import com.android.server.integrity.model.AtomicFormula;
-import com.android.server.integrity.model.Formula;
-import com.android.server.integrity.model.OpenFormula;
-import com.android.server.integrity.model.Rule;
+import androidx.annotation.NonNull;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -38,6 +38,7 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
+import java.util.Optional;
@RunWith(JUnit4.class)
public class RuleXmlSerializerTest {
@@ -48,7 +49,9 @@ public class RuleXmlSerializerTest {
RuleSerializer xmlSerializer = new RuleXmlSerializer();
String expectedRules = "<RL />";
- String actualRules = xmlSerializer.serialize(Collections.singletonList(rule));
+ String actualRules =
+ xmlSerializer.serialize(
+ Collections.singletonList(rule), /* formatVersion= */ Optional.empty());
assertEquals(expectedRules, actualRules);
}
@@ -56,53 +59,74 @@ public class RuleXmlSerializerTest {
@Test
public void testXmlString_serializeMultipleRules_oneEmpty() throws Exception {
Rule rule1 = null;
- Rule rule2 = new Rule(
- new AtomicFormula.StringAtomicFormula(AtomicFormula.PACKAGE_NAME, "com.app.test",
- /* isHashedValue= */ false),
- Rule.DENY);
+ Rule rule2 =
+ new Rule(
+ new AtomicFormula.StringAtomicFormula(
+ AtomicFormula.PACKAGE_NAME,
+ "com.app.test",
+ /* isHashedValue= */ false),
+ Rule.DENY);
RuleSerializer xmlSerializer = new RuleXmlSerializer();
Map<String, String> packageNameAttrs = new LinkedHashMap<>();
packageNameAttrs.put("K", String.valueOf(AtomicFormula.PACKAGE_NAME));
packageNameAttrs.put("V", "com.app.test");
packageNameAttrs.put("H", "false");
- String expectedRules = "<RL>"
- + generateTagWithAttribute(/* tag= */ "R",
- Collections.singletonMap("E", String.valueOf(Rule.DENY)),
- /* closed= */ false)
- + generateTagWithAttribute(/* tag= */ "AF", packageNameAttrs, /* closed= */ true)
- + "</R>"
- + "</RL>";
-
- String actualRules = xmlSerializer.serialize(Arrays.asList(rule1, rule2));
+ String expectedRules =
+ "<RL>"
+ + generateTagWithAttribute(
+ /* tag= */ "R",
+ Collections.singletonMap("E", String.valueOf(Rule.DENY)),
+ /* closed= */ false)
+ + generateTagWithAttribute(
+ /* tag= */ "AF", packageNameAttrs, /* closed= */ true)
+ + "</R>"
+ + "</RL>";
+
+ String actualRules =
+ xmlSerializer.serialize(
+ Arrays.asList(rule1, rule2), /* formatVersion= */ Optional.empty());
assertEquals(expectedRules, actualRules);
}
@Test
public void testXmlStream_serializeValidOpenFormula() throws Exception {
- Rule rule = new Rule(new OpenFormula(OpenFormula.NOT,
- Collections.singletonList(
- new AtomicFormula.StringAtomicFormula(AtomicFormula.PACKAGE_NAME,
- "com.app.test", /* isHashedValue= */ false))), Rule.DENY);
+ Rule rule =
+ new Rule(
+ new CompoundFormula(
+ CompoundFormula.NOT,
+ Collections.singletonList(
+ new AtomicFormula.StringAtomicFormula(
+ AtomicFormula.PACKAGE_NAME,
+ "com.app.test",
+ /* isHashedValue= */ false))),
+ Rule.DENY);
RuleSerializer xmlSerializer = new RuleXmlSerializer();
OutputStream outputStream = new ByteArrayOutputStream();
Map<String, String> packageNameAttrs = new LinkedHashMap<>();
packageNameAttrs.put("K", String.valueOf(AtomicFormula.PACKAGE_NAME));
packageNameAttrs.put("V", "com.app.test");
packageNameAttrs.put("H", "false");
- String expectedRules = "<RL>"
- + generateTagWithAttribute(/* tag= */ "R",
- Collections.singletonMap("E", String.valueOf(Rule.DENY)),
- /* closed= */ false)
- + generateTagWithAttribute(/* tag= */ "OF",
- Collections.singletonMap("C", String.valueOf(OpenFormula.NOT)),
- /* closed= */ false)
- + generateTagWithAttribute(/* tag= */ "AF", packageNameAttrs, /* closed= */ true)
- + "</OF>"
- + "</R>"
- + "</RL>";
-
- xmlSerializer.serialize(Collections.singletonList(rule), outputStream);
+ String expectedRules =
+ "<RL>"
+ + generateTagWithAttribute(
+ /* tag= */ "R",
+ Collections.singletonMap("E", String.valueOf(Rule.DENY)),
+ /* closed= */ false)
+ + generateTagWithAttribute(
+ /* tag= */ "OF",
+ Collections.singletonMap("C", String.valueOf(CompoundFormula.NOT)),
+ /* closed= */ false)
+ + generateTagWithAttribute(
+ /* tag= */ "AF", packageNameAttrs, /* closed= */ true)
+ + "</OF>"
+ + "</R>"
+ + "</RL>";
+
+ xmlSerializer.serialize(
+ Collections.singletonList(rule),
+ /* formatVersion= */ Optional.empty(),
+ outputStream);
String actualRules = outputStream.toString();
assertEquals(expectedRules, actualRules);
@@ -110,39 +134,60 @@ public class RuleXmlSerializerTest {
@Test
public void testXmlString_serializeValidOpenFormula_notConnector() throws Exception {
- Rule rule = new Rule(new OpenFormula(OpenFormula.NOT,
- Collections.singletonList(
- new AtomicFormula.StringAtomicFormula(AtomicFormula.PACKAGE_NAME,
- "com.app.test", /* isHashedValue= */ false))), Rule.DENY);
+ Rule rule =
+ new Rule(
+ new CompoundFormula(
+ CompoundFormula.NOT,
+ Collections.singletonList(
+ new AtomicFormula.StringAtomicFormula(
+ AtomicFormula.PACKAGE_NAME,
+ "com.app.test",
+ /* isHashedValue= */ false))),
+ Rule.DENY);
RuleSerializer xmlSerializer = new RuleXmlSerializer();
Map<String, String> packageNameAttrs = new LinkedHashMap<>();
packageNameAttrs.put("K", String.valueOf(AtomicFormula.PACKAGE_NAME));
packageNameAttrs.put("V", "com.app.test");
packageNameAttrs.put("H", "false");
- String expectedRules = "<RL>"
- + generateTagWithAttribute(/* tag= */ "R",
- Collections.singletonMap("E", String.valueOf(Rule.DENY)),
- /* closed= */ false)
- + generateTagWithAttribute(/* tag= */ "OF",
- Collections.singletonMap("C", String.valueOf(OpenFormula.NOT)),
- /* closed= */ false)
- + generateTagWithAttribute(/* tag= */ "AF", packageNameAttrs, /* closed= */ true)
- + "</OF>"
- + "</R>"
- + "</RL>";
-
- String actualRules = xmlSerializer.serialize(Collections.singletonList(rule));
+ String expectedRules =
+ "<RL>"
+ + generateTagWithAttribute(
+ /* tag= */ "R",
+ Collections.singletonMap("E", String.valueOf(Rule.DENY)),
+ /* closed= */ false)
+ + generateTagWithAttribute(
+ /* tag= */ "OF",
+ Collections.singletonMap("C", String.valueOf(CompoundFormula.NOT)),
+ /* closed= */ false)
+ + generateTagWithAttribute(
+ /* tag= */ "AF", packageNameAttrs, /* closed= */ true)
+ + "</OF>"
+ + "</R>"
+ + "</RL>";
+
+ String actualRules =
+ xmlSerializer.serialize(
+ Collections.singletonList(rule), /* formatVersion= */ Optional.empty());
assertEquals(expectedRules, actualRules);
}
@Test
public void testXmlString_serializeValidOpenFormula_andConnector() throws Exception {
- Rule rule = new Rule(new OpenFormula(OpenFormula.AND,
- Arrays.asList(new AtomicFormula.StringAtomicFormula(AtomicFormula.PACKAGE_NAME,
- "com.app.test", /* isHashedValue= */ false),
- new AtomicFormula.StringAtomicFormula(AtomicFormula.APP_CERTIFICATE,
- "test_cert", /* isHashedValue= */ false))), Rule.DENY);
+ Rule rule =
+ new Rule(
+ new CompoundFormula(
+ CompoundFormula.AND,
+ Arrays.asList(
+ new AtomicFormula.StringAtomicFormula(
+ AtomicFormula.PACKAGE_NAME,
+ "com.app.test",
+ /* isHashedValue= */ false),
+ new AtomicFormula.StringAtomicFormula(
+ AtomicFormula.APP_CERTIFICATE,
+ "test_cert",
+ /* isHashedValue= */ false))),
+ Rule.DENY);
RuleSerializer xmlSerializer = new RuleXmlSerializer();
Map<String, String> packageNameAttrs = new LinkedHashMap<>();
packageNameAttrs.put("K", String.valueOf(AtomicFormula.PACKAGE_NAME));
@@ -152,31 +197,47 @@ public class RuleXmlSerializerTest {
appCertificateAttrs.put("K", String.valueOf(AtomicFormula.APP_CERTIFICATE));
appCertificateAttrs.put("V", "test_cert");
appCertificateAttrs.put("H", "false");
- String expectedRules = "<RL>"
- + generateTagWithAttribute(/* tag= */ "R",
- Collections.singletonMap("E", String.valueOf(Rule.DENY)),
- /* closed= */ false)
- + generateTagWithAttribute(/* tag= */ "OF",
- Collections.singletonMap("C", String.valueOf(OpenFormula.AND)),
- /* closed= */ false)
- + generateTagWithAttribute(/* tag= */ "AF", packageNameAttrs, /* closed= */ true)
- + generateTagWithAttribute(/* tag= */ "AF", appCertificateAttrs, /* closed= */ true)
- + "</OF>"
- + "</R>"
- + "</RL>";
-
- String actualRules = xmlSerializer.serialize(Collections.singletonList(rule));
+ String expectedRules =
+ "<RL>"
+ + generateTagWithAttribute(
+ /* tag= */ "R",
+ Collections.singletonMap("E", String.valueOf(Rule.DENY)),
+ /* closed= */ false)
+ + generateTagWithAttribute(
+ /* tag= */ "OF",
+ Collections.singletonMap("C", String.valueOf(CompoundFormula.AND)),
+ /* closed= */ false)
+ + generateTagWithAttribute(
+ /* tag= */ "AF", packageNameAttrs, /* closed= */ true)
+ + generateTagWithAttribute(
+ /* tag= */ "AF", appCertificateAttrs, /* closed= */ true)
+ + "</OF>"
+ + "</R>"
+ + "</RL>";
+
+ String actualRules =
+ xmlSerializer.serialize(
+ Collections.singletonList(rule), /* formatVersion= */ Optional.empty());
assertEquals(expectedRules, actualRules);
}
@Test
public void testXmlString_serializeValidOpenFormula_orConnector() throws Exception {
- Rule rule = new Rule(new OpenFormula(OpenFormula.OR,
- Arrays.asList(new AtomicFormula.StringAtomicFormula(AtomicFormula.PACKAGE_NAME,
- "com.app.test", /* isHashedValue= */ false),
- new AtomicFormula.StringAtomicFormula(AtomicFormula.APP_CERTIFICATE,
- "test_cert", /* isHashedValue= */ false))), Rule.DENY);
+ Rule rule =
+ new Rule(
+ new CompoundFormula(
+ CompoundFormula.OR,
+ Arrays.asList(
+ new AtomicFormula.StringAtomicFormula(
+ AtomicFormula.PACKAGE_NAME,
+ "com.app.test",
+ /* isHashedValue= */ false),
+ new AtomicFormula.StringAtomicFormula(
+ AtomicFormula.APP_CERTIFICATE,
+ "test_cert",
+ /* isHashedValue= */ false))),
+ Rule.DENY);
RuleSerializer xmlSerializer = new RuleXmlSerializer();
Map<String, String> packageNameAttrs = new LinkedHashMap<>();
packageNameAttrs.put("K", String.valueOf(AtomicFormula.PACKAGE_NAME));
@@ -186,89 +247,117 @@ public class RuleXmlSerializerTest {
appCertificateAttrs.put("K", String.valueOf(AtomicFormula.APP_CERTIFICATE));
appCertificateAttrs.put("V", "test_cert");
appCertificateAttrs.put("H", "false");
- String expectedRules = "<RL>"
- + generateTagWithAttribute(/* tag= */ "R",
- Collections.singletonMap("E", String.valueOf(Rule.DENY)),
- /* closed= */ false)
- + generateTagWithAttribute(/* tag= */ "OF",
- Collections.singletonMap("C", String.valueOf(OpenFormula.OR)),
- /* closed= */ false)
- + generateTagWithAttribute(/* tag= */ "AF", packageNameAttrs, /* closed= */ true)
- + generateTagWithAttribute(/* tag= */ "AF", appCertificateAttrs, /* closed= */ true)
- + "</OF>"
- + "</R>"
- + "</RL>";
-
- String actualRules = xmlSerializer.serialize(Collections.singletonList(rule));
+ String expectedRules =
+ "<RL>"
+ + generateTagWithAttribute(
+ /* tag= */ "R",
+ Collections.singletonMap("E", String.valueOf(Rule.DENY)),
+ /* closed= */ false)
+ + generateTagWithAttribute(
+ /* tag= */ "OF",
+ Collections.singletonMap("C", String.valueOf(CompoundFormula.OR)),
+ /* closed= */ false)
+ + generateTagWithAttribute(
+ /* tag= */ "AF", packageNameAttrs, /* closed= */ true)
+ + generateTagWithAttribute(
+ /* tag= */ "AF", appCertificateAttrs, /* closed= */ true)
+ + "</OF>"
+ + "</R>"
+ + "</RL>";
+
+ String actualRules =
+ xmlSerializer.serialize(
+ Collections.singletonList(rule), /* formatVersion= */ Optional.empty());
assertEquals(expectedRules, actualRules);
}
@Test
public void testXmlString_serializeValidAtomicFormula_stringValue() throws Exception {
- Rule rule = new Rule(
- new AtomicFormula.StringAtomicFormula(AtomicFormula.PACKAGE_NAME, "com.app.test",
- /* isHashedValue= */ false),
- Rule.DENY);
+ Rule rule =
+ new Rule(
+ new AtomicFormula.StringAtomicFormula(
+ AtomicFormula.PACKAGE_NAME,
+ "com.app.test",
+ /* isHashedValue= */ false),
+ Rule.DENY);
RuleSerializer xmlSerializer = new RuleXmlSerializer();
Map<String, String> packageNameAttrs = new LinkedHashMap<>();
packageNameAttrs.put("K", String.valueOf(AtomicFormula.PACKAGE_NAME));
packageNameAttrs.put("V", "com.app.test");
packageNameAttrs.put("H", "false");
- String expectedRules = "<RL>"
- + generateTagWithAttribute(/* tag= */ "R",
- Collections.singletonMap("E", String.valueOf(Rule.DENY)),
- /* closed= */ false)
- + generateTagWithAttribute(/* tag= */ "AF", packageNameAttrs, /* closed= */ true)
- + "</R>"
- + "</RL>";
-
- String actualRules = xmlSerializer.serialize(Collections.singletonList(rule));
+ String expectedRules =
+ "<RL>"
+ + generateTagWithAttribute(
+ /* tag= */ "R",
+ Collections.singletonMap("E", String.valueOf(Rule.DENY)),
+ /* closed= */ false)
+ + generateTagWithAttribute(
+ /* tag= */ "AF", packageNameAttrs, /* closed= */ true)
+ + "</R>"
+ + "</RL>";
+
+ String actualRules =
+ xmlSerializer.serialize(
+ Collections.singletonList(rule), /* formatVersion= */ Optional.empty());
assertEquals(expectedRules, actualRules);
}
@Test
public void testXmlString_serializeValidAtomicFormula_integerValue() throws Exception {
- Rule rule = new Rule(
- new AtomicFormula.IntAtomicFormula(AtomicFormula.VERSION_CODE, AtomicFormula.EQ, 1),
- Rule.DENY);
+ Rule rule =
+ new Rule(
+ new AtomicFormula.IntAtomicFormula(
+ AtomicFormula.VERSION_CODE, AtomicFormula.EQ, 1),
+ Rule.DENY);
RuleSerializer xmlSerializer = new RuleXmlSerializer();
Map<String, String> versionCodeAttrs = new LinkedHashMap<>();
versionCodeAttrs.put("K", String.valueOf(AtomicFormula.VERSION_CODE));
versionCodeAttrs.put("O", String.valueOf(AtomicFormula.EQ));
versionCodeAttrs.put("V", "1");
- String expectedRules = "<RL>"
- + generateTagWithAttribute(/* tag= */ "R",
- Collections.singletonMap("E", String.valueOf(Rule.DENY)),
- /* closed= */ false)
- + generateTagWithAttribute(/* tag= */ "AF", versionCodeAttrs, /* closed= */ true)
- + "</R>"
- + "</RL>";
-
- String actualRules = xmlSerializer.serialize(Collections.singletonList(rule));
+ String expectedRules =
+ "<RL>"
+ + generateTagWithAttribute(
+ /* tag= */ "R",
+ Collections.singletonMap("E", String.valueOf(Rule.DENY)),
+ /* closed= */ false)
+ + generateTagWithAttribute(
+ /* tag= */ "AF", versionCodeAttrs, /* closed= */ true)
+ + "</R>"
+ + "</RL>";
+
+ String actualRules =
+ xmlSerializer.serialize(
+ Collections.singletonList(rule), /* formatVersion= */ Optional.empty());
assertEquals(expectedRules, actualRules);
}
@Test
public void testXmlString_serializeValidAtomicFormula_booleanValue() throws Exception {
- Rule rule = new Rule(
- new AtomicFormula.BooleanAtomicFormula(AtomicFormula.PRE_INSTALLED, true),
- Rule.DENY);
+ Rule rule =
+ new Rule(
+ new AtomicFormula.BooleanAtomicFormula(AtomicFormula.PRE_INSTALLED, true),
+ Rule.DENY);
RuleSerializer xmlSerializer = new RuleXmlSerializer();
Map<String, String> preInstalledAttrs = new LinkedHashMap<>();
preInstalledAttrs.put("K", String.valueOf(AtomicFormula.PRE_INSTALLED));
preInstalledAttrs.put("V", "true");
- String expectedRules = "<RL>"
- + generateTagWithAttribute(/* tag= */ "R",
- Collections.singletonMap("E", String.valueOf(Rule.DENY)),
- /* closed= */ false)
- + generateTagWithAttribute(/* tag= */ "AF", preInstalledAttrs, /* closed= */ true)
- + "</R>"
- + "</RL>";
-
- String actualRules = xmlSerializer.serialize(Collections.singletonList(rule));
+ String expectedRules =
+ "<RL>"
+ + generateTagWithAttribute(
+ /* tag= */ "R",
+ Collections.singletonMap("E", String.valueOf(Rule.DENY)),
+ /* closed= */ false)
+ + generateTagWithAttribute(
+ /* tag= */ "AF", preInstalledAttrs, /* closed= */ true)
+ + "</R>"
+ + "</RL>";
+
+ String actualRules =
+ xmlSerializer.serialize(
+ Collections.singletonList(rule), /* formatVersion= */ Optional.empty());
assertEquals(expectedRules, actualRules);
}
@@ -282,11 +371,14 @@ public class RuleXmlSerializerTest {
assertExpectException(
RuleSerializeException.class,
/* expectedExceptionMessageRegex */ "Invalid formula type",
- () -> xmlSerializer.serialize(Collections.singletonList(rule)));
+ () ->
+ xmlSerializer.serialize(
+ Collections.singletonList(rule),
+ /* formatVersion= */ Optional.empty()));
}
- private String generateTagWithAttribute(String tag, Map<String, String> attributeValues,
- boolean closed) {
+ private String generateTagWithAttribute(
+ String tag, Map<String, String> attributeValues, boolean closed) {
StringBuilder res = new StringBuilder("<");
res.append(tag);
for (String attribute : attributeValues.keySet()) {
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserRestrictionsUtilsTest.java b/services/tests/servicestests/src/com/android/server/pm/UserRestrictionsUtilsTest.java
index 2cc5323e56a2..1a630ffa7097 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserRestrictionsUtilsTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserRestrictionsUtilsTest.java
@@ -122,13 +122,15 @@ public class UserRestrictionsUtilsTest extends AndroidTestCase {
final Bundle local = new Bundle();
final Bundle global = new Bundle();
- UserRestrictionsUtils.sortToGlobalAndLocal(null, false /* isDeviceOwner */,
- UserManagerInternal.CAMERA_NOT_DISABLED, global, local);
+ UserRestrictionsUtils.sortToGlobalAndLocal(null,
+ UserManagerInternal.OWNER_TYPE_PROFILE_OWNER,
+ global, local);
assertEquals(0, global.size());
assertEquals(0, local.size());
- UserRestrictionsUtils.sortToGlobalAndLocal(Bundle.EMPTY, false /* isDeviceOwner */,
- UserManagerInternal.CAMERA_NOT_DISABLED, global, local);
+ UserRestrictionsUtils.sortToGlobalAndLocal(Bundle.EMPTY,
+ UserManagerInternal.OWNER_TYPE_PROFILE_OWNER,
+ global, local);
assertEquals(0, global.size());
assertEquals(0, local.size());
@@ -140,8 +142,10 @@ public class UserRestrictionsUtilsTest extends AndroidTestCase {
UserManager.DISALLOW_CONFIG_TETHERING,
UserManager.DISALLOW_OUTGOING_BEAM,
UserManager.DISALLOW_APPS_CONTROL,
- UserManager.ENSURE_VERIFY_APPS
- ), true /* isDeviceOwner */, UserManagerInternal.CAMERA_NOT_DISABLED, global, local);
+ UserManager.ENSURE_VERIFY_APPS,
+ UserManager.DISALLOW_CAMERA
+ ), UserManagerInternal.OWNER_TYPE_DEVICE_OWNER,
+ global, local);
assertRestrictions(newRestrictions(
@@ -154,7 +158,10 @@ public class UserRestrictionsUtilsTest extends AndroidTestCase {
// These can only be set by DO.
UserManager.DISALLOW_USB_FILE_TRANSFER,
- UserManager.DISALLOW_CONFIG_TETHERING
+ UserManager.DISALLOW_CONFIG_TETHERING,
+
+ // This can be set by DO or PO of organisation owned device
+ UserManager.DISALLOW_CAMERA
), global);
assertRestrictions(newRestrictions(
@@ -174,8 +181,10 @@ public class UserRestrictionsUtilsTest extends AndroidTestCase {
UserManager.DISALLOW_CONFIG_TETHERING,
UserManager.DISALLOW_OUTGOING_BEAM,
UserManager.DISALLOW_APPS_CONTROL,
- UserManager.ENSURE_VERIFY_APPS
- ), false /* isDeviceOwner */, UserManagerInternal.CAMERA_NOT_DISABLED, global, local);
+ UserManager.ENSURE_VERIFY_APPS,
+ UserManager.DISALLOW_CAMERA
+ ), UserManagerInternal.OWNER_TYPE_PROFILE_OWNER,
+ global, local);
assertRestrictions(newRestrictions(
// This one is global no matter who sets it.
@@ -193,23 +202,47 @@ public class UserRestrictionsUtilsTest extends AndroidTestCase {
// These can only be set by DO.
UserManager.DISALLOW_USB_FILE_TRANSFER,
- UserManager.DISALLOW_CONFIG_TETHERING
+ UserManager.DISALLOW_CONFIG_TETHERING,
+
+ // This can be set by DO or PO of organisation owned device
+ UserManager.DISALLOW_CAMERA
), local);
+ local.clear();
+ global.clear();
+
+ // Restrictions set by PO of organisation owned device
+ UserRestrictionsUtils.sortToGlobalAndLocal(newRestrictions(
+ UserManager.DISALLOW_CONFIG_DATE_TIME
+ ), UserManagerInternal.OWNER_TYPE_PROFILE_OWNER_OF_ORGANIZATION_OWNED_DEVICE,
+ global, local);
+
+ assertRestrictions(newRestrictions(
+ // This user restriction is global when set by PO of org owned device
+ UserManager.DISALLOW_CONFIG_DATE_TIME
+ ), global);
+ assertEquals(0, local.size());
}
public void testSortToLocalAndGlobalWithCameraDisabled() {
final Bundle local = new Bundle();
final Bundle global = new Bundle();
- UserRestrictionsUtils.sortToGlobalAndLocal(Bundle.EMPTY, false,
- UserManagerInternal.CAMERA_DISABLED_GLOBALLY, global, local);
+ UserRestrictionsUtils.sortToGlobalAndLocal(newRestrictions(UserManager.DISALLOW_CAMERA),
+ UserManagerInternal.OWNER_TYPE_DEVICE_OWNER, global, local);
+ assertRestrictions(newRestrictions(UserManager.DISALLOW_CAMERA), global);
+ assertEquals(0, local.size());
+ global.clear();
+
+ UserRestrictionsUtils.sortToGlobalAndLocal(newRestrictions(UserManager.DISALLOW_CAMERA),
+ UserManagerInternal.OWNER_TYPE_PROFILE_OWNER_OF_ORGANIZATION_OWNED_DEVICE, global,
+ local);
assertRestrictions(newRestrictions(UserManager.DISALLOW_CAMERA), global);
assertEquals(0, local.size());
global.clear();
- UserRestrictionsUtils.sortToGlobalAndLocal(Bundle.EMPTY, false,
- UserManagerInternal.CAMERA_DISABLED_LOCALLY, global, local);
+ UserRestrictionsUtils.sortToGlobalAndLocal(newRestrictions(UserManager.DISALLOW_CAMERA),
+ UserManagerInternal.OWNER_TYPE_PROFILE_OWNER, global, local);
assertEquals(0, global.size());
assertRestrictions(newRestrictions(UserManager.DISALLOW_CAMERA), local);
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserSystemPackageInstallerTest.java b/services/tests/servicestests/src/com/android/server/pm/UserSystemPackageInstallerTest.java
index f492932a0d77..790f2b47cdd5 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserSystemPackageInstallerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserSystemPackageInstallerTest.java
@@ -16,15 +16,15 @@
package com.android.server.pm;
-import static android.content.pm.UserInfo.FLAG_FULL;
-import static android.content.pm.UserInfo.FLAG_GUEST;
-import static android.content.pm.UserInfo.FLAG_MANAGED_PROFILE;
-import static android.content.pm.UserInfo.FLAG_SYSTEM;
+import static android.os.UserManager.USER_TYPE_FULL_GUEST;
+import static android.os.UserManager.USER_TYPE_FULL_SECONDARY;
+import static android.os.UserManager.USER_TYPE_PROFILE_MANAGED;
import static com.android.server.pm.UserSystemPackageInstaller.PACKAGE_WHITELIST_MODE_PROP;
import static com.android.server.pm.UserSystemPackageInstaller.USER_TYPE_PACKAGE_WHITELIST_MODE_DEVICE_DEFAULT;
import static com.android.server.pm.UserSystemPackageInstaller.USER_TYPE_PACKAGE_WHITELIST_MODE_DISABLE;
import static com.android.server.pm.UserSystemPackageInstaller.USER_TYPE_PACKAGE_WHITELIST_MODE_ENFORCE;
+import static com.android.server.pm.UserSystemPackageInstaller.USER_TYPE_PACKAGE_WHITELIST_MODE_IGNORE_OTA;
import static com.android.server.pm.UserSystemPackageInstaller.USER_TYPE_PACKAGE_WHITELIST_MODE_IMPLICIT_WHITELIST;
import static com.android.server.pm.UserSystemPackageInstaller.USER_TYPE_PACKAGE_WHITELIST_MODE_LOG;
@@ -98,7 +98,8 @@ public class UserSystemPackageInstallerTest {
LocalServices.removeServiceForTest(UserManagerInternal.class);
UserManagerService ums = new UserManagerService(InstrumentationRegistry.getContext());
- mUserSystemPackageInstaller = new UserSystemPackageInstaller(ums);
+ ArrayMap<String, UserTypeDetails> userTypes = UserTypeFactory.getUserTypes();
+ mUserSystemPackageInstaller = new UserSystemPackageInstaller(ums, userTypes);
mContext = InstrumentationRegistry.getTargetContext();
}
@@ -130,9 +131,10 @@ public class UserSystemPackageInstallerTest {
public ArrayMap<String, Set<String>> getAndClearPackageToUserTypeWhitelist() {
ArrayMap<String, Set<String>> r = new ArrayMap<>();
r.put("com.android.package1", new ArraySet<>(Arrays.asList(
- "PROFILE", "SYSTEM", "GUEST", "FULL", "invalid-garbage1")));
+ "PROFILE", "SYSTEM", USER_TYPE_FULL_GUEST, "invalid-garbage1")));
r.put("com.android.package2", new ArraySet<>(Arrays.asList(
- "MANAGED_PROFILE")));
+ USER_TYPE_PROFILE_MANAGED)));
+ r.put("com.android.package3", new ArraySet<>(Arrays.asList("FULL")));
return r;
}
@@ -140,18 +142,46 @@ public class UserSystemPackageInstallerTest {
public ArrayMap<String, Set<String>> getAndClearPackageToUserTypeBlacklist() {
ArrayMap<String, Set<String>> r = new ArrayMap<>();
r.put("com.android.package1", new ArraySet<>(Arrays.asList(
- "FULL", "RESTRICTED", "invalid-garbage2")));
+ USER_TYPE_PROFILE_MANAGED, "invalid-garbage2")));
+ // com.android.package2 has nothing blacklisted
+ r.put("com.android.package3", new ArraySet<>(Arrays.asList("SYSTEM")));
return r;
}
};
- final ArrayMap<String, Integer> expectedOutput = getNewPackageToWhitelistedFlagsMap();
- expectedOutput.put("com.android.package1",
- UserInfo.FLAG_PROFILE | FLAG_SYSTEM | FLAG_GUEST);
- expectedOutput.put("com.android.package2",
- UserInfo.FLAG_MANAGED_PROFILE);
+ final ArrayMap<String, UserTypeDetails> userTypes = UserTypeFactory.getUserTypes();
+ // Determine the expected userTypeBitSets based on getUserTypeMask.
+ long expectedUserTypeBitSet1 = 0;
+ expectedUserTypeBitSet1
+ |= mUserSystemPackageInstaller.getUserTypeMask(USER_TYPE_FULL_GUEST);
+ for (int i = 0; i < userTypes.size(); i++) {
+ final String userType = userTypes.keyAt(i);
+ final UserTypeDetails details = userTypes.valueAt(i);
+ if (details.isSystem() || details.isProfile()) {
+ expectedUserTypeBitSet1 |= mUserSystemPackageInstaller.getUserTypeMask(userType);
+ }
+ }
+ expectedUserTypeBitSet1
+ &= ~mUserSystemPackageInstaller.getUserTypeMask(USER_TYPE_PROFILE_MANAGED);
+
+ final long expectedUserTypeBitSet2 =
+ mUserSystemPackageInstaller.getUserTypeMask(USER_TYPE_PROFILE_MANAGED);
+
+ long expectedUserTypeBitSet3 = 0;
+ for (int i = 0; i < userTypes.size(); i++) {
+ final String userType = userTypes.keyAt(i);
+ final UserTypeDetails details = userTypes.valueAt(i);
+ if (details.isFull() && !details.isSystem()) {
+ expectedUserTypeBitSet3 |= mUserSystemPackageInstaller.getUserTypeMask(userType);
+ }
+ }
+
+ final ArrayMap<String, Long> expectedOutput = getNewPackageToWhitelistedBitSetMap();
+ expectedOutput.put("com.android.package1", expectedUserTypeBitSet1);
+ expectedOutput.put("com.android.package2", expectedUserTypeBitSet2);
+ expectedOutput.put("com.android.package3", expectedUserTypeBitSet3);
- final ArrayMap<String, Integer> actualOutput =
+ final ArrayMap<String, Long> actualOutput =
mUserSystemPackageInstaller.determineWhitelistedPackagesForUserTypes(sysConfig);
assertEquals("Incorrect package-to-user mapping.", expectedOutput, actualOutput);
@@ -189,11 +219,12 @@ public class UserSystemPackageInstallerTest {
}
};
- final ArrayMap<String, Integer> expectedOutput = getNewPackageToWhitelistedFlagsMap();
- expectedOutput.put("com.android.package3", 0);
- expectedOutput.put("com.android.package4", 0);
+ final ArrayMap<String, Long> expectedOutput = getNewPackageToWhitelistedBitSetMap();
+ expectedOutput.put("com.android.package2", 0L);
+ expectedOutput.put("com.android.package3", 0L);
+ expectedOutput.put("com.android.package4", 0L);
- final ArrayMap<String, Integer> actualOutput =
+ final ArrayMap<String, Long> actualOutput =
mUserSystemPackageInstaller.determineWhitelistedPackagesForUserTypes(sysConfig);
assertEquals("Incorrect package-to-user mapping.", expectedOutput, actualOutput);
@@ -209,17 +240,16 @@ public class UserSystemPackageInstallerTest {
final String packageName3 = "pkg3"; // whitelisted for a different user type
final String packageName4 = "pkg4"; // not whitelisted nor blacklisted at all
- final ArrayMap<String, Integer> pkgFlgMap = new ArrayMap<>(); // Whitelist: pkgs per flags
- pkgFlgMap.put(packageName1, FLAG_FULL);
- pkgFlgMap.put(packageName2, 0);
- pkgFlgMap.put(packageName3, FLAG_MANAGED_PROFILE);
+ // Whitelist: user type bitset for each pkg (for the test, all that matters is 0 vs non-0).
+ final ArrayMap<String, Long> pkgBitSetMap = new ArrayMap<>();
+ pkgBitSetMap.put(packageName1, 0b01L);
+ pkgBitSetMap.put(packageName2, 0L);
+ pkgBitSetMap.put(packageName3, 0b10L);
- // Whitelist of pkgs for this specific user, i.e. subset of pkgFlagMap for this user.
+ // Whitelist of pkgs for this specific user, i.e. subset of pkgBitSetMap for this user.
final Set<String> userWhitelist = new ArraySet<>();
userWhitelist.add(packageName1);
- final UserSystemPackageInstaller uspi = new UserSystemPackageInstaller(null, pkgFlgMap);
-
final PackageParser.Package pkg1 = new PackageParser.Package(packageName1);
final PackageParser.Package pkg2 = new PackageParser.Package(packageName2);
final PackageParser.Package pkg3 = new PackageParser.Package(packageName3);
@@ -228,26 +258,38 @@ public class UserSystemPackageInstallerTest {
// No implicit whitelist, so only install pkg1.
boolean implicit = false;
boolean isSysUser = false;
- assertTrue(uspi.shouldInstallPackage(pkg1, pkgFlgMap, userWhitelist, implicit, isSysUser));
- assertFalse(uspi.shouldInstallPackage(pkg2, pkgFlgMap, userWhitelist, implicit, isSysUser));
- assertFalse(uspi.shouldInstallPackage(pkg3, pkgFlgMap, userWhitelist, implicit, isSysUser));
- assertFalse(uspi.shouldInstallPackage(pkg4, pkgFlgMap, userWhitelist, implicit, isSysUser));
+ assertTrue(UserSystemPackageInstaller.shouldInstallPackage(
+ pkg1, pkgBitSetMap, userWhitelist, implicit, isSysUser));
+ assertFalse(UserSystemPackageInstaller.shouldInstallPackage(
+ pkg2, pkgBitSetMap, userWhitelist, implicit, isSysUser));
+ assertFalse(UserSystemPackageInstaller.shouldInstallPackage(
+ pkg3, pkgBitSetMap, userWhitelist, implicit, isSysUser));
+ assertFalse(UserSystemPackageInstaller.shouldInstallPackage(
+ pkg4, pkgBitSetMap, userWhitelist, implicit, isSysUser));
// Use implicit whitelist, so install pkg1 and pkg4
implicit = true;
isSysUser = false;
- assertTrue(uspi.shouldInstallPackage(pkg1, pkgFlgMap, userWhitelist, implicit, isSysUser));
- assertFalse(uspi.shouldInstallPackage(pkg2, pkgFlgMap, userWhitelist, implicit, isSysUser));
- assertFalse(uspi.shouldInstallPackage(pkg3, pkgFlgMap, userWhitelist, implicit, isSysUser));
- assertTrue(uspi.shouldInstallPackage(pkg4, pkgFlgMap, userWhitelist, implicit, isSysUser));
+ assertTrue(UserSystemPackageInstaller.shouldInstallPackage(
+ pkg1, pkgBitSetMap, userWhitelist, implicit, isSysUser));
+ assertFalse(UserSystemPackageInstaller.shouldInstallPackage(
+ pkg2, pkgBitSetMap, userWhitelist, implicit, isSysUser));
+ assertFalse(UserSystemPackageInstaller.shouldInstallPackage(
+ pkg3, pkgBitSetMap, userWhitelist, implicit, isSysUser));
+ assertTrue(UserSystemPackageInstaller.shouldInstallPackage(
+ pkg4, pkgBitSetMap, userWhitelist, implicit, isSysUser));
// For user 0 specifically, we always implicitly whitelist.
implicit = false;
isSysUser = true;
- assertTrue(uspi.shouldInstallPackage(pkg1, pkgFlgMap, userWhitelist, implicit, isSysUser));
- assertFalse(uspi.shouldInstallPackage(pkg2, pkgFlgMap, userWhitelist, implicit, isSysUser));
- assertFalse(uspi.shouldInstallPackage(pkg3, pkgFlgMap, userWhitelist, implicit, isSysUser));
- assertTrue(uspi.shouldInstallPackage(pkg4, pkgFlgMap, userWhitelist, implicit, isSysUser));
+ assertTrue(UserSystemPackageInstaller.shouldInstallPackage(
+ pkg1, pkgBitSetMap, userWhitelist, implicit, isSysUser));
+ assertFalse(UserSystemPackageInstaller.shouldInstallPackage(
+ pkg2, pkgBitSetMap, userWhitelist, implicit, isSysUser));
+ assertFalse(UserSystemPackageInstaller.shouldInstallPackage(
+ pkg3, pkgBitSetMap, userWhitelist, implicit, isSysUser));
+ assertTrue(UserSystemPackageInstaller.shouldInstallPackage(
+ pkg4, pkgBitSetMap, userWhitelist, implicit, isSysUser));
}
/**
@@ -256,31 +298,38 @@ public class UserSystemPackageInstallerTest {
*/
@Test
public void testGetWhitelistedPackagesForUserType() {
- final String packageName1 = "pkg1"; // whitelisted for FULL
+ final String[] sortedUserTypes = new String[]{"type_a", "type_b", "type_c", "type_d"};
+ final String nameOfTypeA = sortedUserTypes[0];
+ final String nameOfTypeB = sortedUserTypes[1];
+ final String nameOfTypeC = sortedUserTypes[2];
+ final long maskOfTypeA = 0b0001L;
+ final long maskOfTypeC = 0b0100L;
+
+ final String packageName1 = "pkg1"; // whitelisted for user type A
final String packageName2 = "pkg2"; // blacklisted whenever whitelisted
- final String packageName3 = "pkg3"; // whitelisted for SYSTEM
- final String packageName4 = "pkg4"; // whitelisted for FULL
+ final String packageName3 = "pkg3"; // whitelisted for user type C
+ final String packageName4 = "pkg4"; // whitelisted for user type A
- final ArrayMap<String, Integer> pkgFlagMap = new ArrayMap<>(); // Whitelist: pkgs per flags
- pkgFlagMap.put(packageName1, FLAG_FULL);
- pkgFlagMap.put(packageName2, 0);
- pkgFlagMap.put(packageName3, FLAG_SYSTEM);
- pkgFlagMap.put(packageName4, FLAG_FULL);
+ final ArrayMap<String, Long> pkgBitSetMap = new ArrayMap<>(); // Whitelist: bitset per pkg
+ pkgBitSetMap.put(packageName1, maskOfTypeA);
+ pkgBitSetMap.put(packageName2, 0L);
+ pkgBitSetMap.put(packageName3, maskOfTypeC);
+ pkgBitSetMap.put(packageName4, maskOfTypeA);
- // Whitelist of pkgs for this specific user, i.e. subset of pkgFlagMap for this user.
- final Set<String> expectedUserWhitelist = new ArraySet<>();
- expectedUserWhitelist.add(packageName1);
+ UserSystemPackageInstaller uspi =
+ new UserSystemPackageInstaller(null, pkgBitSetMap, sortedUserTypes);
- UserSystemPackageInstaller uspi = new UserSystemPackageInstaller(null, pkgFlagMap);
-
- Set<String> output = uspi.getWhitelistedPackagesForUserType(FLAG_FULL);
+ Set<String> output = uspi.getWhitelistedPackagesForUserType(nameOfTypeA);
assertEquals("Whitelist for FULL is the wrong size", 2, output.size());
- assertTrue("Whitelist for FULL doesn't contain pkg1", output.contains(packageName1));
- assertTrue("Whitelist for FULL doesn't contain pkg4", output.contains(packageName4));
+ assertTrue("Whitelist for A doesn't contain pkg1", output.contains(packageName1));
+ assertTrue("Whitelist for A doesn't contain pkg4", output.contains(packageName4));
+
+ output = uspi.getWhitelistedPackagesForUserType(nameOfTypeB);
+ assertEquals("Whitelist for B is the wrong size", 0, output.size());
- output = uspi.getWhitelistedPackagesForUserType(FLAG_SYSTEM);
- assertEquals("Whitelist for SYSTEM is the wrong size", 1, output.size());
- assertTrue("Whitelist for SYSTEM doesn't contain pkg1", output.contains(packageName3));
+ output = uspi.getWhitelistedPackagesForUserType(nameOfTypeC);
+ assertEquals("Whitelist for C is the wrong size", 1, output.size());
+ assertTrue("Whitelist for C doesn't contain pkg1", output.contains(packageName3));
}
/**
@@ -291,22 +340,23 @@ public class UserSystemPackageInstallerTest {
*/
@Test
public void testPackagesForCreateUser_full() {
- final int userFlags = UserInfo.FLAG_FULL;
+ final String userTypeToCreate = USER_TYPE_FULL_SECONDARY;
+ final long userTypeMask = mUserSystemPackageInstaller.getUserTypeMask(userTypeToCreate);
setUserTypePackageWhitelistMode(USER_TYPE_PACKAGE_WHITELIST_MODE_ENFORCE);
PackageManager pm = mContext.getPackageManager();
final SystemConfig sysConfig = new SystemConfigTestClass(true);
- final ArrayMap<String, Integer> packageMap =
+ final ArrayMap<String, Long> packageMap =
mUserSystemPackageInstaller.determineWhitelistedPackagesForUserTypes(sysConfig);
final Set<String> expectedPackages = new ArraySet<>(packageMap.size());
for (int i = 0; i < packageMap.size(); i++) {
- if ((userFlags & packageMap.valueAt(i)) != 0) {
+ if ((userTypeMask & packageMap.valueAt(i)) != 0) {
expectedPackages.add(packageMap.keyAt(i));
}
}
final UserManager um = UserManager.get(mContext);
- final UserInfo user = um.createUser("Test User", userFlags);
+ final UserInfo user = um.createUser("Test User", userTypeToCreate, 0);
assertNotNull(user);
mRemoveUsers.add(user.id);
@@ -345,33 +395,45 @@ public class UserSystemPackageInstallerTest {
assertFalse(mUserSystemPackageInstaller.isLogMode());
assertFalse(mUserSystemPackageInstaller.isEnforceMode());
assertFalse(mUserSystemPackageInstaller.isImplicitWhitelistMode());
+ assertFalse(mUserSystemPackageInstaller.isIgnoreOtaMode());
setUserTypePackageWhitelistMode(USER_TYPE_PACKAGE_WHITELIST_MODE_LOG);
assertTrue(mUserSystemPackageInstaller.isLogMode());
assertFalse(mUserSystemPackageInstaller.isEnforceMode());
assertFalse(mUserSystemPackageInstaller.isImplicitWhitelistMode());
+ assertFalse(mUserSystemPackageInstaller.isIgnoreOtaMode());
setUserTypePackageWhitelistMode(USER_TYPE_PACKAGE_WHITELIST_MODE_ENFORCE);
assertFalse(mUserSystemPackageInstaller.isLogMode());
assertTrue(mUserSystemPackageInstaller.isEnforceMode());
assertFalse(mUserSystemPackageInstaller.isImplicitWhitelistMode());
+ assertFalse(mUserSystemPackageInstaller.isIgnoreOtaMode());
setUserTypePackageWhitelistMode(USER_TYPE_PACKAGE_WHITELIST_MODE_IMPLICIT_WHITELIST);
assertFalse(mUserSystemPackageInstaller.isLogMode());
assertFalse(mUserSystemPackageInstaller.isEnforceMode());
assertTrue(mUserSystemPackageInstaller.isImplicitWhitelistMode());
+ assertFalse(mUserSystemPackageInstaller.isIgnoreOtaMode());
+
+ setUserTypePackageWhitelistMode(USER_TYPE_PACKAGE_WHITELIST_MODE_IGNORE_OTA);
+ assertFalse(mUserSystemPackageInstaller.isLogMode());
+ assertFalse(mUserSystemPackageInstaller.isEnforceMode());
+ assertFalse(mUserSystemPackageInstaller.isImplicitWhitelistMode());
+ assertTrue(mUserSystemPackageInstaller.isIgnoreOtaMode());
setUserTypePackageWhitelistMode(
USER_TYPE_PACKAGE_WHITELIST_MODE_LOG | USER_TYPE_PACKAGE_WHITELIST_MODE_ENFORCE);
assertTrue(mUserSystemPackageInstaller.isLogMode());
assertTrue(mUserSystemPackageInstaller.isEnforceMode());
assertFalse(mUserSystemPackageInstaller.isImplicitWhitelistMode());
+ assertFalse(mUserSystemPackageInstaller.isIgnoreOtaMode());
setUserTypePackageWhitelistMode(USER_TYPE_PACKAGE_WHITELIST_MODE_IMPLICIT_WHITELIST
| USER_TYPE_PACKAGE_WHITELIST_MODE_ENFORCE);
assertFalse(mUserSystemPackageInstaller.isLogMode());
assertTrue(mUserSystemPackageInstaller.isEnforceMode());
assertTrue(mUserSystemPackageInstaller.isImplicitWhitelistMode());
+ assertFalse(mUserSystemPackageInstaller.isIgnoreOtaMode());
}
/** Sets the whitelist mode to the desired value via adb's setprop. */
@@ -387,10 +449,11 @@ public class UserSystemPackageInstallerTest {
}
}
- private ArrayMap<String, Integer> getNewPackageToWhitelistedFlagsMap() {
- final ArrayMap<String, Integer> pkgFlagMap = new ArrayMap<>();
- // "android" is always treated as whitelisted, regardless of the xml file.
- pkgFlagMap.put("android", FLAG_SYSTEM | UserInfo.FLAG_FULL | UserInfo.FLAG_PROFILE);
- return pkgFlagMap;
+ /** @see UserSystemPackageInstaller#mWhitelistedPackagesForUserTypes */
+ private ArrayMap<String, Long> getNewPackageToWhitelistedBitSetMap() {
+ final ArrayMap<String, Long> pkgBitSetMap = new ArrayMap<>();
+ // "android" is always treated as whitelisted for all types, regardless of the xml file.
+ pkgBitSetMap.put("android", ~0L);
+ return pkgBitSetMap;
}
}
diff --git a/services/tests/servicestests/src/com/android/server/timedetector/SimpleTimeZoneDetectorStrategyTest.java b/services/tests/servicestests/src/com/android/server/timedetector/SimpleTimeZoneDetectorStrategyTest.java
index d79795593456..317fd4d566ae 100644
--- a/services/tests/servicestests/src/com/android/server/timedetector/SimpleTimeZoneDetectorStrategyTest.java
+++ b/services/tests/servicestests/src/com/android/server/timedetector/SimpleTimeZoneDetectorStrategyTest.java
@@ -23,6 +23,7 @@ import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import android.app.timedetector.ManualTimeSuggestion;
import android.app.timedetector.PhoneTimeSuggestion;
import android.content.Intent;
import android.icu.util.Calendar;
@@ -36,6 +37,8 @@ import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.time.Duration;
+
@RunWith(AndroidJUnit4.class)
public class SimpleTimeZoneDetectorStrategyTest {
@@ -47,6 +50,8 @@ public class SimpleTimeZoneDetectorStrategyTest {
private static final int ARBITRARY_PHONE_ID = 123456;
+ private static final long ONE_DAY_MILLIS = Duration.ofDays(1).toMillis();
+
private Script mScript;
@Before
@@ -55,7 +60,7 @@ public class SimpleTimeZoneDetectorStrategyTest {
}
@Test
- public void testSuggestPhoneTime_nitz_timeDetectionEnabled() {
+ public void testSuggestPhoneTime_autoTimeEnabled() {
Scenario scenario = SCENARIO_1;
mScript.pokeFakeClocks(scenario)
.pokeTimeDetectionEnabled(true);
@@ -67,7 +72,20 @@ public class SimpleTimeZoneDetectorStrategyTest {
mScript.simulateTimePassing(clockIncrement)
.simulatePhoneTimeSuggestion(timeSuggestion)
- .verifySystemClockWasSetAndResetCallTracking(expectSystemClockMillis);
+ .verifySystemClockWasSetAndResetCallTracking(
+ expectSystemClockMillis, true /* expectNetworkBroadcast */);
+ }
+
+ @Test
+ public void testSuggestPhoneTime_emptySuggestionIgnored() {
+ Scenario scenario = SCENARIO_1;
+ mScript.pokeFakeClocks(scenario)
+ .pokeTimeDetectionEnabled(true);
+
+ PhoneTimeSuggestion timeSuggestion = createPhoneTimeSuggestion(ARBITRARY_PHONE_ID, null);
+
+ mScript.simulatePhoneTimeSuggestion(timeSuggestion)
+ .verifySystemClockWasNotSetAndResetCallTracking();
}
@Test
@@ -91,7 +109,8 @@ public class SimpleTimeZoneDetectorStrategyTest {
// Send the first time signal. It should be used.
mScript.simulatePhoneTimeSuggestion(timeSuggestion1)
- .verifySystemClockWasSetAndResetCallTracking(expectSystemClockMillis1);
+ .verifySystemClockWasSetAndResetCallTracking(
+ expectSystemClockMillis1, true /* expectNetworkBroadcast */);
// Now send another time signal, but one that is too similar to the last one and should be
// ignored.
@@ -99,7 +118,8 @@ public class SimpleTimeZoneDetectorStrategyTest {
TimestampedValue<Long> utcTime2 = new TimestampedValue<>(
mScript.peekElapsedRealtimeMillis(),
mScript.peekSystemClockMillis() + underThresholdMillis);
- PhoneTimeSuggestion timeSuggestion2 = new PhoneTimeSuggestion(ARBITRARY_PHONE_ID, utcTime2);
+ PhoneTimeSuggestion timeSuggestion2 =
+ createPhoneTimeSuggestion(ARBITRARY_PHONE_ID, utcTime2);
mScript.simulateTimePassing(clockIncrement)
.simulatePhoneTimeSuggestion(timeSuggestion2)
.verifySystemClockWasNotSetAndResetCallTracking();
@@ -109,18 +129,20 @@ public class SimpleTimeZoneDetectorStrategyTest {
mScript.peekElapsedRealtimeMillis(),
mScript.peekSystemClockMillis() + systemClockUpdateThresholdMillis);
- PhoneTimeSuggestion timeSuggestion3 = new PhoneTimeSuggestion(ARBITRARY_PHONE_ID, utcTime3);
+ PhoneTimeSuggestion timeSuggestion3 =
+ createPhoneTimeSuggestion(ARBITRARY_PHONE_ID, utcTime3);
mScript.simulateTimePassing(clockIncrement);
long expectSystemClockMillis3 =
TimeDetectorStrategy.getTimeAt(utcTime3, mScript.peekElapsedRealtimeMillis());
mScript.simulatePhoneTimeSuggestion(timeSuggestion3)
- .verifySystemClockWasSetAndResetCallTracking(expectSystemClockMillis3);
+ .verifySystemClockWasSetAndResetCallTracking(
+ expectSystemClockMillis3, true /* expectNetworkBroadcast */);
}
@Test
- public void testSuggestPhoneTime_nitz_timeDetectionDisabled() {
+ public void testSuggestPhoneTime_autoTimeDisabled() {
Scenario scenario = SCENARIO_1;
mScript.pokeFakeClocks(scenario)
.pokeTimeDetectionEnabled(false);
@@ -132,7 +154,7 @@ public class SimpleTimeZoneDetectorStrategyTest {
}
@Test
- public void testSuggestPhoneTime_nitz_invalidNitzReferenceTimesIgnored() {
+ public void testSuggestPhoneTime_invalidNitzReferenceTimesIgnored() {
Scenario scenario = SCENARIO_1;
final int systemClockUpdateThreshold = 2000;
mScript.pokeFakeClocks(scenario)
@@ -147,7 +169,8 @@ public class SimpleTimeZoneDetectorStrategyTest {
long expectedSystemClockMillis1 =
TimeDetectorStrategy.getTimeAt(utcTime1, mScript.peekElapsedRealtimeMillis());
mScript.simulatePhoneTimeSuggestion(timeSuggestion1)
- .verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis1);
+ .verifySystemClockWasSetAndResetCallTracking(
+ expectedSystemClockMillis1, true /* expectNetworkBroadcast */);
// The UTC time increment should be larger than the system clock update threshold so we
// know it shouldn't be ignored for other reasons.
@@ -158,7 +181,8 @@ public class SimpleTimeZoneDetectorStrategyTest {
long referenceTimeBeforeLastSignalMillis = utcTime1.getReferenceTimeMillis() - 1;
TimestampedValue<Long> utcTime2 = new TimestampedValue<>(
referenceTimeBeforeLastSignalMillis, validUtcTimeMillis);
- PhoneTimeSuggestion timeSuggestion2 = new PhoneTimeSuggestion(ARBITRARY_PHONE_ID, utcTime2);
+ PhoneTimeSuggestion timeSuggestion2 =
+ createPhoneTimeSuggestion(ARBITRARY_PHONE_ID, utcTime2);
mScript.simulatePhoneTimeSuggestion(timeSuggestion2)
.verifySystemClockWasNotSetAndResetCallTracking();
@@ -168,7 +192,8 @@ public class SimpleTimeZoneDetectorStrategyTest {
utcTime1.getReferenceTimeMillis() + Integer.MAX_VALUE + 1;
TimestampedValue<Long> utcTime3 = new TimestampedValue<>(
referenceTimeInFutureMillis, validUtcTimeMillis);
- PhoneTimeSuggestion timeSuggestion3 = new PhoneTimeSuggestion(ARBITRARY_PHONE_ID, utcTime3);
+ PhoneTimeSuggestion timeSuggestion3 =
+ createPhoneTimeSuggestion(ARBITRARY_PHONE_ID, utcTime3);
mScript.simulatePhoneTimeSuggestion(timeSuggestion3)
.verifySystemClockWasNotSetAndResetCallTracking();
@@ -178,9 +203,11 @@ public class SimpleTimeZoneDetectorStrategyTest {
validReferenceTimeMillis, validUtcTimeMillis);
long expectedSystemClockMillis4 =
TimeDetectorStrategy.getTimeAt(utcTime4, mScript.peekElapsedRealtimeMillis());
- PhoneTimeSuggestion timeSuggestion4 = new PhoneTimeSuggestion(ARBITRARY_PHONE_ID, utcTime4);
+ PhoneTimeSuggestion timeSuggestion4 =
+ createPhoneTimeSuggestion(ARBITRARY_PHONE_ID, utcTime4);
mScript.simulatePhoneTimeSuggestion(timeSuggestion4)
- .verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis4);
+ .verifySystemClockWasSetAndResetCallTracking(
+ expectedSystemClockMillis4, true /* expectNetworkBroadcast */);
}
@Test
@@ -212,7 +239,8 @@ public class SimpleTimeZoneDetectorStrategyTest {
// Turn on auto time detection.
mScript.simulateAutoTimeDetectionToggle()
- .verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis1);
+ .verifySystemClockWasSetAndResetCallTracking(
+ expectedSystemClockMillis1, true /* expectNetworkBroadcast */);
// Turn off auto time detection.
mScript.simulateAutoTimeDetectionToggle()
@@ -223,7 +251,8 @@ public class SimpleTimeZoneDetectorStrategyTest {
TimestampedValue<Long> utcTime2 = new TimestampedValue<>(
mScript.peekElapsedRealtimeMillis(),
mScript.peekSystemClockMillis() + systemClockUpdateThreshold);
- PhoneTimeSuggestion timeSuggestion2 = new PhoneTimeSuggestion(ARBITRARY_PHONE_ID, utcTime2);
+ PhoneTimeSuggestion timeSuggestion2 =
+ createPhoneTimeSuggestion(ARBITRARY_PHONE_ID, utcTime2);
// Simulate more time passing.
mScript.simulateTimePassing(clockIncrementMillis);
@@ -238,7 +267,99 @@ public class SimpleTimeZoneDetectorStrategyTest {
// Turn on auto time detection.
mScript.simulateAutoTimeDetectionToggle()
- .verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis2);
+ .verifySystemClockWasSetAndResetCallTracking(
+ expectedSystemClockMillis2, true /* expectNetworkBroadcast */);
+ }
+
+ @Test
+ public void testSuggestManualTime_autoTimeDisabled() {
+ Scenario scenario = SCENARIO_1;
+ mScript.pokeFakeClocks(scenario)
+ .pokeTimeDetectionEnabled(false);
+
+ ManualTimeSuggestion timeSuggestion = scenario.createManualTimeSuggestionForActual();
+ final int clockIncrement = 1000;
+ long expectSystemClockMillis = scenario.getActualTimeMillis() + clockIncrement;
+
+ mScript.simulateTimePassing(clockIncrement)
+ .simulateManualTimeSuggestion(timeSuggestion)
+ .verifySystemClockWasSetAndResetCallTracking(
+ expectSystemClockMillis, false /* expectNetworkBroadcast */);
+ }
+
+ @Test
+ public void testSuggestManualTime_retainsAutoSignal() {
+ Scenario scenario = SCENARIO_1;
+
+ // Configure the start state.
+ mScript.pokeFakeClocks(scenario)
+ .pokeTimeDetectionEnabled(true);
+
+ // Simulate a phone suggestion.
+ PhoneTimeSuggestion phoneTimeSuggestion =
+ scenario.createPhoneTimeSuggestionForActual(ARBITRARY_PHONE_ID);
+ long expectedAutoClockMillis = phoneTimeSuggestion.getUtcTime().getValue();
+ final int clockIncrement = 1000;
+
+ // Simulate the passage of time.
+ mScript.simulateTimePassing(clockIncrement);
+ expectedAutoClockMillis += clockIncrement;
+
+ mScript.simulatePhoneTimeSuggestion(phoneTimeSuggestion)
+ .verifySystemClockWasSetAndResetCallTracking(
+ expectedAutoClockMillis, true /* expectNetworkBroadcast */);
+
+ // Simulate the passage of time.
+ mScript.simulateTimePassing(clockIncrement);
+ expectedAutoClockMillis += clockIncrement;
+
+ // Switch to manual.
+ mScript.simulateAutoTimeDetectionToggle()
+ .verifySystemClockWasNotSetAndResetCallTracking();
+
+ // Simulate the passage of time.
+ mScript.simulateTimePassing(clockIncrement);
+ expectedAutoClockMillis += clockIncrement;
+
+
+ // Simulate a manual suggestion 1 day different from the auto suggestion.
+ long manualTimeMillis = SCENARIO_1.getActualTimeMillis() + ONE_DAY_MILLIS;
+ long expectedManualClockMillis = manualTimeMillis;
+ ManualTimeSuggestion manualTimeSuggestion = createManualTimeSuggestion(manualTimeMillis);
+ mScript.simulateManualTimeSuggestion(manualTimeSuggestion)
+ .verifySystemClockWasSetAndResetCallTracking(
+ expectedManualClockMillis, false /* expectNetworkBroadcast */);
+
+ // Simulate the passage of time.
+ mScript.simulateTimePassing(clockIncrement);
+ expectedAutoClockMillis += clockIncrement;
+
+ // Switch back to auto.
+ mScript.simulateAutoTimeDetectionToggle();
+
+ mScript.verifySystemClockWasSetAndResetCallTracking(
+ expectedAutoClockMillis, true /* expectNetworkBroadcast */);
+
+ // Switch back to manual - nothing should happen to the clock.
+ mScript.simulateAutoTimeDetectionToggle()
+ .verifySystemClockWasNotSetAndResetCallTracking();
+ }
+
+ /**
+ * Manual suggestions should be ignored if auto time is enabled.
+ */
+ @Test
+ public void testSuggestManualTime_autoTimeEnabled() {
+ Scenario scenario = SCENARIO_1;
+ mScript.pokeFakeClocks(scenario)
+ .pokeTimeDetectionEnabled(true);
+
+ ManualTimeSuggestion timeSuggestion = scenario.createManualTimeSuggestionForActual();
+ final int clockIncrement = 1000;
+
+ mScript.simulateTimePassing(clockIncrement)
+ .simulateManualTimeSuggestion(timeSuggestion)
+ .verifySystemClockWasNotSetAndResetCallTracking();
}
/**
@@ -262,7 +383,7 @@ public class SimpleTimeZoneDetectorStrategyTest {
}
@Override
- public boolean isTimeDetectionEnabled() {
+ public boolean isAutoTimeDetectionEnabled() {
return mTimeDetectionEnabled;
}
@@ -408,8 +529,13 @@ public class SimpleTimeZoneDetectorStrategyTest {
return this;
}
+ Script simulateManualTimeSuggestion(ManualTimeSuggestion timeSuggestion) {
+ mSimpleTimeDetectorStrategy.suggestManualTime(timeSuggestion);
+ return this;
+ }
+
Script simulateAutoTimeDetectionToggle() {
- boolean enabled = !mFakeCallback.isTimeDetectionEnabled();
+ boolean enabled = !mFakeCallback.isAutoTimeDetectionEnabled();
mFakeCallback.pokeTimeDetectionEnabled(enabled);
mSimpleTimeDetectorStrategy.handleAutoTimeDetectionToggle(enabled);
return this;
@@ -427,9 +553,12 @@ public class SimpleTimeZoneDetectorStrategyTest {
return this;
}
- Script verifySystemClockWasSetAndResetCallTracking(long expectSystemClockMillis) {
+ Script verifySystemClockWasSetAndResetCallTracking(
+ long expectSystemClockMillis, boolean expectNetworkBroadcast) {
mFakeCallback.verifySystemClockWasSet(expectSystemClockMillis);
- mFakeCallback.verifyIntentWasBroadcast();
+ if (expectNetworkBroadcast) {
+ mFakeCallback.verifyIntentWasBroadcast();
+ }
mFakeCallback.resetCallTracking();
return this;
}
@@ -465,7 +594,13 @@ public class SimpleTimeZoneDetectorStrategyTest {
PhoneTimeSuggestion createPhoneTimeSuggestionForActual(int phoneId) {
TimestampedValue<Long> time = new TimestampedValue<>(
mInitialDeviceRealtimeMillis, mActualTimeMillis);
- return new PhoneTimeSuggestion(phoneId, time);
+ return createPhoneTimeSuggestion(phoneId, time);
+ }
+
+ ManualTimeSuggestion createManualTimeSuggestionForActual() {
+ TimestampedValue<Long> time = new TimestampedValue<>(
+ mInitialDeviceRealtimeMillis, mActualTimeMillis);
+ return new ManualTimeSuggestion(time);
}
static class Builder {
@@ -500,6 +635,19 @@ public class SimpleTimeZoneDetectorStrategyTest {
}
}
+ private static PhoneTimeSuggestion createPhoneTimeSuggestion(int phoneId,
+ TimestampedValue<Long> utcTime) {
+ PhoneTimeSuggestion timeSuggestion = new PhoneTimeSuggestion(phoneId);
+ timeSuggestion.setUtcTime(utcTime);
+ return timeSuggestion;
+ }
+
+ private ManualTimeSuggestion createManualTimeSuggestion(long timeMillis) {
+ TimestampedValue<Long> utcTime =
+ new TimestampedValue<>(mScript.peekElapsedRealtimeMillis(), timeMillis);
+ return new ManualTimeSuggestion(utcTime);
+ }
+
private static long createUtcTime(int year, int monthInYear, int day, int hourOfDay, int minute,
int second) {
Calendar cal = new GregorianCalendar(TimeZone.getTimeZone("Etc/UTC"));
diff --git a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java
index 37da01824e88..4efe771a4e95 100644
--- a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java
@@ -28,6 +28,7 @@ import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.app.timedetector.ManualTimeSuggestion;
import android.app.timedetector.PhoneTimeSuggestion;
import android.content.Context;
import android.content.pm.PackageManager;
@@ -90,6 +91,19 @@ public class TimeDetectorServiceTest {
}
@Test
+ public void testSuggestManualTime() {
+ doNothing().when(mMockContext).enforceCallingPermission(anyString(), any());
+
+ ManualTimeSuggestion manualTimeSuggestion = createManualTimeSuggestion();
+ mTimeDetectorService.suggestManualTime(manualTimeSuggestion);
+
+ verify(mMockContext).enforceCallingPermission(
+ eq(android.Manifest.permission.SET_TIME),
+ anyString());
+ mStubbedTimeDetectorStrategy.verifySuggestManualTimeCalled(manualTimeSuggestion);
+ }
+
+ @Test
public void testDump() {
when(mMockContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP))
.thenReturn(PackageManager.PERMISSION_GRANTED);
@@ -102,13 +116,13 @@ public class TimeDetectorServiceTest {
@Test
public void testAutoTimeDetectionToggle() {
- when(mMockCallback.isTimeDetectionEnabled()).thenReturn(true);
+ when(mMockCallback.isAutoTimeDetectionEnabled()).thenReturn(true);
mTimeDetectorService.handleAutoTimeDetectionToggle();
mStubbedTimeDetectorStrategy.verifyHandleAutoTimeDetectionToggleCalled(true);
- when(mMockCallback.isTimeDetectionEnabled()).thenReturn(false);
+ when(mMockCallback.isAutoTimeDetectionEnabled()).thenReturn(false);
mTimeDetectorService.handleAutoTimeDetectionToggle();
@@ -117,14 +131,22 @@ public class TimeDetectorServiceTest {
private static PhoneTimeSuggestion createPhoneTimeSuggestion() {
int phoneId = 1234;
+ PhoneTimeSuggestion suggestion = new PhoneTimeSuggestion(phoneId);
TimestampedValue<Long> timeValue = new TimestampedValue<>(100L, 1_000_000L);
- return new PhoneTimeSuggestion(phoneId, timeValue);
+ suggestion.setUtcTime(timeValue);
+ return suggestion;
+ }
+
+ private static ManualTimeSuggestion createManualTimeSuggestion() {
+ TimestampedValue<Long> timeValue = new TimestampedValue<>(100L, 1_000_000L);
+ return new ManualTimeSuggestion(timeValue);
}
private static class StubbedTimeDetectorStrategy implements TimeDetectorStrategy {
// Call tracking.
private PhoneTimeSuggestion mLastPhoneSuggestion;
+ private ManualTimeSuggestion mLastManualSuggestion;
private Boolean mLastAutoTimeDetectionToggle;
private boolean mDumpCalled;
@@ -139,6 +161,12 @@ public class TimeDetectorServiceTest {
}
@Override
+ public void suggestManualTime(ManualTimeSuggestion timeSuggestion) {
+ resetCallTracking();
+ mLastManualSuggestion = timeSuggestion;
+ }
+
+ @Override
public void handleAutoTimeDetectionToggle(boolean enabled) {
resetCallTracking();
mLastAutoTimeDetectionToggle = enabled;
@@ -152,12 +180,17 @@ public class TimeDetectorServiceTest {
void resetCallTracking() {
mLastPhoneSuggestion = null;
+ mLastManualSuggestion = null;
mLastAutoTimeDetectionToggle = null;
mDumpCalled = false;
}
- void verifySuggestPhoneTimeCalled(PhoneTimeSuggestion expectedSignal) {
- assertEquals(expectedSignal, mLastPhoneSuggestion);
+ void verifySuggestPhoneTimeCalled(PhoneTimeSuggestion expectedSuggestion) {
+ assertEquals(expectedSuggestion, mLastPhoneSuggestion);
+ }
+
+ public void verifySuggestManualTimeCalled(ManualTimeSuggestion expectedSuggestion) {
+ assertEquals(expectedSuggestion, mLastManualSuggestion);
}
void verifyHandleAutoTimeDetectionToggleCalled(boolean expectedEnable) {
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyTest.java b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyTest.java
new file mode 100644
index 000000000000..f9f23c3605ce
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyTest.java
@@ -0,0 +1,592 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.timezonedetector;
+
+import static android.app.timezonedetector.PhoneTimeZoneSuggestion.MATCH_TYPE_EMULATOR_ZONE_ID;
+import static android.app.timezonedetector.PhoneTimeZoneSuggestion.MATCH_TYPE_NETWORK_COUNTRY_AND_OFFSET;
+import static android.app.timezonedetector.PhoneTimeZoneSuggestion.MATCH_TYPE_NETWORK_COUNTRY_ONLY;
+import static android.app.timezonedetector.PhoneTimeZoneSuggestion.MATCH_TYPE_TEST_NETWORK_OFFSET_ONLY;
+import static android.app.timezonedetector.PhoneTimeZoneSuggestion.QUALITY_MULTIPLE_ZONES_WITH_DIFFERENT_OFFSETS;
+import static android.app.timezonedetector.PhoneTimeZoneSuggestion.QUALITY_MULTIPLE_ZONES_WITH_SAME_OFFSET;
+import static android.app.timezonedetector.PhoneTimeZoneSuggestion.QUALITY_SINGLE_ZONE;
+
+import static com.android.server.timezonedetector.TimeZoneDetectorStrategy.SCORE_HIGH;
+import static com.android.server.timezonedetector.TimeZoneDetectorStrategy.SCORE_HIGHEST;
+import static com.android.server.timezonedetector.TimeZoneDetectorStrategy.SCORE_LOW;
+import static com.android.server.timezonedetector.TimeZoneDetectorStrategy.SCORE_MEDIUM;
+import static com.android.server.timezonedetector.TimeZoneDetectorStrategy.SCORE_NONE;
+import static com.android.server.timezonedetector.TimeZoneDetectorStrategy.SCORE_USAGE_THRESHOLD;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import android.app.timezonedetector.PhoneTimeZoneSuggestion;
+import android.app.timezonedetector.PhoneTimeZoneSuggestion.MatchType;
+import android.app.timezonedetector.PhoneTimeZoneSuggestion.Quality;
+
+import com.android.server.timezonedetector.TimeZoneDetectorStrategy.QualifiedPhoneTimeZoneSuggestion;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.LinkedList;
+
+/**
+ * White-box unit tests for {@link TimeZoneDetectorStrategy}.
+ */
+public class TimeZoneDetectorStrategyTest {
+
+ /** A time zone used for initialization that does not occur elsewhere in tests. */
+ private static final String ARBITRARY_TIME_ZONE_ID = "Etc/UTC";
+ private static final int PHONE1_ID = 10000;
+ private static final int PHONE2_ID = 20000;
+
+ // Suggestion test cases are ordered so that each successive one is of the same or higher score
+ // than the previous.
+ private static final SuggestionTestCase[] TEST_CASES = new SuggestionTestCase[] {
+ newTestCase(MATCH_TYPE_NETWORK_COUNTRY_ONLY,
+ QUALITY_MULTIPLE_ZONES_WITH_DIFFERENT_OFFSETS, SCORE_LOW),
+ newTestCase(MATCH_TYPE_NETWORK_COUNTRY_ONLY, QUALITY_MULTIPLE_ZONES_WITH_SAME_OFFSET,
+ SCORE_MEDIUM),
+ newTestCase(MATCH_TYPE_NETWORK_COUNTRY_AND_OFFSET,
+ QUALITY_MULTIPLE_ZONES_WITH_SAME_OFFSET, SCORE_MEDIUM),
+ newTestCase(MATCH_TYPE_NETWORK_COUNTRY_ONLY, QUALITY_SINGLE_ZONE, SCORE_HIGH),
+ newTestCase(MATCH_TYPE_NETWORK_COUNTRY_AND_OFFSET, QUALITY_SINGLE_ZONE, SCORE_HIGH),
+ newTestCase(MATCH_TYPE_TEST_NETWORK_OFFSET_ONLY,
+ QUALITY_MULTIPLE_ZONES_WITH_SAME_OFFSET, SCORE_HIGHEST),
+ newTestCase(MATCH_TYPE_EMULATOR_ZONE_ID, QUALITY_SINGLE_ZONE, SCORE_HIGHEST),
+ };
+
+ private TimeZoneDetectorStrategy mTimeZoneDetectorStrategy;
+ private FakeTimeZoneDetectorStrategyCallback mFakeTimeZoneDetectorStrategyCallback;
+
+ @Before
+ public void setUp() {
+ mFakeTimeZoneDetectorStrategyCallback = new FakeTimeZoneDetectorStrategyCallback();
+ mTimeZoneDetectorStrategy =
+ new TimeZoneDetectorStrategy(mFakeTimeZoneDetectorStrategyCallback);
+ }
+
+ @Test
+ public void testEmptySuggestions() {
+ PhoneTimeZoneSuggestion phone1TimeZoneSuggestion = createEmptyPhone1Suggestion();
+ PhoneTimeZoneSuggestion phone2TimeZoneSuggestion = createEmptyPhone2Suggestion();
+ Script script = new Script()
+ .initializeTimeZoneDetectionEnabled(true)
+ .initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID);
+
+ script.suggestPhoneTimeZone(phone1TimeZoneSuggestion)
+ .verifyTimeZoneNotSet();
+
+ // Assert internal service state.
+ QualifiedPhoneTimeZoneSuggestion expectedPhone1ScoredSuggestion =
+ new QualifiedPhoneTimeZoneSuggestion(phone1TimeZoneSuggestion, SCORE_NONE);
+ assertEquals(expectedPhone1ScoredSuggestion,
+ mTimeZoneDetectorStrategy.getLatestPhoneSuggestion(PHONE1_ID));
+ assertNull(mTimeZoneDetectorStrategy.getLatestPhoneSuggestion(PHONE2_ID));
+ assertEquals(expectedPhone1ScoredSuggestion,
+ mTimeZoneDetectorStrategy.findBestSuggestionForTests());
+
+ script.suggestPhoneTimeZone(phone2TimeZoneSuggestion)
+ .verifyTimeZoneNotSet();
+
+ // Assert internal service state.
+ QualifiedPhoneTimeZoneSuggestion expectedPhone2ScoredSuggestion =
+ new QualifiedPhoneTimeZoneSuggestion(phone2TimeZoneSuggestion, SCORE_NONE);
+ assertEquals(expectedPhone1ScoredSuggestion,
+ mTimeZoneDetectorStrategy.getLatestPhoneSuggestion(PHONE1_ID));
+ assertEquals(expectedPhone2ScoredSuggestion,
+ mTimeZoneDetectorStrategy.getLatestPhoneSuggestion(PHONE2_ID));
+ // Phone 1 should always beat phone 2, all other things being equal.
+ assertEquals(expectedPhone1ScoredSuggestion,
+ mTimeZoneDetectorStrategy.findBestSuggestionForTests());
+ }
+
+ @Test
+ public void testFirstPlausibleSuggestionAcceptedWhenTimeZoneUninitialized() {
+ SuggestionTestCase testCase = newTestCase(MATCH_TYPE_NETWORK_COUNTRY_ONLY,
+ QUALITY_MULTIPLE_ZONES_WITH_DIFFERENT_OFFSETS, SCORE_LOW);
+ PhoneTimeZoneSuggestion lowQualitySuggestion =
+ testCase.createSuggestion(PHONE1_ID, "America/New_York");
+
+ // The device time zone setting is left uninitialized.
+ Script script = new Script()
+ .initializeTimeZoneDetectionEnabled(true);
+
+ // The very first suggestion will be taken.
+ script.suggestPhoneTimeZone(lowQualitySuggestion)
+ .verifyTimeZoneSetAndReset(lowQualitySuggestion);
+
+ // Assert internal service state.
+ QualifiedPhoneTimeZoneSuggestion expectedScoredSuggestion =
+ new QualifiedPhoneTimeZoneSuggestion(lowQualitySuggestion, testCase.expectedScore);
+ assertEquals(expectedScoredSuggestion,
+ mTimeZoneDetectorStrategy.getLatestPhoneSuggestion(PHONE1_ID));
+ assertEquals(expectedScoredSuggestion,
+ mTimeZoneDetectorStrategy.findBestSuggestionForTests());
+
+ // Another low quality suggestion will be ignored now that the setting is initialized.
+ PhoneTimeZoneSuggestion lowQualitySuggestion2 =
+ testCase.createSuggestion(PHONE1_ID, "America/Los_Angeles");
+ script.suggestPhoneTimeZone(lowQualitySuggestion2)
+ .verifyTimeZoneNotSet();
+
+ // Assert internal service state.
+ QualifiedPhoneTimeZoneSuggestion expectedScoredSuggestion2 =
+ new QualifiedPhoneTimeZoneSuggestion(lowQualitySuggestion2, testCase.expectedScore);
+ assertEquals(expectedScoredSuggestion2,
+ mTimeZoneDetectorStrategy.getLatestPhoneSuggestion(PHONE1_ID));
+ assertEquals(expectedScoredSuggestion2,
+ mTimeZoneDetectorStrategy.findBestSuggestionForTests());
+ }
+
+ /**
+ * Confirms that toggling the auto time zone detection setting has the expected behavior when
+ * the strategy is "opinionated".
+ */
+ @Test
+ public void testTogglingTimeZoneDetection() {
+ Script script = new Script();
+
+ for (SuggestionTestCase testCase : TEST_CASES) {
+ // Start with the device in a known state.
+ script.initializeTimeZoneDetectionEnabled(false)
+ .initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID);
+
+ PhoneTimeZoneSuggestion suggestion =
+ testCase.createSuggestion(PHONE1_ID, "Europe/London");
+ script.suggestPhoneTimeZone(suggestion);
+
+ // When time zone detection is not enabled, the time zone suggestion will not be set
+ // regardless of the score.
+ script.verifyTimeZoneNotSet();
+
+ // Assert internal service state.
+ QualifiedPhoneTimeZoneSuggestion expectedScoredSuggestion =
+ new QualifiedPhoneTimeZoneSuggestion(suggestion, testCase.expectedScore);
+ assertEquals(expectedScoredSuggestion,
+ mTimeZoneDetectorStrategy.getLatestPhoneSuggestion(PHONE1_ID));
+ assertEquals(expectedScoredSuggestion,
+ mTimeZoneDetectorStrategy.findBestSuggestionForTests());
+
+ // Toggling the time zone setting on should cause the device setting to be set.
+ script.timeZoneDetectionEnabled(true);
+
+ // When time zone detection is already enabled the suggestion (if it scores highly
+ // enough) should be set immediately.
+ if (testCase.expectedScore >= SCORE_USAGE_THRESHOLD) {
+ script.verifyTimeZoneSetAndReset(suggestion);
+ } else {
+ script.verifyTimeZoneNotSet();
+ }
+
+ // Assert internal service state.
+ assertEquals(expectedScoredSuggestion,
+ mTimeZoneDetectorStrategy.getLatestPhoneSuggestion(PHONE1_ID));
+ assertEquals(expectedScoredSuggestion,
+ mTimeZoneDetectorStrategy.findBestSuggestionForTests());
+
+ // Toggling the time zone setting should off should do nothing.
+ script.timeZoneDetectionEnabled(false)
+ .verifyTimeZoneNotSet();
+
+ // Assert internal service state.
+ assertEquals(expectedScoredSuggestion,
+ mTimeZoneDetectorStrategy.getLatestPhoneSuggestion(PHONE1_ID));
+ assertEquals(expectedScoredSuggestion,
+ mTimeZoneDetectorStrategy.findBestSuggestionForTests());
+ }
+ }
+
+ @Test
+ public void testSuggestionsSinglePhone() {
+ Script script = new Script()
+ .initializeTimeZoneDetectionEnabled(true)
+ .initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID);
+
+ for (SuggestionTestCase testCase : TEST_CASES) {
+ makePhone1SuggestionAndCheckState(script, testCase);
+ }
+
+ /*
+ * This is the same test as above but the test cases are in
+ * reverse order of their expected score. New suggestions always replace previous ones:
+ * there's effectively no history and so ordering shouldn't make any difference.
+ */
+
+ // Each test case will have the same or lower score than the last.
+ ArrayList<SuggestionTestCase> descendingCasesByScore =
+ new ArrayList<>(Arrays.asList(TEST_CASES));
+ Collections.reverse(descendingCasesByScore);
+
+ for (SuggestionTestCase testCase : descendingCasesByScore) {
+ makePhone1SuggestionAndCheckState(script, testCase);
+ }
+ }
+
+ private void makePhone1SuggestionAndCheckState(Script script, SuggestionTestCase testCase) {
+ // Give the next suggestion a different zone from the currently set device time zone;
+ String currentZoneId = mFakeTimeZoneDetectorStrategyCallback.getDeviceTimeZone();
+ String suggestionZoneId =
+ "Europe/London".equals(currentZoneId) ? "Europe/Paris" : "Europe/London";
+ PhoneTimeZoneSuggestion zonePhone1Suggestion =
+ testCase.createSuggestion(PHONE1_ID, suggestionZoneId);
+ QualifiedPhoneTimeZoneSuggestion expectedZonePhone1ScoredSuggestion =
+ new QualifiedPhoneTimeZoneSuggestion(zonePhone1Suggestion, testCase.expectedScore);
+
+ script.suggestPhoneTimeZone(zonePhone1Suggestion);
+ if (testCase.expectedScore >= SCORE_USAGE_THRESHOLD) {
+ script.verifyTimeZoneSetAndReset(zonePhone1Suggestion);
+ } else {
+ script.verifyTimeZoneNotSet();
+ }
+
+ // Assert internal service state.
+ assertEquals(expectedZonePhone1ScoredSuggestion,
+ mTimeZoneDetectorStrategy.getLatestPhoneSuggestion(PHONE1_ID));
+ assertEquals(expectedZonePhone1ScoredSuggestion,
+ mTimeZoneDetectorStrategy.findBestSuggestionForTests());
+ }
+
+ /**
+ * Tries a set of test cases to see if the phone with the lowest ID is given preference. This
+ * test also confirms that the time zone setting would only be set if a suggestion is of
+ * sufficient quality.
+ */
+ @Test
+ public void testMultiplePhoneSuggestionScoringAndPhoneIdBias() {
+ String[] zoneIds = { "Europe/London", "Europe/Paris" };
+ PhoneTimeZoneSuggestion emptyPhone1Suggestion = createEmptyPhone1Suggestion();
+ PhoneTimeZoneSuggestion emptyPhone2Suggestion = createEmptyPhone2Suggestion();
+ QualifiedPhoneTimeZoneSuggestion expectedEmptyPhone1ScoredSuggestion =
+ new QualifiedPhoneTimeZoneSuggestion(emptyPhone1Suggestion, SCORE_NONE);
+ QualifiedPhoneTimeZoneSuggestion expectedEmptyPhone2ScoredSuggestion =
+ new QualifiedPhoneTimeZoneSuggestion(emptyPhone2Suggestion, SCORE_NONE);
+
+ Script script = new Script()
+ .initializeTimeZoneDetectionEnabled(true)
+ .initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID)
+ // Initialize the latest suggestions as empty so we don't need to worry about nulls
+ // below for the first loop.
+ .suggestPhoneTimeZone(emptyPhone1Suggestion)
+ .suggestPhoneTimeZone(emptyPhone2Suggestion)
+ .resetState();
+
+ for (SuggestionTestCase testCase : TEST_CASES) {
+ PhoneTimeZoneSuggestion zonePhone1Suggestion =
+ testCase.createSuggestion(PHONE1_ID, zoneIds[0]);
+ PhoneTimeZoneSuggestion zonePhone2Suggestion =
+ testCase.createSuggestion(PHONE2_ID, zoneIds[1]);
+ QualifiedPhoneTimeZoneSuggestion expectedZonePhone1ScoredSuggestion =
+ new QualifiedPhoneTimeZoneSuggestion(zonePhone1Suggestion,
+ testCase.expectedScore);
+ QualifiedPhoneTimeZoneSuggestion expectedZonePhone2ScoredSuggestion =
+ new QualifiedPhoneTimeZoneSuggestion(zonePhone2Suggestion,
+ testCase.expectedScore);
+
+ // Start the test by making a suggestion for phone 1.
+ script.suggestPhoneTimeZone(zonePhone1Suggestion);
+ if (testCase.expectedScore >= SCORE_USAGE_THRESHOLD) {
+ script.verifyTimeZoneSetAndReset(zonePhone1Suggestion);
+ } else {
+ script.verifyTimeZoneNotSet();
+ }
+
+ // Assert internal service state.
+ assertEquals(expectedZonePhone1ScoredSuggestion,
+ mTimeZoneDetectorStrategy.getLatestPhoneSuggestion(PHONE1_ID));
+ assertEquals(expectedEmptyPhone2ScoredSuggestion,
+ mTimeZoneDetectorStrategy.getLatestPhoneSuggestion(PHONE2_ID));
+ assertEquals(expectedZonePhone1ScoredSuggestion,
+ mTimeZoneDetectorStrategy.findBestSuggestionForTests());
+
+ // Phone 2 then makes an alternative suggestion with an identical score. Phone 1's
+ // suggestion should still "win" if it is above the required threshold.
+ script.suggestPhoneTimeZone(zonePhone2Suggestion);
+ script.verifyTimeZoneNotSet();
+
+ // Assert internal service state.
+ assertEquals(expectedZonePhone1ScoredSuggestion,
+ mTimeZoneDetectorStrategy.getLatestPhoneSuggestion(PHONE1_ID));
+ assertEquals(expectedZonePhone2ScoredSuggestion,
+ mTimeZoneDetectorStrategy.getLatestPhoneSuggestion(PHONE2_ID));
+ // Phone 1 should always beat phone 2, all other things being equal.
+ assertEquals(expectedZonePhone1ScoredSuggestion,
+ mTimeZoneDetectorStrategy.findBestSuggestionForTests());
+
+ // Withdrawing phone 1's suggestion should leave phone 2 as the new winner. Since the
+ // zoneId is different, the time zone setting should be updated if the score is high
+ // enough.
+ script.suggestPhoneTimeZone(emptyPhone1Suggestion);
+ if (testCase.expectedScore >= SCORE_USAGE_THRESHOLD) {
+ script.verifyTimeZoneSetAndReset(zonePhone2Suggestion);
+ } else {
+ script.verifyTimeZoneNotSet();
+ }
+
+ // Assert internal service state.
+ assertEquals(expectedEmptyPhone1ScoredSuggestion,
+ mTimeZoneDetectorStrategy.getLatestPhoneSuggestion(PHONE1_ID));
+ assertEquals(expectedZonePhone2ScoredSuggestion,
+ mTimeZoneDetectorStrategy.getLatestPhoneSuggestion(PHONE2_ID));
+ assertEquals(expectedZonePhone2ScoredSuggestion,
+ mTimeZoneDetectorStrategy.findBestSuggestionForTests());
+
+ // Reset the state for the next loop.
+ script.suggestPhoneTimeZone(emptyPhone2Suggestion)
+ .verifyTimeZoneNotSet();
+ assertEquals(expectedEmptyPhone1ScoredSuggestion,
+ mTimeZoneDetectorStrategy.getLatestPhoneSuggestion(PHONE1_ID));
+ assertEquals(expectedEmptyPhone2ScoredSuggestion,
+ mTimeZoneDetectorStrategy.getLatestPhoneSuggestion(PHONE2_ID));
+ }
+ }
+
+ /**
+ * The {@link TimeZoneDetectorStrategy.Callback} is left to detect whether changing the time
+ * zone is actually necessary. This test proves that the service doesn't assume it knows the
+ * current setting.
+ */
+ @Test
+ public void testTimeZoneDetectorStrategyDoesNotAssumeCurrentSetting() {
+ Script script = new Script()
+ .initializeTimeZoneDetectionEnabled(true);
+
+ SuggestionTestCase testCase =
+ newTestCase(MATCH_TYPE_NETWORK_COUNTRY_AND_OFFSET, QUALITY_SINGLE_ZONE, SCORE_HIGH);
+ PhoneTimeZoneSuggestion losAngelesSuggestion =
+ testCase.createSuggestion(PHONE1_ID, "America/Los_Angeles");
+ PhoneTimeZoneSuggestion newYorkSuggestion =
+ testCase.createSuggestion(PHONE1_ID, "America/New_York");
+
+ // Initialization.
+ script.suggestPhoneTimeZone(losAngelesSuggestion)
+ .verifyTimeZoneSetAndReset(losAngelesSuggestion);
+ // Suggest it again - it should not be set because it is already set.
+ script.suggestPhoneTimeZone(losAngelesSuggestion)
+ .verifyTimeZoneNotSet();
+
+ // Toggling time zone detection should set the device time zone only if the current setting
+ // value is different from the most recent phone suggestion.
+ script.timeZoneDetectionEnabled(false)
+ .verifyTimeZoneNotSet()
+ .timeZoneDetectionEnabled(true)
+ .verifyTimeZoneNotSet();
+
+ // Simulate a user turning auto detection off, a new suggestion being made while auto
+ // detection is off, and the user turning it on again.
+ script.timeZoneDetectionEnabled(false)
+ .suggestPhoneTimeZone(newYorkSuggestion)
+ .verifyTimeZoneNotSet();
+ // Latest suggestion should be used.
+ script.timeZoneDetectionEnabled(true)
+ .verifyTimeZoneSetAndReset(newYorkSuggestion);
+ }
+
+ private static PhoneTimeZoneSuggestion createEmptyPhone1Suggestion() {
+ return new PhoneTimeZoneSuggestion.Builder(PHONE1_ID).build();
+ }
+
+ private static PhoneTimeZoneSuggestion createEmptyPhone2Suggestion() {
+ return new PhoneTimeZoneSuggestion.Builder(PHONE2_ID).build();
+ }
+
+ class FakeTimeZoneDetectorStrategyCallback implements TimeZoneDetectorStrategy.Callback {
+
+ private boolean mTimeZoneDetectionEnabled;
+ private TestState<String> mTimeZoneId = new TestState<>();
+
+ @Override
+ public boolean isTimeZoneDetectionEnabled() {
+ return mTimeZoneDetectionEnabled;
+ }
+
+ @Override
+ public boolean isDeviceTimeZoneInitialized() {
+ return mTimeZoneId.getLatest() != null;
+ }
+
+ @Override
+ public String getDeviceTimeZone() {
+ return mTimeZoneId.getLatest();
+ }
+
+ @Override
+ public void setDeviceTimeZone(String zoneId) {
+ mTimeZoneId.set(zoneId);
+ }
+
+ void initializeTimeZoneDetectionEnabled(boolean enabled) {
+ mTimeZoneDetectionEnabled = enabled;
+ }
+
+ void initializeTimeZone(String zoneId) {
+ mTimeZoneId.init(zoneId);
+ }
+
+ void setTimeZoneDetectionEnabled(boolean enabled) {
+ mTimeZoneDetectionEnabled = enabled;
+ }
+
+ void assertTimeZoneNotSet() {
+ mTimeZoneId.assertHasNotBeenSet();
+ }
+
+ void assertTimeZoneSet(String timeZoneId) {
+ mTimeZoneId.assertHasBeenSet();
+ mTimeZoneId.assertChangeCount(1);
+ mTimeZoneId.assertLatestEquals(timeZoneId);
+ }
+
+ void commitAllChanges() {
+ mTimeZoneId.commitLatest();
+ }
+ }
+
+ /** Some piece of state that tests want to track. */
+ private static class TestState<T> {
+ private T mInitialValue;
+ private LinkedList<T> mValues = new LinkedList<>();
+
+ void init(T value) {
+ mValues.clear();
+ mInitialValue = value;
+ }
+
+ void set(T value) {
+ mValues.addFirst(value);
+ }
+
+ boolean hasBeenSet() {
+ return mValues.size() > 0;
+ }
+
+ void assertHasNotBeenSet() {
+ assertFalse(hasBeenSet());
+ }
+
+ void assertHasBeenSet() {
+ assertTrue(hasBeenSet());
+ }
+
+ void commitLatest() {
+ if (hasBeenSet()) {
+ mInitialValue = mValues.getLast();
+ mValues.clear();
+ }
+ }
+
+ void assertLatestEquals(T expected) {
+ assertEquals(expected, getLatest());
+ }
+
+ void assertChangeCount(int expectedCount) {
+ assertEquals(expectedCount, mValues.size());
+ }
+
+ public T getLatest() {
+ if (hasBeenSet()) {
+ return mValues.getFirst();
+ }
+ return mInitialValue;
+ }
+ }
+
+ /**
+ * A "fluent" class allows reuse of code in tests: initialization, simulation and verification
+ * logic.
+ */
+ private class Script {
+
+ Script initializeTimeZoneDetectionEnabled(boolean enabled) {
+ mFakeTimeZoneDetectorStrategyCallback.initializeTimeZoneDetectionEnabled(enabled);
+ return this;
+ }
+
+ Script initializeTimeZoneSetting(String zoneId) {
+ mFakeTimeZoneDetectorStrategyCallback.initializeTimeZone(zoneId);
+ return this;
+ }
+
+ Script timeZoneDetectionEnabled(boolean enabled) {
+ mFakeTimeZoneDetectorStrategyCallback.setTimeZoneDetectionEnabled(enabled);
+ mTimeZoneDetectorStrategy.handleTimeZoneDetectionChange();
+ return this;
+ }
+
+ /** Simulates the time zone detection service receiving a phone-originated suggestion. */
+ Script suggestPhoneTimeZone(PhoneTimeZoneSuggestion phoneTimeZoneSuggestion) {
+ mTimeZoneDetectorStrategy.suggestPhoneTimeZone(phoneTimeZoneSuggestion);
+ return this;
+ }
+
+ /** Simulates the user manually setting the time zone. */
+ Script manuallySetTimeZone(String timeZoneId) {
+ // Assert the test code is correct to call this method.
+ assertFalse(mFakeTimeZoneDetectorStrategyCallback.isTimeZoneDetectionEnabled());
+
+ mFakeTimeZoneDetectorStrategyCallback.initializeTimeZone(timeZoneId);
+ return this;
+ }
+
+ Script verifyTimeZoneNotSet() {
+ mFakeTimeZoneDetectorStrategyCallback.assertTimeZoneNotSet();
+ return this;
+ }
+
+ Script verifyTimeZoneSetAndReset(PhoneTimeZoneSuggestion timeZoneSuggestion) {
+ mFakeTimeZoneDetectorStrategyCallback.assertTimeZoneSet(timeZoneSuggestion.getZoneId());
+ mFakeTimeZoneDetectorStrategyCallback.commitAllChanges();
+ return this;
+ }
+
+ Script resetState() {
+ mFakeTimeZoneDetectorStrategyCallback.commitAllChanges();
+ return this;
+ }
+ }
+
+ private static class SuggestionTestCase {
+ public final int matchType;
+ public final int quality;
+ public final int expectedScore;
+
+ SuggestionTestCase(int matchType, int quality, int expectedScore) {
+ this.matchType = matchType;
+ this.quality = quality;
+ this.expectedScore = expectedScore;
+ }
+
+ private PhoneTimeZoneSuggestion createSuggestion(int phoneId, String zoneId) {
+ return new PhoneTimeZoneSuggestion.Builder(phoneId)
+ .setZoneId(zoneId)
+ .setMatchType(matchType)
+ .setQuality(quality)
+ .build();
+ }
+ }
+
+ private static SuggestionTestCase newTestCase(
+ @MatchType int matchType, @Quality int quality, int expectedScore) {
+ return new SuggestionTestCase(matchType, quality, expectedScore);
+ }
+}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryDatabaseTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryDatabaseTest.java
index a00afecda072..9ad6986f2f90 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryDatabaseTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryDatabaseTest.java
@@ -27,6 +27,7 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.AlarmManager;
+import android.app.NotificationHistory;
import android.app.NotificationHistory.HistoricalNotification;
import android.content.Context;
import android.graphics.drawable.Icon;
@@ -199,6 +200,16 @@ public class NotificationHistoryDatabaseTest extends UiServiceTestCase {
}
@Test
+ public void testReadNotificationHistory_readsBuffer() throws Exception {
+ HistoricalNotification hn = getHistoricalNotification(1);
+ mDataBase.addNotification(hn);
+
+ NotificationHistory nh = mDataBase.readNotificationHistory();
+
+ assertThat(nh.getNotificationsToWrite()).contains(hn);
+ }
+
+ @Test
public void testReadNotificationHistory_withNumFilterDoesNotReadExtraFiles() throws Exception {
AtomicFile af = mock(AtomicFile.class);
when(af.getBaseFile()).thenReturn(new File(mRootDir, "af"));
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryManagerTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryManagerTest.java
index aa3c4659c413..92c05466deb5 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryManagerTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryManagerTest.java
@@ -15,11 +15,12 @@
*/
package com.android.server.notification;
-import static android.os.UserHandle.USER_ALL;
+import static android.os.UserHandle.MIN_SECONDARY_USER_ID;
import static android.os.UserHandle.USER_SYSTEM;
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
@@ -28,9 +29,11 @@ import static org.mockito.Mockito.when;
import android.app.NotificationHistory;
import android.app.NotificationHistory.HistoricalNotification;
-import android.content.Context;
+import android.content.pm.UserInfo;
import android.graphics.drawable.Icon;
+import android.os.Handler;
import android.os.UserManager;
+import android.provider.Settings;
import androidx.test.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
@@ -44,23 +47,22 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import java.util.ArrayList;
+import java.util.List;
+
@RunWith(AndroidJUnit4.class)
public class NotificationHistoryManagerTest extends UiServiceTestCase {
@Mock
- Context mContext;
- @Mock
UserManager mUserManager;
@Mock
NotificationHistoryDatabase mDb;
+ @Mock
+ Handler mHandler;
+ List<UserInfo> mUsers;
NotificationHistoryManager mHistoryManager;
- private HistoricalNotification getHistoricalNotification(int index) {
- return getHistoricalNotification("package" + index, index);
- }
-
private HistoricalNotification getHistoricalNotification(String packageName, int index) {
String expectedChannelName = "channelName" + index;
String expectedChannelId = "channelId" + index;
@@ -88,13 +90,28 @@ public class NotificationHistoryManagerTest extends UiServiceTestCase {
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
- when(mContext.getSystemService(UserManager.class)).thenReturn(mUserManager);
- when(mContext.getUser()).thenReturn(getContext().getUser());
- when(mContext.getPackageName()).thenReturn(getContext().getPackageName());
+
+ getContext().addMockSystemService(UserManager.class, mUserManager);
+
+ mUsers = new ArrayList<>();
+ UserInfo userSystem = new UserInfo();
+ userSystem.id = USER_SYSTEM;
+ mUsers.add(userSystem);
+ UserInfo userAll = new UserInfo();
+ userAll.id = MIN_SECONDARY_USER_ID;
+ mUsers.add(userAll);
+ mUsers.add(userAll);
+ when(mUserManager.getUsers()).thenReturn(mUsers);
+
+ for (UserInfo info : mUsers) {
+ Settings.Secure.putIntForUser(getContext().getContentResolver(),
+ Settings.Secure.NOTIFICATION_HISTORY_ENABLED, 1, info.id);
+ }
NotificationHistoryDatabaseFactory.setTestingNotificationHistoryDatabase(mDb);
- mHistoryManager = new NotificationHistoryManager(mContext);
+ mHistoryManager = new NotificationHistoryManager(getContext(), mHandler);
+ mHistoryManager.onBootPhaseAppsCanStart();
}
@Test
@@ -107,6 +124,20 @@ public class NotificationHistoryManagerTest extends UiServiceTestCase {
verify(mDb, times(1)).init();
}
+ public void testOnUserUnlocked_historyDisabled() {
+ Settings.Secure.putIntForUser(getContext().getContentResolver(),
+ Settings.Secure.NOTIFICATION_HISTORY_ENABLED, 0, USER_SYSTEM);
+ mHistoryManager.mSettingsObserver.update(null, USER_SYSTEM);
+ assertThat(mHistoryManager.doesHistoryExistForUser(USER_SYSTEM)).isFalse();
+ assertThat(mHistoryManager.isUserUnlocked(USER_SYSTEM)).isFalse();
+
+ mHistoryManager.onUserUnlocked(USER_SYSTEM);
+
+ assertThat(mHistoryManager.doesHistoryExistForUser(USER_SYSTEM)).isFalse();
+ assertThat(mHistoryManager.isUserUnlocked(USER_SYSTEM)).isFalse();
+ verify(mDb, times(1)).disableHistory();
+ }
+
@Test
public void testOnUserUnlocked_cleansUpRemovedPackages() {
String pkg = "pkg";
@@ -144,6 +175,7 @@ public class NotificationHistoryManagerTest extends UiServiceTestCase {
assertThat(mHistoryManager.doesHistoryExistForUser(USER_SYSTEM)).isFalse();
assertThat(mHistoryManager.isUserUnlocked(USER_SYSTEM)).isFalse();
+ assertThat(mHistoryManager.isHistoryEnabled(USER_SYSTEM)).isFalse();
}
@Test
@@ -187,6 +219,18 @@ public class NotificationHistoryManagerTest extends UiServiceTestCase {
}
@Test
+ public void testOnPackageRemoved_historyDisabled() {
+ Settings.Secure.putIntForUser(getContext().getContentResolver(),
+ Settings.Secure.NOTIFICATION_HISTORY_ENABLED, 0, USER_SYSTEM);
+ mHistoryManager.mSettingsObserver.update(null, USER_SYSTEM);
+ String pkg = "pkg";
+ mHistoryManager.onPackageRemoved(USER_SYSTEM, pkg);
+
+ assertThat(mHistoryManager.getPendingPackageRemovalsForUser(USER_SYSTEM))
+ .isNull();
+ }
+
+ @Test
public void testOnPackageRemoved_multiUser() {
String pkg = "pkg";
NotificationHistoryDatabase userHistorySystem = mock(NotificationHistoryDatabase.class);
@@ -195,8 +239,8 @@ public class NotificationHistoryManagerTest extends UiServiceTestCase {
mHistoryManager.onUserUnlocked(USER_SYSTEM);
mHistoryManager.replaceNotificationHistoryDatabase(USER_SYSTEM, userHistorySystem);
- mHistoryManager.onUserUnlocked(USER_ALL);
- mHistoryManager.replaceNotificationHistoryDatabase(USER_ALL, userHistoryAll);
+ mHistoryManager.onUserUnlocked(MIN_SECONDARY_USER_ID);
+ mHistoryManager.replaceNotificationHistoryDatabase(MIN_SECONDARY_USER_ID, userHistoryAll);
mHistoryManager.onPackageRemoved(USER_SYSTEM, pkg);
@@ -212,8 +256,8 @@ public class NotificationHistoryManagerTest extends UiServiceTestCase {
mHistoryManager.onUserUnlocked(USER_SYSTEM);
mHistoryManager.replaceNotificationHistoryDatabase(USER_SYSTEM, userHistorySystem);
- mHistoryManager.onUserUnlocked(USER_ALL);
- mHistoryManager.replaceNotificationHistoryDatabase(USER_ALL, userHistoryAll);
+ mHistoryManager.onUserUnlocked(MIN_SECONDARY_USER_ID);
+ mHistoryManager.replaceNotificationHistoryDatabase(MIN_SECONDARY_USER_ID, userHistoryAll);
mHistoryManager.triggerWriteToDisk();
@@ -229,9 +273,9 @@ public class NotificationHistoryManagerTest extends UiServiceTestCase {
mHistoryManager.onUserUnlocked(USER_SYSTEM);
mHistoryManager.replaceNotificationHistoryDatabase(USER_SYSTEM, userHistorySystem);
- mHistoryManager.onUserUnlocked(USER_ALL);
- mHistoryManager.replaceNotificationHistoryDatabase(USER_ALL, userHistoryAll);
- mHistoryManager.onUserStopped(USER_ALL);
+ mHistoryManager.onUserUnlocked(MIN_SECONDARY_USER_ID);
+ mHistoryManager.replaceNotificationHistoryDatabase(MIN_SECONDARY_USER_ID, userHistoryAll);
+ mHistoryManager.onUserStopped(MIN_SECONDARY_USER_ID);
mHistoryManager.triggerWriteToDisk();
@@ -240,6 +284,21 @@ public class NotificationHistoryManagerTest extends UiServiceTestCase {
}
@Test
+ public void testTriggerWriteToDisk_historyDisabled() {
+ Settings.Secure.putIntForUser(getContext().getContentResolver(),
+ Settings.Secure.NOTIFICATION_HISTORY_ENABLED, 0, USER_SYSTEM);
+ mHistoryManager.mSettingsObserver.update(null, USER_SYSTEM);
+ NotificationHistoryDatabase userHistorySystem = mock(NotificationHistoryDatabase.class);
+
+ mHistoryManager.onUserUnlocked(USER_SYSTEM);
+ mHistoryManager.replaceNotificationHistoryDatabase(USER_SYSTEM, userHistorySystem);
+
+ mHistoryManager.triggerWriteToDisk();
+
+ verify(userHistorySystem, never()).forceWriteToDisk();
+ }
+
+ @Test
public void testAddNotification_userLocked_noCrash() {
HistoricalNotification hn = getHistoricalNotification("pkg", 1);
@@ -247,9 +306,23 @@ public class NotificationHistoryManagerTest extends UiServiceTestCase {
}
@Test
+ public void testAddNotification_historyDisabled() {
+ HistoricalNotification hn = getHistoricalNotification("pkg", 1);
+
+ Settings.Secure.putIntForUser(getContext().getContentResolver(),
+ Settings.Secure.NOTIFICATION_HISTORY_ENABLED, 0, hn.getUserId());
+ mHistoryManager.mSettingsObserver.update(null, USER_SYSTEM);
+
+ mHistoryManager.onUserUnlocked(hn.getUserId());
+ mHistoryManager.addNotification(hn);
+
+ verify(mDb, never()).addNotification(any());
+ }
+
+ @Test
public void testAddNotification() {
HistoricalNotification hnSystem = getHistoricalNotification("pkg", USER_SYSTEM);
- HistoricalNotification hnAll = getHistoricalNotification("pkg", USER_ALL);
+ HistoricalNotification hnAll = getHistoricalNotification("pkg", MIN_SECONDARY_USER_ID);
NotificationHistoryDatabase userHistorySystem = mock(NotificationHistoryDatabase.class);
NotificationHistoryDatabase userHistoryAll = mock(NotificationHistoryDatabase.class);
@@ -257,8 +330,8 @@ public class NotificationHistoryManagerTest extends UiServiceTestCase {
mHistoryManager.onUserUnlocked(USER_SYSTEM);
mHistoryManager.replaceNotificationHistoryDatabase(USER_SYSTEM, userHistorySystem);
- mHistoryManager.onUserUnlocked(USER_ALL);
- mHistoryManager.replaceNotificationHistoryDatabase(USER_ALL, userHistoryAll);
+ mHistoryManager.onUserUnlocked(MIN_SECONDARY_USER_ID);
+ mHistoryManager.replaceNotificationHistoryDatabase(MIN_SECONDARY_USER_ID, userHistoryAll);
mHistoryManager.addNotification(hnSystem);
mHistoryManager.addNotification(hnAll);
@@ -270,7 +343,7 @@ public class NotificationHistoryManagerTest extends UiServiceTestCase {
@Test
public void testReadNotificationHistory() {
HistoricalNotification hnSystem = getHistoricalNotification("pkg", USER_SYSTEM);
- HistoricalNotification hnAll = getHistoricalNotification("pkg", USER_ALL);
+ HistoricalNotification hnAll = getHistoricalNotification("pkg", MIN_SECONDARY_USER_ID);
NotificationHistoryDatabase userHistorySystem = mock(NotificationHistoryDatabase.class);
NotificationHistoryDatabase userHistoryAll = mock(NotificationHistoryDatabase.class);
@@ -283,8 +356,8 @@ public class NotificationHistoryManagerTest extends UiServiceTestCase {
when(nhSystem.getNotificationsToWrite()).thenReturn(nhSystemList);
when(userHistorySystem.readNotificationHistory()).thenReturn(nhSystem);
- mHistoryManager.onUserUnlocked(USER_ALL);
- mHistoryManager.replaceNotificationHistoryDatabase(USER_ALL, userHistoryAll);
+ mHistoryManager.onUserUnlocked(MIN_SECONDARY_USER_ID);
+ mHistoryManager.replaceNotificationHistoryDatabase(MIN_SECONDARY_USER_ID, userHistoryAll);
NotificationHistory nhAll = mock(NotificationHistory.class);
ArrayList<HistoricalNotification> nhAllList = new ArrayList<>();
nhAllList.add(hnAll);
@@ -293,13 +366,47 @@ public class NotificationHistoryManagerTest extends UiServiceTestCase {
// ensure read history returns both historical notifs
NotificationHistory nh = mHistoryManager.readNotificationHistory(
- new int[] {USER_SYSTEM, USER_ALL});
+ new int[] {USER_SYSTEM, MIN_SECONDARY_USER_ID});
assertThat(nh.getNotificationsToWrite()).contains(hnSystem);
assertThat(nh.getNotificationsToWrite()).contains(hnAll);
}
@Test
- public void readFilteredNotificationHistory_userUnlocked() {
+ public void testReadNotificationHistory_historyDisabled() {
+ HistoricalNotification hnSystem = getHistoricalNotification("pkg", USER_SYSTEM);
+
+ mHistoryManager.onUserUnlocked(USER_SYSTEM);
+ NotificationHistory nhSystem = mock(NotificationHistory.class);
+ ArrayList<HistoricalNotification> nhSystemList = new ArrayList<>();
+ nhSystemList.add(hnSystem);
+ when(nhSystem.getNotificationsToWrite()).thenReturn(nhSystemList);
+ when(mDb.readNotificationHistory()).thenReturn(nhSystem);
+
+ mHistoryManager.onUserUnlocked(USER_SYSTEM);
+
+ Settings.Secure.putIntForUser(getContext().getContentResolver(),
+ Settings.Secure.NOTIFICATION_HISTORY_ENABLED, 0, USER_SYSTEM);
+ mHistoryManager.mSettingsObserver.update(null, USER_SYSTEM);
+
+ NotificationHistory nh =
+ mHistoryManager.readNotificationHistory(new int[] {USER_SYSTEM,});
+ assertThat(nh.getNotificationsToWrite()).isEmpty();
+ }
+
+ @Test
+ public void testReadFilteredNotificationHistory_userLocked() {
+ NotificationHistory nh =
+ mHistoryManager.readFilteredNotificationHistory(USER_SYSTEM, "", "", 1000);
+ assertThat(nh.getNotificationsToWrite()).isEmpty();
+ }
+
+ @Test
+ public void testReadFilteredNotificationHistory_historyDisabled() {
+ Settings.Secure.putIntForUser(getContext().getContentResolver(),
+ Settings.Secure.NOTIFICATION_HISTORY_ENABLED, 0, USER_SYSTEM);
+ mHistoryManager.mSettingsObserver.update(null, USER_SYSTEM);
+
+ mHistoryManager.onUserUnlocked(USER_SYSTEM);
NotificationHistory nh =
mHistoryManager.readFilteredNotificationHistory(USER_SYSTEM, "", "", 1000);
assertThat(nh.getNotificationsToWrite()).isEmpty();
@@ -312,4 +419,15 @@ public class NotificationHistoryManagerTest extends UiServiceTestCase {
mHistoryManager.readFilteredNotificationHistory(USER_SYSTEM, "pkg", "chn", 1000);
verify(mDb, times(1)).readNotificationHistory("pkg", "chn", 1000);
}
+
+ @Test
+ public void testIsHistoryEnabled() {
+ assertThat(mHistoryManager.isHistoryEnabled(USER_SYSTEM)).isTrue();
+
+ Settings.Secure.putIntForUser(getContext().getContentResolver(),
+ Settings.Secure.NOTIFICATION_HISTORY_ENABLED, 0, USER_SYSTEM);
+ mHistoryManager.mSettingsObserver.update(null, USER_SYSTEM);
+
+ assertThat(mHistoryManager.isHistoryEnabled(USER_SYSTEM)).isFalse();
+ }
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index 21de668e10c3..876e77acde86 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -218,6 +218,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
@Mock
RankingHandler mRankingHandler;
+ private static final int MAX_POST_DELAY = 1000;
+
private NotificationChannel mTestNotificationChannel = new NotificationChannel(
TEST_CHANNEL_ID, TEST_CHANNEL_ID, IMPORTANCE_DEFAULT);
@@ -246,6 +248,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
mNotificationAssistantAccessGrantedCallback;
@Mock
UserManager mUm;
+ @Mock
+ NotificationHistoryManager mHistoryManager;
// Use a Testable subclass so we can simulate calls from the system without failing.
private static class TestableNotificationManagerService extends NotificationManagerService {
@@ -404,13 +408,13 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
when(mAssistants.isAdjustmentAllowed(anyString())).thenReturn(true);
- mService.init(mTestableLooper.getLooper(), mRankingHandler,
- mPackageManager, mPackageManagerClient, mockLightsManager,
+ mService.init(mService.new WorkerHandler(mTestableLooper.getLooper()),
+ mRankingHandler, mPackageManager, mPackageManagerClient, mockLightsManager,
mListeners, mAssistants, mConditionProviders,
mCompanionMgr, mSnoozeHelper, mUsageStats, mPolicyFile, mActivityManager,
mGroupHelper, mAm, mAppUsageStats,
mock(DevicePolicyManagerInternal.class), mUgm, mUgmInternal,
- mAppOpsManager, mUm);
+ mAppOpsManager, mUm, mHistoryManager);
mService.onBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY);
mService.setAudioManager(mAudioManager);
@@ -430,6 +434,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
public void tearDown() throws Exception {
if (mFile != null) mFile.delete();
clearDeviceConfig();
+ mService.unregisterDeviceConfigChange();
InstrumentationRegistry.getInstrumentation()
.getUiAutomation().dropShellPermissionIdentity();
}
@@ -5947,4 +5952,61 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
}
// TODO: add tests for the rest of the non-empty cases
+
+ @Test
+ public void testOnUnlockUser() {
+ UserInfo ui = new UserInfo();
+ ui.id = 10;
+ mService.onUnlockUser(ui);
+ waitForIdle();
+
+ verify(mHistoryManager, timeout(MAX_POST_DELAY).times(1)).onUserUnlocked(ui.id);
+ }
+
+ @Test
+ public void testOnStopUser() {
+ UserInfo ui = new UserInfo();
+ ui.id = 10;
+ mService.onStopUser(ui);
+ waitForIdle();
+
+ verify(mHistoryManager, timeout(MAX_POST_DELAY).times(1)).onUserStopped(ui.id);
+ }
+
+ @Test
+ public void testOnBootPhase() {
+ mService.onBootPhase(SystemService.PHASE_ACTIVITY_MANAGER_READY);
+
+ verify(mHistoryManager, never()).onBootPhaseAppsCanStart();
+
+ mService.onBootPhase(SystemService.PHASE_THIRD_PARTY_APPS_CAN_START);
+
+ verify(mHistoryManager, times(1)).onBootPhaseAppsCanStart();
+ }
+
+ @Test
+ public void testHandleOnPackageChanged() {
+ String[] pkgs = new String[] {PKG, PKG_N_MR1};
+ int[] uids = new int[] {mUid, UserHandle.PER_USER_RANGE + 1};
+
+ mService.handleOnPackageChanged(false, USER_SYSTEM, pkgs, uids);
+
+ verify(mHistoryManager, never()).onPackageRemoved(anyInt(), anyString());
+
+ mService.handleOnPackageChanged(true, USER_SYSTEM, pkgs, uids);
+
+ verify(mHistoryManager, times(1)).onPackageRemoved(UserHandle.getUserId(uids[0]), pkgs[0]);
+ verify(mHistoryManager, times(1)).onPackageRemoved(UserHandle.getUserId(uids[1]), pkgs[1]);
+ }
+
+ @Test
+ public void testNotificationHistory_addNoisyNotification() throws Exception {
+ NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel,
+ null /* tvExtender */, false);
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, nr.sbn.getTag(),
+ nr.sbn.getId(), nr.sbn.getNotification(), nr.sbn.getUserId());
+ waitForIdle();
+
+ verify(mHistoryManager, times(1)).addNotification(any());
+ }
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java b/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java
index 7f9f489c509a..c828f02901b3 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java
@@ -129,7 +129,8 @@ public class RoleObserverTest extends UiServiceTestCase {
mRoleObserver = mService.new RoleObserver(mRoleManager, mPm, mExecutor);
try {
- mService.init(mock(Looper.class), mock(RankingHandler.class),
+ mService.init(mService.new WorkerHandler(mock(Looper.class)),
+ mock(RankingHandler.class),
mock(IPackageManager.class), mock(PackageManager.class),
mock(LightsManager.class),
mock(NotificationListeners.class), mock(NotificationAssistants.class),
@@ -140,7 +141,7 @@ public class RoleObserverTest extends UiServiceTestCase {
mock(UsageStatsManagerInternal.class),
mock(DevicePolicyManagerInternal.class), mock(IUriGrantsManager.class),
mock(UriGrantsManagerInternal.class),
- mock(AppOpsManager.class), mUm);
+ mock(AppOpsManager.class), mUm, mock(NotificationHistoryManager.class));
} catch (SecurityException e) {
if (!e.getMessage().contains("Permission Denial: not allowed to send broadcast")) {
throw e;
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java
index 36175a93f667..5841e59ab3a0 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java
@@ -350,6 +350,26 @@ public class SnoozeHelperTest extends UiServiceTestCase {
}
@Test
+ public void testUpdateAfterCancel() throws Exception {
+ // snooze a notification
+ NotificationRecord r = getNotificationRecord("pkg", 1, "one", UserHandle.SYSTEM);
+ mSnoozeHelper.snooze(r , 1000);
+
+ // cancel the notification
+ mSnoozeHelper.cancel(UserHandle.USER_SYSTEM, false);
+
+ // update the notification
+ r = getNotificationRecord("pkg", 1, "one", UserHandle.SYSTEM);
+ mSnoozeHelper.update(UserHandle.USER_SYSTEM, r);
+
+ // verify callback is called when repost (snooze is expired)
+ verify(mCallback, never()).repost(anyInt(), any(NotificationRecord.class));
+ mSnoozeHelper.repost(r.getKey(), UserHandle.USER_SYSTEM);
+ verify(mCallback, times(1)).repost(UserHandle.USER_SYSTEM, r);
+ assertFalse(r.isCanceled);
+ }
+
+ @Test
public void testGetSnoozedByUser() throws Exception {
NotificationRecord r = getNotificationRecord("pkg", 1, "one", UserHandle.SYSTEM);
NotificationRecord r2 = getNotificationRecord("pkg", 2, "two", UserHandle.SYSTEM);
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
index ae1bb8e57e56..c712d6dedb27 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -962,4 +962,19 @@ public class ActivityStarterTests extends ActivityTestsBase {
}
assertThat(exceptionCaught).isTrue();
}
+
+ @Test
+ public void testRecycleTaskFromAnotherUser() {
+ final ActivityStarter starter = prepareStarter(0 /* flags */);
+ starter.mStartActivity = new ActivityBuilder(mService).build();
+ final Task task = new TaskBuilder(mService.mStackSupervisor)
+ .setStack(mService.mRootActivityContainer.getDefaultDisplay().createStack(
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */))
+ .setUserId(10)
+ .build();
+
+ final int result = starter.recycleTask(task, null, null);
+ assertThat(result == START_SUCCESS).isTrue();
+ assertThat(starter.mAddingToTask).isTrue();
+ }
}
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index 63b062e91c98..ba4a4484f09b 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -62,12 +62,10 @@ import android.os.Environment;
import android.os.FileUtils;
import android.os.Handler;
import android.os.IBinder;
-import android.os.IDeviceIdleController;
import android.os.Looper;
import android.os.Message;
import android.os.Process;
import android.os.RemoteException;
-import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.UserHandle;
@@ -150,7 +148,6 @@ public class UsageStatsService extends SystemService implements
UserManager mUserManager;
PackageManager mPackageManager;
PackageManagerInternal mPackageManagerInternal;
- IDeviceIdleController mDeviceIdleController;
// Do not use directly. Call getDpmInternal() instead
DevicePolicyManagerInternal mDpmInternal;
@@ -265,9 +262,6 @@ public class UsageStatsService extends SystemService implements
// initialize mDpmInternal
getDpmInternal();
- mDeviceIdleController = IDeviceIdleController.Stub.asInterface(
- ServiceManager.getService(Context.DEVICE_IDLE_CONTROLLER));
-
if (ENABLE_KERNEL_UPDATES && KERNEL_COUNTER_FILE.exists()) {
try {
ActivityManager.getService().registerUidObserver(mUidObserver,
@@ -1626,16 +1620,6 @@ public class UsageStatsService extends SystemService implements
}
@Override
- public void whitelistAppTemporarily(String packageName, long duration, int userId)
- throws RemoteException {
- StringBuilder reason = new StringBuilder(32);
- reason.append("from:");
- UserHandle.formatUid(reason, Binder.getCallingUid());
- mDeviceIdleController.addPowerSaveTempWhitelistApp(packageName, duration, userId,
- reason.toString());
- }
-
- @Override
public void onCarrierPrivilegedAppsChanged() {
if (DEBUG) {
Slog.i(TAG, "Carrier privileged apps changed");
diff --git a/services/wifi/Android.bp b/services/wifi/Android.bp
deleted file mode 100644
index 8a7f73fcf501..000000000000
--- a/services/wifi/Android.bp
+++ /dev/null
@@ -1,16 +0,0 @@
-filegroup {
- name: "services.wifi-sources",
- srcs: [
- "java/**/*.java",
- "java/**/*.aidl",
- ],
- path: "java",
- visibility: ["//frameworks/base/services"],
-}
-
-// Interfaces between the core system and the wifi mainline module.
-java_library_static {
- name: "services.wifi",
- srcs: [":services.wifi-sources"],
- libs: ["services.net"],
-}
diff --git a/services/wifi/java/android/net/wifi/WifiStackClient.java b/services/wifi/java/android/net/wifi/WifiStackClient.java
deleted file mode 100644
index dcdfbc54687c..000000000000
--- a/services/wifi/java/android/net/wifi/WifiStackClient.java
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES 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.net.wifi;
-
-import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_HIGH;
-import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_NORMAL;
-
-import android.annotation.NonNull;
-import android.content.Context;
-import android.net.ConnectivityModuleConnector;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.util.Log;
-
-import java.util.List;
-
-/**
- * Service used to communicate with the wifi stack, which could be running in a separate
- * module.
- * @hide
- */
-public class WifiStackClient {
- public static final String PERMISSION_MAINLINE_WIFI_STACK =
- "android.permission.MAINLINE_WIFI_STACK";
-
- private static final String TAG = WifiStackClient.class.getSimpleName();
- private static WifiStackClient sInstance;
-
- private WifiStackClient() { }
-
- /**
- * Get the WifiStackClient singleton instance.
- */
- public static synchronized WifiStackClient getInstance() {
- if (sInstance == null) {
- sInstance = new WifiStackClient();
- }
- return sInstance;
- }
-
- private class WifiStackConnection implements
- ConnectivityModuleConnector.ModuleServiceCallback {
- @Override
- public void onModuleServiceConnected(IBinder service) {
- Log.i(TAG, "Wifi stack connected");
- registerWifiStackService(service);
-
- IWifiStackConnector connector = IWifiStackConnector.Stub.asInterface(service);
-
- List<WifiApiServiceInfo> wifiApiServiceInfos;
- try {
- wifiApiServiceInfos = connector.getWifiApiServiceInfos();
- } catch (RemoteException e) {
- throw new RuntimeException("Failed to getWifiApiServiceInfos()", e);
- }
-
- for (WifiApiServiceInfo wifiApiServiceInfo : wifiApiServiceInfos) {
- String serviceName = wifiApiServiceInfo.name;
- IBinder binder = wifiApiServiceInfo.binder;
- Log.i(TAG, "Registering " + serviceName);
- ServiceManager.addService(serviceName, binder);
- }
- }
- }
-
- private void registerWifiStackService(@NonNull IBinder service) {
- ServiceManager.addService(Context.WIFI_STACK_SERVICE, service,
- false /* allowIsolated */,
- DUMP_FLAG_PRIORITY_HIGH | DUMP_FLAG_PRIORITY_NORMAL);
- Log.i(TAG, "Wifi stack service registered");
- }
-
- /**
- * Start the wifi stack. Should be called only once on device startup.
- *
- * <p>This method will start the wifi stack either in the wifi stack
- * process, or inside the system server on devices that do not support the wifi stack
- * module.
- */
- public void start() {
- Log.i(TAG, "Starting wifi stack");
- ConnectivityModuleConnector.getInstance().startModuleService(
- IWifiStackConnector.class.getName(), PERMISSION_MAINLINE_WIFI_STACK,
- new WifiStackConnection());
- }
-}
diff --git a/telecomm/java/android/telecom/ConnectionRequest.java b/telecomm/java/android/telecom/ConnectionRequest.java
index b42853046031..221f8f129744 100644
--- a/telecomm/java/android/telecom/ConnectionRequest.java
+++ b/telecomm/java/android/telecom/ConnectionRequest.java
@@ -16,6 +16,10 @@
package android.telecom;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.annotation.TestApi;
import android.net.Uri;
import android.os.Bundle;
import android.os.Parcel;
@@ -32,6 +36,7 @@ public final class ConnectionRequest implements Parcelable {
* Builder class for {@link ConnectionRequest}
* @hide
*/
+ @TestApi // For convenience in CTS tests
public static final class Builder {
private PhoneAccountHandle mAccountHandle;
private Uri mAddress;
@@ -48,7 +53,7 @@ public final class ConnectionRequest implements Parcelable {
* Sets the phone account handle for the resulting {@link ConnectionRequest}
* @param accountHandle The accountHandle which should be used to place the call.
*/
- public Builder setAccountHandle(PhoneAccountHandle accountHandle) {
+ public @NonNull Builder setAccountHandle(@NonNull PhoneAccountHandle accountHandle) {
this.mAccountHandle = accountHandle;
return this;
}
@@ -58,7 +63,7 @@ public final class ConnectionRequest implements Parcelable {
* @param address The address(e.g., phone number) to which the {@link Connection} is to
* connect.
*/
- public Builder setAddress(Uri address) {
+ public @NonNull Builder setAddress(@NonNull Uri address) {
this.mAddress = address;
return this;
}
@@ -67,7 +72,7 @@ public final class ConnectionRequest implements Parcelable {
* Sets the extras bundle for the resulting {@link ConnectionRequest}
* @param extras Application-specific extra data.
*/
- public Builder setExtras(Bundle extras) {
+ public @NonNull Builder setExtras(@NonNull Bundle extras) {
this.mExtras = extras;
return this;
}
@@ -76,7 +81,7 @@ public final class ConnectionRequest implements Parcelable {
* Sets the video state for the resulting {@link ConnectionRequest}
* @param videoState Determines the video state for the connection.
*/
- public Builder setVideoState(int videoState) {
+ public @NonNull Builder setVideoState(int videoState) {
this.mVideoState = videoState;
return this;
}
@@ -85,7 +90,7 @@ public final class ConnectionRequest implements Parcelable {
* Sets the Telecom call ID for the resulting {@link ConnectionRequest}
* @param telecomCallId The telecom call ID.
*/
- public Builder setTelecomCallId(String telecomCallId) {
+ public @NonNull Builder setTelecomCallId(@NonNull String telecomCallId) {
this.mTelecomCallId = telecomCallId;
return this;
}
@@ -97,7 +102,7 @@ public final class ConnectionRequest implements Parcelable {
* its own incoming call UI for an incoming call. When
* {@code false}, Telecom shows the incoming call UI.
*/
- public Builder setShouldShowIncomingCallUi(boolean shouldShowIncomingCallUi) {
+ public @NonNull Builder setShouldShowIncomingCallUi(boolean shouldShowIncomingCallUi) {
this.mShouldShowIncomingCallUi = shouldShowIncomingCallUi;
return this;
}
@@ -107,7 +112,8 @@ public final class ConnectionRequest implements Parcelable {
* resulting {@link ConnectionRequest}
* @param rttPipeFromInCall The data pipe to read from.
*/
- public Builder setRttPipeFromInCall(ParcelFileDescriptor rttPipeFromInCall) {
+ public @NonNull Builder setRttPipeFromInCall(
+ @NonNull ParcelFileDescriptor rttPipeFromInCall) {
this.mRttPipeFromInCall = rttPipeFromInCall;
return this;
}
@@ -117,12 +123,16 @@ public final class ConnectionRequest implements Parcelable {
* resulting {@link ConnectionRequest}
* @param rttPipeToInCall The data pipe to write to.
*/
- public Builder setRttPipeToInCall(ParcelFileDescriptor rttPipeToInCall) {
+ public @NonNull Builder setRttPipeToInCall(@NonNull ParcelFileDescriptor rttPipeToInCall) {
this.mRttPipeToInCall = rttPipeToInCall;
return this;
}
- public ConnectionRequest build() {
+ /**
+ * Build the {@link ConnectionRequest}
+ * @return Result of the builder
+ */
+ public @NonNull ConnectionRequest build() {
return new ConnectionRequest(
mAccountHandle,
mAddress,
@@ -261,7 +271,9 @@ public final class ConnectionRequest implements Parcelable {
* @return The Telecom ID.
* @hide
*/
- public String getTelecomCallId() {
+ @SystemApi
+ @TestApi
+ public @Nullable String getTelecomCallId() {
return mTelecomCallId;
}
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index 4016943d9c2c..39d741c3d3bf 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -1029,12 +1029,16 @@ public class TelecomManager {
* by the user.
*
* @param includeDisabledAccounts When {@code true}, disabled phone accounts will be included,
- * when {@code false}, only
+ * when {@code false}, only enabled phone accounts will be
+ * included.
* @return A list of {@code PhoneAccountHandle} objects.
* @hide
*/
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 119305590)
- public List<PhoneAccountHandle> getCallCapablePhoneAccounts(boolean includeDisabledAccounts) {
+ @SystemApi
+ @TestApi
+ @RequiresPermission(READ_PRIVILEGED_PHONE_STATE)
+ public @NonNull List<PhoneAccountHandle> getCallCapablePhoneAccounts(
+ boolean includeDisabledAccounts) {
try {
if (isServiceConnected()) {
return getTelecomService().getCallCapablePhoneAccounts(
diff --git a/telephony/java/com/android/internal/telephony/EncodeException.java b/telephony/common/com/android/internal/telephony/EncodeException.java
index cdc853e09895..cdc853e09895 100644
--- a/telephony/java/com/android/internal/telephony/EncodeException.java
+++ b/telephony/common/com/android/internal/telephony/EncodeException.java
diff --git a/core/java/android/service/carrier/CarrierIdentifier.aidl b/telephony/java/android/service/carrier/CarrierIdentifier.aidl
index 48b13983050d..48b13983050d 100644
--- a/core/java/android/service/carrier/CarrierIdentifier.aidl
+++ b/telephony/java/android/service/carrier/CarrierIdentifier.aidl
diff --git a/core/java/android/service/carrier/CarrierIdentifier.java b/telephony/java/android/service/carrier/CarrierIdentifier.java
index af5bf7475f95..af5bf7475f95 100644
--- a/core/java/android/service/carrier/CarrierIdentifier.java
+++ b/telephony/java/android/service/carrier/CarrierIdentifier.java
diff --git a/core/java/android/service/carrier/CarrierService.java b/telephony/java/android/service/carrier/CarrierService.java
index eefc1b70bac9..eefc1b70bac9 100644
--- a/core/java/android/service/carrier/CarrierService.java
+++ b/telephony/java/android/service/carrier/CarrierService.java
diff --git a/core/java/android/service/carrier/ICarrierService.aidl b/telephony/java/android/service/carrier/ICarrierService.aidl
index ac6f9614d8f5..ac6f9614d8f5 100644
--- a/core/java/android/service/carrier/ICarrierService.aidl
+++ b/telephony/java/android/service/carrier/ICarrierService.aidl
diff --git a/core/java/android/service/euicc/DownloadSubscriptionResult.aidl b/telephony/java/android/service/euicc/DownloadSubscriptionResult.aidl
index b625fd6d3cb4..b625fd6d3cb4 100644
--- a/core/java/android/service/euicc/DownloadSubscriptionResult.aidl
+++ b/telephony/java/android/service/euicc/DownloadSubscriptionResult.aidl
diff --git a/core/java/android/service/euicc/DownloadSubscriptionResult.java b/telephony/java/android/service/euicc/DownloadSubscriptionResult.java
index 3b1a2c9def4f..3b1a2c9def4f 100644
--- a/core/java/android/service/euicc/DownloadSubscriptionResult.java
+++ b/telephony/java/android/service/euicc/DownloadSubscriptionResult.java
diff --git a/core/java/android/service/euicc/EuiccProfileInfo.aidl b/telephony/java/android/service/euicc/EuiccProfileInfo.aidl
index 321021b5273c..321021b5273c 100644
--- a/core/java/android/service/euicc/EuiccProfileInfo.aidl
+++ b/telephony/java/android/service/euicc/EuiccProfileInfo.aidl
diff --git a/core/java/android/service/euicc/EuiccProfileInfo.java b/telephony/java/android/service/euicc/EuiccProfileInfo.java
index 6c357ccdd03d..6c357ccdd03d 100644
--- a/core/java/android/service/euicc/EuiccProfileInfo.java
+++ b/telephony/java/android/service/euicc/EuiccProfileInfo.java
diff --git a/core/java/android/service/euicc/EuiccService.java b/telephony/java/android/service/euicc/EuiccService.java
index bc6a9e848e2a..bc6a9e848e2a 100644
--- a/core/java/android/service/euicc/EuiccService.java
+++ b/telephony/java/android/service/euicc/EuiccService.java
diff --git a/core/java/android/service/euicc/GetDefaultDownloadableSubscriptionListResult.aidl b/telephony/java/android/service/euicc/GetDefaultDownloadableSubscriptionListResult.aidl
index c2636a16edee..c2636a16edee 100644
--- a/core/java/android/service/euicc/GetDefaultDownloadableSubscriptionListResult.aidl
+++ b/telephony/java/android/service/euicc/GetDefaultDownloadableSubscriptionListResult.aidl
diff --git a/core/java/android/service/euicc/GetDefaultDownloadableSubscriptionListResult.java b/telephony/java/android/service/euicc/GetDefaultDownloadableSubscriptionListResult.java
index c7a985160730..c7a985160730 100644
--- a/core/java/android/service/euicc/GetDefaultDownloadableSubscriptionListResult.java
+++ b/telephony/java/android/service/euicc/GetDefaultDownloadableSubscriptionListResult.java
diff --git a/core/java/android/service/euicc/GetDownloadableSubscriptionMetadataResult.aidl b/telephony/java/android/service/euicc/GetDownloadableSubscriptionMetadataResult.aidl
index 791ad9b469ef..791ad9b469ef 100644
--- a/core/java/android/service/euicc/GetDownloadableSubscriptionMetadataResult.aidl
+++ b/telephony/java/android/service/euicc/GetDownloadableSubscriptionMetadataResult.aidl
diff --git a/core/java/android/service/euicc/GetDownloadableSubscriptionMetadataResult.java b/telephony/java/android/service/euicc/GetDownloadableSubscriptionMetadataResult.java
index abd4065c754a..abd4065c754a 100644
--- a/core/java/android/service/euicc/GetDownloadableSubscriptionMetadataResult.java
+++ b/telephony/java/android/service/euicc/GetDownloadableSubscriptionMetadataResult.java
diff --git a/core/java/android/service/euicc/GetEuiccProfileInfoListResult.aidl b/telephony/java/android/service/euicc/GetEuiccProfileInfoListResult.aidl
index 6003b79462da..6003b79462da 100644
--- a/core/java/android/service/euicc/GetEuiccProfileInfoListResult.aidl
+++ b/telephony/java/android/service/euicc/GetEuiccProfileInfoListResult.aidl
diff --git a/core/java/android/service/euicc/GetEuiccProfileInfoListResult.java b/telephony/java/android/service/euicc/GetEuiccProfileInfoListResult.java
index 9add38e40d9b..9add38e40d9b 100644
--- a/core/java/android/service/euicc/GetEuiccProfileInfoListResult.java
+++ b/telephony/java/android/service/euicc/GetEuiccProfileInfoListResult.java
diff --git a/core/java/android/service/euicc/IDeleteSubscriptionCallback.aidl b/telephony/java/android/service/euicc/IDeleteSubscriptionCallback.aidl
index aff8f1b7b346..aff8f1b7b346 100644
--- a/core/java/android/service/euicc/IDeleteSubscriptionCallback.aidl
+++ b/telephony/java/android/service/euicc/IDeleteSubscriptionCallback.aidl
diff --git a/core/java/android/service/euicc/IDownloadSubscriptionCallback.aidl b/telephony/java/android/service/euicc/IDownloadSubscriptionCallback.aidl
index 50ecbebf5e84..50ecbebf5e84 100644
--- a/core/java/android/service/euicc/IDownloadSubscriptionCallback.aidl
+++ b/telephony/java/android/service/euicc/IDownloadSubscriptionCallback.aidl
diff --git a/core/java/android/service/euicc/IEraseSubscriptionsCallback.aidl b/telephony/java/android/service/euicc/IEraseSubscriptionsCallback.aidl
index 34b53cc71dfb..34b53cc71dfb 100644
--- a/core/java/android/service/euicc/IEraseSubscriptionsCallback.aidl
+++ b/telephony/java/android/service/euicc/IEraseSubscriptionsCallback.aidl
diff --git a/core/java/android/service/euicc/IEuiccService.aidl b/telephony/java/android/service/euicc/IEuiccService.aidl
index 2acc47aae919..2acc47aae919 100644
--- a/core/java/android/service/euicc/IEuiccService.aidl
+++ b/telephony/java/android/service/euicc/IEuiccService.aidl
diff --git a/core/java/android/service/euicc/IGetDefaultDownloadableSubscriptionListCallback.aidl b/telephony/java/android/service/euicc/IGetDefaultDownloadableSubscriptionListCallback.aidl
index ad69ef132428..ad69ef132428 100644
--- a/core/java/android/service/euicc/IGetDefaultDownloadableSubscriptionListCallback.aidl
+++ b/telephony/java/android/service/euicc/IGetDefaultDownloadableSubscriptionListCallback.aidl
diff --git a/core/java/android/service/euicc/IGetDownloadableSubscriptionMetadataCallback.aidl b/telephony/java/android/service/euicc/IGetDownloadableSubscriptionMetadataCallback.aidl
index 01f187ed11e2..01f187ed11e2 100644
--- a/core/java/android/service/euicc/IGetDownloadableSubscriptionMetadataCallback.aidl
+++ b/telephony/java/android/service/euicc/IGetDownloadableSubscriptionMetadataCallback.aidl
diff --git a/core/java/android/service/euicc/IGetEidCallback.aidl b/telephony/java/android/service/euicc/IGetEidCallback.aidl
index e405a981c85a..e405a981c85a 100644
--- a/core/java/android/service/euicc/IGetEidCallback.aidl
+++ b/telephony/java/android/service/euicc/IGetEidCallback.aidl
diff --git a/core/java/android/service/euicc/IGetEuiccInfoCallback.aidl b/telephony/java/android/service/euicc/IGetEuiccInfoCallback.aidl
index c0611825ff0f..c0611825ff0f 100644
--- a/core/java/android/service/euicc/IGetEuiccInfoCallback.aidl
+++ b/telephony/java/android/service/euicc/IGetEuiccInfoCallback.aidl
diff --git a/core/java/android/service/euicc/IGetEuiccProfileInfoListCallback.aidl b/telephony/java/android/service/euicc/IGetEuiccProfileInfoListCallback.aidl
index 0485f7be29d3..0485f7be29d3 100644
--- a/core/java/android/service/euicc/IGetEuiccProfileInfoListCallback.aidl
+++ b/telephony/java/android/service/euicc/IGetEuiccProfileInfoListCallback.aidl
diff --git a/core/java/android/service/euicc/IGetOtaStatusCallback.aidl b/telephony/java/android/service/euicc/IGetOtaStatusCallback.aidl
index f6678889ccc7..f6678889ccc7 100644
--- a/core/java/android/service/euicc/IGetOtaStatusCallback.aidl
+++ b/telephony/java/android/service/euicc/IGetOtaStatusCallback.aidl
diff --git a/core/java/android/service/euicc/IOtaStatusChangedCallback.aidl b/telephony/java/android/service/euicc/IOtaStatusChangedCallback.aidl
index caec75f13f61..caec75f13f61 100644
--- a/core/java/android/service/euicc/IOtaStatusChangedCallback.aidl
+++ b/telephony/java/android/service/euicc/IOtaStatusChangedCallback.aidl
diff --git a/core/java/android/service/euicc/IRetainSubscriptionsForFactoryResetCallback.aidl b/telephony/java/android/service/euicc/IRetainSubscriptionsForFactoryResetCallback.aidl
index 340401fe89cb..340401fe89cb 100644
--- a/core/java/android/service/euicc/IRetainSubscriptionsForFactoryResetCallback.aidl
+++ b/telephony/java/android/service/euicc/IRetainSubscriptionsForFactoryResetCallback.aidl
diff --git a/core/java/android/service/euicc/ISwitchToSubscriptionCallback.aidl b/telephony/java/android/service/euicc/ISwitchToSubscriptionCallback.aidl
index b8f984d1c28b..b8f984d1c28b 100644
--- a/core/java/android/service/euicc/ISwitchToSubscriptionCallback.aidl
+++ b/telephony/java/android/service/euicc/ISwitchToSubscriptionCallback.aidl
diff --git a/core/java/android/service/euicc/IUpdateSubscriptionNicknameCallback.aidl b/telephony/java/android/service/euicc/IUpdateSubscriptionNicknameCallback.aidl
index 0aa66978bb91..0aa66978bb91 100644
--- a/core/java/android/service/euicc/IUpdateSubscriptionNicknameCallback.aidl
+++ b/telephony/java/android/service/euicc/IUpdateSubscriptionNicknameCallback.aidl
diff --git a/telephony/java/android/telephony/DataFailCause.java b/telephony/java/android/telephony/DataFailCause.java
index 246bec7de59e..7bdf1f57f8b2 100644
--- a/telephony/java/android/telephony/DataFailCause.java
+++ b/telephony/java/android/telephony/DataFailCause.java
@@ -15,17 +15,14 @@
*/
package android.telephony;
-import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.content.Context;
import android.os.PersistableBundle;
-
import android.telephony.Annotation.DataFailureCause;
-import com.android.internal.util.ArrayUtils;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
+import com.android.internal.telephony.util.ArrayUtils;
+
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
diff --git a/telephony/java/android/telephony/LocationAccessPolicy.java b/telephony/java/android/telephony/LocationAccessPolicy.java
index 79b375675588..fe273b267e98 100644
--- a/telephony/java/android/telephony/LocationAccessPolicy.java
+++ b/telephony/java/android/telephony/LocationAccessPolicy.java
@@ -193,6 +193,17 @@ public final class LocationAccessPolicy {
}
}
+ private static String getAppOpsString(String manifestPermission) {
+ switch (manifestPermission) {
+ case Manifest.permission.ACCESS_FINE_LOCATION:
+ return AppOpsManager.OPSTR_FINE_LOCATION;
+ case Manifest.permission.ACCESS_COARSE_LOCATION:
+ return AppOpsManager.OPSTR_COARSE_LOCATION;
+ default:
+ return null;
+ }
+ }
+
private static LocationPermissionResult checkAppLocationPermissionHelper(Context context,
LocationPermissionQuery query, String permissionToCheck) {
String locationTypeForLog =
@@ -206,8 +217,8 @@ public final class LocationAccessPolicy {
if (hasManifestPermission) {
// Only check the app op if the app has the permission.
int appOpMode = context.getSystemService(AppOpsManager.class)
- .noteOpNoThrow(AppOpsManager.permissionToOpCode(permissionToCheck),
- query.callingUid, query.callingPackage, query.callingFeatureId, null);
+ .noteOpNoThrow(getAppOpsString(permissionToCheck), query.callingUid,
+ query.callingPackage, query.callingFeatureId, null);
if (appOpMode == AppOpsManager.MODE_ALLOWED) {
// If the app did everything right, return without logging.
return LocationPermissionResult.ALLOWED;
diff --git a/telephony/java/android/telephony/SmsCbMessage.java b/telephony/java/android/telephony/SmsCbMessage.java
index fad70d2da8be..c7f952954d5f 100644
--- a/telephony/java/android/telephony/SmsCbMessage.java
+++ b/telephony/java/android/telephony/SmsCbMessage.java
@@ -29,6 +29,7 @@ import android.telephony.CbGeoUtils.Geometry;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
import java.util.List;
/**
@@ -407,13 +408,17 @@ public final class SmsCbMessage implements Parcelable {
}
/**
- * Get the warning area coordinates information represent by polygons and circles.
- * @return a list of geometries, {@link Nullable} means there is no coordinate information
- * associated to this message.
+ * Get the warning area coordinates information represented by polygons and circles.
+ * @return a list of geometries, or an empty list if there is no coordinate information
+ * associated with this message.
* @hide
*/
- @Nullable
+ @SystemApi
+ @NonNull
public List<Geometry> getGeometries() {
+ if (mGeometries == null) {
+ return new ArrayList<>();
+ }
return mGeometries;
}
@@ -720,6 +725,6 @@ public final class SmsCbMessage implements Parcelable {
* @return {@code True} if this message needs geo-fencing check.
*/
public boolean needGeoFencingCheck() {
- return mMaximumWaitTimeSec > 0 && mGeometries != null;
+ return mMaximumWaitTimeSec > 0 && mGeometries != null && !mGeometries.isEmpty();
}
}
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 43d9c1102b1a..fbbf75a85a9b 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -2713,9 +2713,14 @@ public class SubscriptionManager {
if (executor == null || callback == null) {
return;
}
- Binder.withCleanCallingIdentity(() -> executor.execute(() -> {
- callback.accept(result);
- }));
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ executor.execute(() -> {
+ callback.accept(result);
+ });
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
};
iSub.setPreferredDataSubscriptionId(subId, needValidation, callbackStub);
@@ -3110,7 +3115,11 @@ public class SubscriptionManager {
}
/**
- * Enables or disables a subscription. This is currently used in the settings page.
+ * Enables or disables a subscription. This is currently used in the settings page. It will
+ * fail and return false if operation is not supported or failed.
+ *
+ * To disable an active subscription on a physical (non-Euicc) SIM,
+ * {@link #canDisablePhysicalSubscription} needs to be true.
*
* <p>
* Permissions android.Manifest.permission.MODIFY_PHONE_STATE is required
@@ -3142,6 +3151,38 @@ public class SubscriptionManager {
}
/**
+ * Whether it's supported to disable / re-enable a subscription on a physical (non-euicc) SIM.
+ *
+ * Physical SIM refers non-euicc, or aka non-programmable SIM.
+ *
+ * It provides whether a physical SIM card can be disabled without taking it out, which is done
+ * via {@link #setSubscriptionEnabled(int, boolean)} API.
+ *
+ * Requires Permission: READ_PRIVILEGED_PHONE_STATE.
+ *
+ * @return whether can disable subscriptions on physical SIMs.
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ public boolean canDisablePhysicalSubscription() {
+ if (VDBG) {
+ logd("canDisablePhysicalSubscription");
+ }
+ try {
+ ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ if (iSub != null) {
+ return iSub.canDisablePhysicalSubscription();
+ }
+ } catch (RemoteException ex) {
+ // ignore it
+ }
+
+ return false;
+ }
+
+ /**
* DO NOT USE.
* This API is designed for features that are not finished at this point. Do not call this API.
* @hide
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 9f8a213600da..fc26122912dc 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -86,7 +86,6 @@ import android.util.Pair;
import com.android.ims.internal.IImsServiceFeatureCallback;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.telecom.ITelecomService;
import com.android.internal.telephony.CellNetworkScanResult;
import com.android.internal.telephony.INumberVerificationCallback;
import com.android.internal.telephony.IOns;
@@ -5176,13 +5175,11 @@ public class TelephonyManager {
* @return the current call state.
*/
public @CallState int getCallState() {
- try {
- ITelecomService telecom = getTelecomService();
- if (telecom != null) {
- return telecom.getCallState();
+ if (mContext != null) {
+ TelecomManager telecomManager = mContext.getSystemService(TelecomManager.class);
+ if (telecomManager != null) {
+ return telecomManager.getCallState();
}
- } catch (RemoteException e) {
- Log.e(TAG, "Error calling ITelecomService#getCallState", e);
}
return CALL_STATE_IDLE;
}
@@ -5341,13 +5338,6 @@ public class TelephonyManager {
return ITelephony.Stub.asInterface(ServiceManager.getService(Context.TELEPHONY_SERVICE));
}
- /**
- * @hide
- */
- private ITelecomService getTelecomService() {
- return ITelecomService.Stub.asInterface(ServiceManager.getService(TELECOM_SERVICE));
- }
-
private ITelephonyRegistry getTelephonyRegistry() {
return ITelephonyRegistry.Stub.asInterface(ServiceManager.getService("telephony.registry"));
}
@@ -5682,16 +5672,24 @@ public class TelephonyManager {
new ICellInfoCallback.Stub() {
@Override
public void onCellInfo(List<CellInfo> cellInfo) {
- Binder.withCleanCallingIdentity(() ->
- executor.execute(() -> callback.onCellInfo(cellInfo)));
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ executor.execute(() -> callback.onCellInfo(cellInfo));
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
@Override
public void onError(int errorCode, String exceptionName, String message) {
- Binder.withCleanCallingIdentity(() ->
- executor.execute(() -> callback.onError(
- errorCode,
- createThrowableByClassName(exceptionName, message))));
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ executor.execute(() -> callback.onError(
+ errorCode,
+ createThrowableByClassName(exceptionName, message)));
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
}, getOpPackageName(), getFeatureId());
} catch (RemoteException ex) {
@@ -5724,16 +5722,25 @@ public class TelephonyManager {
new ICellInfoCallback.Stub() {
@Override
public void onCellInfo(List<CellInfo> cellInfo) {
- Binder.withCleanCallingIdentity(() ->
- executor.execute(() -> callback.onCellInfo(cellInfo)));
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ executor.execute(() -> callback.onCellInfo(cellInfo));
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+
}
@Override
public void onError(int errorCode, String exceptionName, String message) {
- Binder.withCleanCallingIdentity(() ->
- executor.execute(() -> callback.onError(
- errorCode,
- createThrowableByClassName(exceptionName, message))));
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ executor.execute(() -> callback.onError(
+ errorCode,
+ createThrowableByClassName(exceptionName, message)));
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
}, getOpPackageName(), getFeatureId(), workSource);
} catch (RemoteException ex) {
@@ -6598,16 +6605,24 @@ public class TelephonyManager {
INumberVerificationCallback internalCallback = new INumberVerificationCallback.Stub() {
@Override
public void onCallReceived(String phoneNumber) {
- Binder.withCleanCallingIdentity(() ->
- executor.execute(() ->
- callback.onCallReceived(phoneNumber)));
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ executor.execute(() ->
+ callback.onCallReceived(phoneNumber));
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
@Override
public void onVerificationFailed(int reason) {
- Binder.withCleanCallingIdentity(() ->
- executor.execute(() ->
- callback.onVerificationFailed(reason)));
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ executor.execute(() ->
+ callback.onVerificationFailed(reason));
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
};
@@ -11507,9 +11522,14 @@ public class TelephonyManager {
if (executor == null || callback == null) {
return;
}
- Binder.withCleanCallingIdentity(() -> executor.execute(() -> {
- callback.accept(SET_OPPORTUNISTIC_SUB_REMOTE_SERVICE_EXCEPTION);
- }));
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ executor.execute(() -> {
+ callback.accept(SET_OPPORTUNISTIC_SUB_REMOTE_SERVICE_EXCEPTION);
+ });
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
return;
}
ISetOpportunisticDataCallback callbackStub = new ISetOpportunisticDataCallback.Stub() {
@@ -11518,9 +11538,14 @@ public class TelephonyManager {
if (executor == null || callback == null) {
return;
}
- Binder.withCleanCallingIdentity(() -> executor.execute(() -> {
- callback.accept(result);
- }));
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ executor.execute(() -> {
+ callback.accept(result);
+ });
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
};
@@ -11594,13 +11619,23 @@ public class TelephonyManager {
return;
}
if (iOpportunisticNetworkService == null) {
- Binder.withCleanCallingIdentity(() -> executor.execute(() -> {
- callback.accept(UPDATE_AVAILABLE_NETWORKS_REMOTE_SERVICE_EXCEPTION);
- }));
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ executor.execute(() -> {
+ callback.accept(UPDATE_AVAILABLE_NETWORKS_REMOTE_SERVICE_EXCEPTION);
+ });
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
} else {
- Binder.withCleanCallingIdentity(() -> executor.execute(() -> {
- callback.accept(UPDATE_AVAILABLE_NETWORKS_INVALID_ARGUMENTS);
- }));
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ executor.execute(() -> {
+ callback.accept(UPDATE_AVAILABLE_NETWORKS_INVALID_ARGUMENTS);
+ });
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
return;
}
@@ -11611,9 +11646,14 @@ public class TelephonyManager {
if (executor == null || callback == null) {
return;
}
- Binder.withCleanCallingIdentity(() -> executor.execute(() -> {
- callback.accept(result);
- }));
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ executor.execute(() -> {
+ callback.accept(result);
+ });
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
};
iOpportunisticNetworkService.updateAvailableNetworks(availableNetworks, callbackStub,
diff --git a/telephony/java/com/android/internal/telephony/CarrierAppUtils.java b/telephony/java/com/android/internal/telephony/CarrierAppUtils.java
index e6bebbb62153..2dc6ae3ff10b 100644
--- a/telephony/java/com/android/internal/telephony/CarrierAppUtils.java
+++ b/telephony/java/com/android/internal/telephony/CarrierAppUtils.java
@@ -32,7 +32,7 @@ import android.util.ArraySet;
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.ArrayUtils;
+import com.android.internal.telephony.util.ArrayUtils;
import com.android.server.SystemConfig;
import java.util.ArrayList;
diff --git a/telephony/java/com/android/internal/telephony/ISub.aidl b/telephony/java/com/android/internal/telephony/ISub.aidl
index 151aae89a3ff..c5d58ac24904 100755
--- a/telephony/java/com/android/internal/telephony/ISub.aidl
+++ b/telephony/java/com/android/internal/telephony/ISub.aidl
@@ -298,4 +298,6 @@ interface ISub {
boolean setAlwaysAllowMmsData(int subId, boolean alwaysAllow);
int getActiveDataSubscriptionId();
+
+ boolean canDisablePhysicalSubscription();
}
diff --git a/telephony/java/com/android/internal/telephony/Sms7BitEncodingTranslator.java b/telephony/java/com/android/internal/telephony/Sms7BitEncodingTranslator.java
index 2cdf2f63e02f..dcea9bb72c01 100644
--- a/telephony/java/com/android/internal/telephony/Sms7BitEncodingTranslator.java
+++ b/telephony/java/com/android/internal/telephony/Sms7BitEncodingTranslator.java
@@ -23,7 +23,7 @@ import android.telephony.Rlog;
import android.util.SparseIntArray;
import com.android.internal.telephony.cdma.sms.UserData;
-import com.android.internal.util.XmlUtils;
+import com.android.internal.telephony.util.XmlUtils;
import dalvik.annotation.compat.UnsupportedAppUsage;
diff --git a/telephony/java/com/android/internal/telephony/TelephonyPermissions.java b/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
index 6e20621e82f2..96ddf22b64b4 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
@@ -390,7 +390,6 @@ public final class TelephonyPermissions {
private static boolean reportAccessDeniedToReadIdentifiers(Context context, int subId, int pid,
int uid, String callingPackage, String message) {
boolean isPreinstalled = false;
- boolean isPrivApp = false;
ApplicationInfo callingPackageInfo = null;
try {
callingPackageInfo = context.getPackageManager().getApplicationInfoAsUser(
@@ -398,9 +397,6 @@ public final class TelephonyPermissions {
if (callingPackageInfo != null) {
if (callingPackageInfo.isSystemApp()) {
isPreinstalled = true;
- if (callingPackageInfo.isPrivilegedApp()) {
- isPrivApp = true;
- }
}
}
} catch (PackageManager.NameNotFoundException e) {
@@ -423,10 +419,10 @@ public final class TelephonyPermissions {
}
invokedMethods.add(message);
StatsLog.write(StatsLog.DEVICE_IDENTIFIER_ACCESS_DENIED, callingPackage, message,
- isPreinstalled, isPrivApp);
+ isPreinstalled, false);
}
Log.w(LOG_TAG, "reportAccessDeniedToReadIdentifiers:" + callingPackage + ":" + message
- + ":isPreinstalled=" + isPreinstalled + ":isPrivApp=" + isPrivApp);
+ + ":isPreinstalled=" + isPreinstalled);
// if the target SDK is pre-Q then check if the calling package would have previously
// had access to device identifiers.
if (callingPackageInfo != null && (
diff --git a/telephony/java/com/android/internal/telephony/util/ArrayUtils.java b/telephony/java/com/android/internal/telephony/util/ArrayUtils.java
new file mode 100644
index 000000000000..2905125c69cc
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/util/ArrayUtils.java
@@ -0,0 +1,229 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.telephony.util;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+import java.lang.reflect.Array;
+import java.util.Collection;
+import java.util.Map;
+import java.util.Objects;
+
+/** Utility methods for array operations. */
+public final class ArrayUtils {
+ private ArrayUtils() { /* cannot be instantiated */ }
+
+ /**
+ * Adds value to given array if not already present, providing set-like behavior.
+ */
+ @SuppressWarnings("unchecked")
+ public static @NonNull <T> T[] appendElement(Class<T> kind, @Nullable T[] array, T element) {
+ return appendElement(kind, array, element, false);
+ }
+
+ /**
+ * Adds value to given array.
+ */
+ @SuppressWarnings("unchecked")
+ public static @NonNull <T> T[] appendElement(Class<T> kind, @Nullable T[] array, T element,
+ boolean allowDuplicates) {
+ final T[] result;
+ final int end;
+ if (array != null) {
+ if (!allowDuplicates && contains(array, element)) return array;
+ end = array.length;
+ result = (T[]) Array.newInstance(kind, end + 1);
+ System.arraycopy(array, 0, result, 0, end);
+ } else {
+ end = 0;
+ result = (T[]) Array.newInstance(kind, 1);
+ }
+ result[end] = element;
+ return result;
+ }
+
+ /**
+ * Combine multiple arrays into a single array.
+ *
+ * @param kind The class of the array elements
+ * @param arrays The arrays to combine
+ * @param <T> The class of the array elements (inferred from kind).
+ * @return A single array containing all the elements of the parameter arrays.
+ */
+ @SuppressWarnings("unchecked")
+ public static @NonNull <T> T[] concatElements(Class<T> kind, @Nullable T[]... arrays) {
+ if (arrays == null || arrays.length == 0) {
+ return createEmptyArray(kind);
+ }
+
+ int totalLength = 0;
+ for (T[] item : arrays) {
+ if (item == null) {
+ continue;
+ }
+
+ totalLength += item.length;
+ }
+
+ // Optimization for entirely empty arrays.
+ if (totalLength == 0) {
+ return createEmptyArray(kind);
+ }
+
+ final T[] all = (T[]) Array.newInstance(kind, totalLength);
+ int pos = 0;
+ for (T[] item : arrays) {
+ if (item == null || item.length == 0) {
+ continue;
+ }
+ System.arraycopy(item, 0, all, pos, item.length);
+ pos += item.length;
+ }
+ return all;
+ }
+
+ private static @NonNull <T> T[] createEmptyArray(Class<T> kind) {
+ if (kind == String.class) {
+ return (T[]) EmptyArray.STRING;
+ } else if (kind == Object.class) {
+ return (T[]) EmptyArray.OBJECT;
+ }
+
+ return (T[]) Array.newInstance(kind, 0);
+ }
+
+ private static final class EmptyArray {
+ private EmptyArray() {}
+
+ public static final Object[] OBJECT = new Object[0];
+ public static final String[] STRING = new String[0];
+ }
+
+ /**
+ * Checks if {@code value} is in {@code array}.
+ */
+ public static boolean contains(@Nullable char[] array, char value) {
+ if (array == null) return false;
+ for (char element : array) {
+ if (element == value) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Checks if {@code value} is in {@code array}.
+ */
+ public static <T> boolean contains(@Nullable Collection<T> cur, T val) {
+ return (cur != null) ? cur.contains(val) : false;
+ }
+
+ /**
+ * Checks if {@code value} is in {@code array}.
+ */
+ public static boolean contains(@Nullable int[] array, int value) {
+ if (array == null) return false;
+ for (int element : array) {
+ if (element == value) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Checks if {@code value} is in {@code array}.
+ */
+ public static boolean contains(@Nullable long[] array, long value) {
+ if (array == null) return false;
+ for (long element : array) {
+ if (element == value) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Checks if {@code value} is in {@code array}.
+ */
+ public static <T> boolean contains(@Nullable T[] array, T value) {
+ return indexOf(array, value) != -1;
+ }
+
+ /**
+ * Return first index of {@code value} in {@code array}, or {@code -1} if
+ * not found.
+ */
+ public static <T> int indexOf(@Nullable T[] array, T value) {
+ if (array == null) return -1;
+ for (int i = 0; i < array.length; i++) {
+ if (Objects.equals(array[i], value)) return i;
+ }
+ return -1;
+ }
+
+ /**
+ * Checks if given array is null or has zero elements.
+ */
+ public static boolean isEmpty(@Nullable Collection<?> array) {
+ return array == null || array.isEmpty();
+ }
+
+ /**
+ * Checks if given map is null or has zero elements.
+ */
+ public static boolean isEmpty(@Nullable Map<?, ?> map) {
+ return map == null || map.isEmpty();
+ }
+
+ /**
+ * Checks if given array is null or has zero elements.
+ */
+ public static <T> boolean isEmpty(@Nullable T[] array) {
+ return array == null || array.length == 0;
+ }
+
+ /**
+ * Checks if given array is null or has zero elements.
+ */
+ public static boolean isEmpty(@Nullable int[] array) {
+ return array == null || array.length == 0;
+ }
+
+ /**
+ * Checks if given array is null or has zero elements.
+ */
+ public static boolean isEmpty(@Nullable long[] array) {
+ return array == null || array.length == 0;
+ }
+
+ /**
+ * Checks if given array is null or has zero elements.
+ */
+ public static boolean isEmpty(@Nullable byte[] array) {
+ return array == null || array.length == 0;
+ }
+
+ /**
+ * Checks if given array is null or has zero elements.
+ */
+ public static boolean isEmpty(@Nullable boolean[] array) {
+ return array == null || array.length == 0;
+ }
+}
diff --git a/telephony/java/com/android/internal/telephony/util/XmlUtils.java b/telephony/java/com/android/internal/telephony/util/XmlUtils.java
new file mode 100644
index 000000000000..72c5d3a8e31b
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/util/XmlUtils.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony.util;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+
+/** Utility methods for XML operations. */
+public final class XmlUtils {
+ private XmlUtils() {}
+
+ /**
+ * Moves parser to the first start tag, and expects the tag name being {@code firstElementName}.
+ */
+ public static void beginDocument(XmlPullParser parser, String firstElementName)
+ throws XmlPullParserException, IOException {
+ int type;
+ while ((type = parser.next()) != parser.START_TAG && type != parser.END_DOCUMENT) {
+ // no-op
+ }
+
+ if (type != parser.START_TAG) {
+ throw new XmlPullParserException("No start tag found");
+ }
+
+ if (!parser.getName().equals(firstElementName)) {
+ throw new XmlPullParserException("Unexpected start tag: found " + parser.getName()
+ + ", expected " + firstElementName);
+ }
+ }
+
+ /**
+ * Moves parser to the next start tag.
+ */
+ public static void nextElement(XmlPullParser parser)
+ throws XmlPullParserException, IOException {
+ int type;
+ while ((type = parser.next()) != parser.START_TAG && type != parser.END_DOCUMENT) {
+ // no-op
+ }
+ }
+
+ /**
+ * Moves parser to the next start tag within the {@code outerDepth}.
+ */
+ public static boolean nextElementWithin(XmlPullParser parser, int outerDepth)
+ throws IOException, XmlPullParserException {
+ for (;;) {
+ int type = parser.next();
+ if (type == XmlPullParser.END_DOCUMENT
+ || (type == XmlPullParser.END_TAG && parser.getDepth() == outerDepth)) {
+ return false;
+ }
+ if (type == XmlPullParser.START_TAG && parser.getDepth() == outerDepth + 1) {
+ return true;
+ }
+ }
+ }
+}
diff --git a/test-mock/src/android/test/mock/MockContext.java b/test-mock/src/android/test/mock/MockContext.java
index 45b236c307c3..0208c3a0a0de 100644
--- a/test-mock/src/android/test/mock/MockContext.java
+++ b/test-mock/src/android/test/mock/MockContext.java
@@ -470,6 +470,13 @@ public class MockContext extends Context {
}
@Override
+ public void sendOrderedBroadcast(Intent intent, String receiverPermission, String receiverAppOp,
+ Bundle options, BroadcastReceiver resultReceiver, Handler scheduler, int initialCode,
+ String initialData, Bundle initialExtras) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
public void sendStickyBroadcast(Intent intent) {
throw new UnsupportedOperationException();
}
diff --git a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
index 06b58fda5b7d..e30878157a26 100644
--- a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
+++ b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
@@ -670,11 +670,11 @@ public class PackageWatchdogTest {
public void testPackageHealthCheckStateTransitions() {
TestController controller = new TestController();
PackageWatchdog wd = createWatchdog(controller, true /* withPackagesReady */);
- MonitoredPackage m1 = wd.new MonitoredPackage(APP_A, LONG_DURATION,
+ MonitoredPackage m1 = wd.newMonitoredPackage(APP_A, LONG_DURATION,
false /* hasPassedHealthCheck */);
- MonitoredPackage m2 = wd.new MonitoredPackage(APP_B, LONG_DURATION, false);
- MonitoredPackage m3 = wd.new MonitoredPackage(APP_C, LONG_DURATION, false);
- MonitoredPackage m4 = wd.new MonitoredPackage(APP_D, LONG_DURATION, SHORT_DURATION, true);
+ MonitoredPackage m2 = wd.newMonitoredPackage(APP_B, LONG_DURATION, false);
+ MonitoredPackage m3 = wd.newMonitoredPackage(APP_C, LONG_DURATION, false);
+ MonitoredPackage m4 = wd.newMonitoredPackage(APP_D, LONG_DURATION, SHORT_DURATION, true);
// Verify transition: inactive -> active -> passed
// Verify initially inactive
diff --git a/tests/net/Android.bp b/tests/net/Android.bp
index 10f27e243c8c..b2f384ac8360 100644
--- a/tests/net/Android.bp
+++ b/tests/net/Android.bp
@@ -45,7 +45,6 @@ android_test {
name: "FrameworksNetTests",
defaults: ["FrameworksNetTests-jni-defaults"],
srcs: [
- ":tethering-tests-src",
"java/**/*.java",
"java/**/*.kt",
],
diff --git a/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt b/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt
index 334b26d82129..25028fb3ca0e 100644
--- a/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt
+++ b/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt
@@ -32,6 +32,7 @@ import android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET
import android.net.NetworkCapabilities.TRANSPORT_CELLULAR
import android.net.NetworkRequest
import android.net.TestNetworkStackClient
+import android.net.TetheringManager
import android.net.metrics.IpConnectivityLog
import android.os.ConditionVariable
import android.os.IBinder
@@ -48,7 +49,6 @@ import com.android.server.connectivity.DefaultNetworkMetrics
import com.android.server.connectivity.IpConnectivityMetrics
import com.android.server.connectivity.MockableSystemProperties
import com.android.server.connectivity.ProxyTracker
-import com.android.server.connectivity.Tethering
import com.android.server.net.NetworkPolicyManagerInternal
import com.android.testutils.TestableNetworkCallback
import org.junit.After
@@ -169,8 +169,7 @@ class ConnectivityServiceIntegrationTest {
val deps = spy(ConnectivityService.Dependencies())
doReturn(networkStackClient).`when`(deps).networkStack
doReturn(metricsLogger).`when`(deps).metricsLogger
- doReturn(mock(Tethering::class.java)).`when`(deps).makeTethering(
- any(), any(), any(), any(), any())
+ doReturn(mock(TetheringManager::class.java)).`when`(deps).getTetheringManager()
doReturn(mock(ProxyTracker::class.java)).`when`(deps).makeProxyTracker(any(), any())
doReturn(mock(MockableSystemProperties::class.java)).`when`(deps).systemProperties
doReturn(TestNetIdManager()).`when`(deps).makeNetIdManager()
diff --git a/tests/net/java/com/android/internal/util/BitUtilsTest.java b/tests/net/java/com/android/internal/util/BitUtilsTest.java
index 01fb0df2d47e..d2fbdce9771a 100644
--- a/tests/net/java/com/android/internal/util/BitUtilsTest.java
+++ b/tests/net/java/com/android/internal/util/BitUtilsTest.java
@@ -21,11 +21,14 @@ import static com.android.internal.util.BitUtils.bytesToLEInt;
import static com.android.internal.util.BitUtils.getUint16;
import static com.android.internal.util.BitUtils.getUint32;
import static com.android.internal.util.BitUtils.getUint8;
+import static com.android.internal.util.BitUtils.packBits;
import static com.android.internal.util.BitUtils.uint16;
import static com.android.internal.util.BitUtils.uint32;
import static com.android.internal.util.BitUtils.uint8;
+import static com.android.internal.util.BitUtils.unpackBits;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
@@ -34,6 +37,8 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import java.nio.ByteBuffer;
+import java.util.Arrays;
+import java.util.Random;
@SmallTest
@RunWith(AndroidJUnit4.class)
@@ -110,20 +115,66 @@ public class BitUtilsTest {
@Test
public void testUnsignedGetters() {
- ByteBuffer b = ByteBuffer.allocate(4);
- b.putInt(0xffff);
+ ByteBuffer b = ByteBuffer.allocate(4);
+ b.putInt(0xffff);
- assertEquals(0x0, getUint8(b, 0));
- assertEquals(0x0, getUint8(b, 1));
- assertEquals(0xff, getUint8(b, 2));
- assertEquals(0xff, getUint8(b, 3));
+ assertEquals(0x0, getUint8(b, 0));
+ assertEquals(0x0, getUint8(b, 1));
+ assertEquals(0xff, getUint8(b, 2));
+ assertEquals(0xff, getUint8(b, 3));
- assertEquals(0x0, getUint16(b, 0));
- assertEquals(0xffff, getUint16(b, 2));
+ assertEquals(0x0, getUint16(b, 0));
+ assertEquals(0xffff, getUint16(b, 2));
- b.rewind();
- b.putInt(0xffffffff);
- assertEquals(0xffffffffL, getUint32(b, 0));
+ b.rewind();
+ b.putInt(0xffffffff);
+ assertEquals(0xffffffffL, getUint32(b, 0));
+ }
+
+ @Test
+ public void testBitsPacking() {
+ BitPackingTestCase[] testCases = {
+ new BitPackingTestCase(0, ints()),
+ new BitPackingTestCase(1, ints(0)),
+ new BitPackingTestCase(2, ints(1)),
+ new BitPackingTestCase(3, ints(0, 1)),
+ new BitPackingTestCase(4, ints(2)),
+ new BitPackingTestCase(6, ints(1, 2)),
+ new BitPackingTestCase(9, ints(0, 3)),
+ new BitPackingTestCase(~Long.MAX_VALUE, ints(63)),
+ new BitPackingTestCase(~Long.MAX_VALUE + 1, ints(0, 63)),
+ new BitPackingTestCase(~Long.MAX_VALUE + 2, ints(1, 63)),
+ };
+ for (BitPackingTestCase tc : testCases) {
+ int[] got = unpackBits(tc.packedBits);
+ assertTrue(
+ "unpackBits("
+ + tc.packedBits
+ + "): expected "
+ + Arrays.toString(tc.bits)
+ + " but got "
+ + Arrays.toString(got),
+ Arrays.equals(tc.bits, got));
+ }
+ for (BitPackingTestCase tc : testCases) {
+ long got = packBits(tc.bits);
+ assertEquals(
+ "packBits("
+ + Arrays.toString(tc.bits)
+ + "): expected "
+ + tc.packedBits
+ + " but got "
+ + got,
+ tc.packedBits,
+ got);
+ }
+
+ long[] moreTestCases = {
+ 0, 1, -1, 23895, -908235, Long.MAX_VALUE, Long.MIN_VALUE, new Random().nextLong(),
+ };
+ for (long l : moreTestCases) {
+ assertEquals(l, packBits(unpackBits(l)));
+ }
}
static byte[] bytes(int b1, int b2, int b3, int b4) {
@@ -133,4 +184,18 @@ public class BitUtilsTest {
static byte b(int i) {
return (byte) i;
}
+
+ static int[] ints(int... array) {
+ return array;
+ }
+
+ static class BitPackingTestCase {
+ final int[] bits;
+ final long packedBits;
+
+ BitPackingTestCase(long packedBits, int[] bits) {
+ this.bits = bits;
+ this.packedBits = packedBits;
+ }
+ }
}
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 7ea9bcf36f91..c4e353bdca55 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -96,6 +96,7 @@ import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.startsWith;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.atLeastOnce;
@@ -163,6 +164,7 @@ import android.net.ProxyInfo;
import android.net.ResolverParamsParcel;
import android.net.RouteInfo;
import android.net.SocketKeepalive;
+import android.net.TetheringManager;
import android.net.UidRange;
import android.net.metrics.IpConnectivityLog;
import android.net.shared.NetworkMonitorUtils;
@@ -197,6 +199,7 @@ import androidx.test.filters.FlakyTest;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
+import com.android.internal.app.IBatteryStats;
import com.android.internal.net.VpnConfig;
import com.android.internal.net.VpnInfo;
import com.android.internal.util.ArrayUtils;
@@ -210,7 +213,6 @@ import com.android.server.connectivity.MockableSystemProperties;
import com.android.server.connectivity.Nat464Xlat;
import com.android.server.connectivity.NetworkNotificationManager.NotificationType;
import com.android.server.connectivity.ProxyTracker;
-import com.android.server.connectivity.Tethering;
import com.android.server.connectivity.Vpn;
import com.android.server.net.NetworkPinner;
import com.android.server.net.NetworkPolicyManagerInternal;
@@ -305,6 +307,7 @@ public class ConnectivityServiceTest {
@Mock DefaultNetworkMetrics mDefaultNetworkMetrics;
@Mock INetworkManagementService mNetworkManagementService;
@Mock INetworkStatsService mStatsService;
+ @Mock IBatteryStats mBatteryStatsService;
@Mock INetworkPolicyManager mNpm;
@Mock IDnsResolver mMockDnsResolver;
@Mock INetd mMockNetd;
@@ -1130,11 +1133,12 @@ public class ConnectivityServiceTest {
doReturn(new TestNetIdManager()).when(deps).makeNetIdManager();
doReturn(mNetworkStack).when(deps).getNetworkStack();
doReturn(systemProperties).when(deps).getSystemProperties();
- doReturn(mock(Tethering.class)).when(deps).makeTethering(any(), any(), any(), any(), any());
+ doReturn(mock(TetheringManager.class)).when(deps).getTetheringManager();
doReturn(mock(ProxyTracker.class)).when(deps).makeProxyTracker(any(), any());
doReturn(mMetricsService).when(deps).getMetricsLogger();
doReturn(true).when(deps).queryUserAccess(anyInt(), anyInt());
doReturn(mIpConnectivityMetrics).when(deps).getIpConnectivityMetrics();
+ doReturn(mBatteryStatsService).when(deps).getBatteryStatsService();
doReturn(true).when(deps).hasService(Context.ETHERNET_SERVICE);
doAnswer(inv -> {
mPolicyTracker = new WrappedMultinetworkPolicyTracker(
@@ -5640,6 +5644,36 @@ public class ConnectivityServiceTest {
mCm.unregisterNetworkCallback(defaultCallback);
}
+ @Test
+ public final void testBatteryStatsNetworkType() throws Exception {
+ final LinkProperties cellLp = new LinkProperties();
+ cellLp.setInterfaceName("cell0");
+ mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, cellLp);
+ mCellNetworkAgent.connect(true);
+ waitForIdle();
+ verify(mBatteryStatsService).noteNetworkInterfaceType(cellLp.getInterfaceName(),
+ TYPE_MOBILE);
+ reset(mBatteryStatsService);
+
+ final LinkProperties wifiLp = new LinkProperties();
+ wifiLp.setInterfaceName("wifi0");
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, wifiLp);
+ mWiFiNetworkAgent.connect(true);
+ waitForIdle();
+ verify(mBatteryStatsService).noteNetworkInterfaceType(wifiLp.getInterfaceName(),
+ TYPE_WIFI);
+ reset(mBatteryStatsService);
+
+ mCellNetworkAgent.disconnect();
+
+ cellLp.setInterfaceName("wifi0");
+ mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, cellLp);
+ mCellNetworkAgent.connect(true);
+ waitForIdle();
+ verify(mBatteryStatsService).noteNetworkInterfaceType(cellLp.getInterfaceName(),
+ TYPE_MOBILE);
+ }
+
/**
* Make simulated InterfaceConfig for Nat464Xlat to query clat lower layer info.
*/
@@ -5680,25 +5714,28 @@ public class ConnectivityServiceTest {
mCm.registerNetworkCallback(networkRequest, networkCallback);
// Prepare ipv6 only link properties.
- mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- final int cellNetId = mCellNetworkAgent.getNetwork().netId;
final LinkProperties cellLp = new LinkProperties();
cellLp.setInterfaceName(MOBILE_IFNAME);
cellLp.addLinkAddress(myIpv6);
cellLp.addRoute(new RouteInfo((IpPrefix) null, myIpv6.getAddress(), MOBILE_IFNAME));
cellLp.addRoute(new RouteInfo(myIpv6, null, MOBILE_IFNAME));
+ mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, cellLp);
reset(mNetworkManagementService);
reset(mMockDnsResolver);
reset(mMockNetd);
+ reset(mBatteryStatsService);
when(mNetworkManagementService.getInterfaceConfig(CLAT_PREFIX + MOBILE_IFNAME))
.thenReturn(getClatInterfaceConfig(myIpv4));
// Connect with ipv6 link properties. Expect prefix discovery to be started.
- mCellNetworkAgent.sendLinkProperties(cellLp);
mCellNetworkAgent.connect(true);
+ final int cellNetId = mCellNetworkAgent.getNetwork().netId;
+ waitForIdle();
verify(mMockNetd, times(1)).networkCreatePhysical(eq(cellNetId), anyInt());
verify(mMockDnsResolver, times(1)).createNetworkCache(eq(cellNetId));
+ verify(mBatteryStatsService).noteNetworkInterfaceType(cellLp.getInterfaceName(),
+ TYPE_MOBILE);
networkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
verify(mMockDnsResolver, times(1)).startPrefix64Discovery(cellNetId);
@@ -5714,6 +5751,11 @@ public class ConnectivityServiceTest {
verify(mMockDnsResolver, times(1)).stopPrefix64Discovery(cellNetId);
verify(mMockDnsResolver, atLeastOnce()).setResolverConfiguration(any());
+ // Make sure BatteryStats was not told about any v4- interfaces, as none should have
+ // come online yet.
+ waitForIdle();
+ verify(mBatteryStatsService, never()).noteNetworkInterfaceType(startsWith("v4-"), anyInt());
+
verifyNoMoreInteractions(mMockNetd);
verifyNoMoreInteractions(mMockDnsResolver);
reset(mMockNetd);
@@ -5760,6 +5802,11 @@ public class ConnectivityServiceTest {
assertEquals(1, resolvrParams.servers.length);
assertTrue(ArrayUtils.contains(resolvrParams.servers, "8.8.8.8"));
+ for (final LinkProperties stackedLp : stackedLpsAfterChange) {
+ verify(mBatteryStatsService).noteNetworkInterfaceType(stackedLp.getInterfaceName(),
+ TYPE_MOBILE);
+ }
+
// Add ipv4 address, expect that clatd and prefix discovery are stopped and stacked
// linkproperties are cleaned up.
cellLp.addLinkAddress(myIpv4);
diff --git a/tools/aapt2/cmd/Link.h b/tools/aapt2/cmd/Link.h
index 56bff8fe0fe8..aea24329c431 100644
--- a/tools/aapt2/cmd/Link.h
+++ b/tools/aapt2/cmd/Link.h
@@ -264,8 +264,8 @@ class LinkCommand : public Command {
&options_.keep_raw_values);
AddOptionalFlag("--no-compress-regex",
"Do not compress extensions matching the regular expression. Remember to\n"
- " use the '$' symbol for end of line. Uses a non case-sensitive\n"
- " ECMAScript regular expression grammar.",
+ "use the '$' symbol for end of line. Uses a case-sensitive ECMAScript"
+ "regular expression grammar.",
&no_compress_regex);
AddOptionalSwitch("--warn-manifest-validation",
"Treat manifest validation errors as warnings.",
diff --git a/tools/aapt2/cmd/Util.cpp b/tools/aapt2/cmd/Util.cpp
index e2c65ba74271..7214f1a68d2c 100644
--- a/tools/aapt2/cmd/Util.cpp
+++ b/tools/aapt2/cmd/Util.cpp
@@ -436,9 +436,9 @@ void SetLongVersionCode(xml::Element* manifest, uint64_t version) {
}
std::regex GetRegularExpression(const std::string &input) {
- // Standard ECMAScript grammar plus case insensitive.
+ // Standard ECMAScript grammar.
std::regex case_insensitive(
- input, std::regex_constants::icase | std::regex_constants::ECMAScript);
+ input, std::regex_constants::ECMAScript);
return case_insensitive;
}
diff --git a/tools/aapt2/cmd/Util_test.cpp b/tools/aapt2/cmd/Util_test.cpp
index 7e492610b658..ac1f981d753c 100644
--- a/tools/aapt2/cmd/Util_test.cpp
+++ b/tools/aapt2/cmd/Util_test.cpp
@@ -383,7 +383,7 @@ TEST (UtilTest, AdjustSplitConstraintsForMinSdk) {
EXPECT_NE(*adjusted_contraints[1].configs.begin(), ConfigDescription::DefaultConfig());
}
-TEST(UtilTest, RegularExperssions) {
+TEST (UtilTest, RegularExperssionsSimple) {
std::string valid(".bc$");
std::regex expression = GetRegularExpression(valid);
EXPECT_TRUE(std::regex_search("file.abc", expression));
@@ -391,4 +391,24 @@ TEST(UtilTest, RegularExperssions) {
EXPECT_FALSE(std::regex_search("abc.zip", expression));
}
+TEST (UtilTest, RegularExpressionComplex) {
+ std::string valid("\\.(d|D)(e|E)(x|X)$");
+ std::regex expression = GetRegularExpression(valid);
+ EXPECT_TRUE(std::regex_search("file.dex", expression));
+ EXPECT_TRUE(std::regex_search("file.DEX", expression));
+ EXPECT_TRUE(std::regex_search("file.dEx", expression));
+ EXPECT_FALSE(std::regex_search("file.dexx", expression));
+ EXPECT_FALSE(std::regex_search("dex.file", expression));
+ EXPECT_FALSE(std::regex_search("file.adex", expression));
+}
+
+TEST (UtilTest, RegularExpressionNonEnglish) {
+ std::string valid("\\.(k|K)(o|O)(ń|Ń)(c|C)(ó|Ó)(w|W)(k|K)(a|A)$");
+ std::regex expression = GetRegularExpression(valid);
+ EXPECT_TRUE(std::regex_search("file.końcówka", expression));
+ EXPECT_TRUE(std::regex_search("file.KOŃCÓWKA", expression));
+ EXPECT_TRUE(std::regex_search("file.kOńcÓwkA", expression));
+ EXPECT_FALSE(std::regex_search("file.koncowka", expression));
+}
+
} // namespace aapt
diff --git a/tools/aapt2/java/JavaClassGenerator.cpp b/tools/aapt2/java/JavaClassGenerator.cpp
index 31d205e1b9c9..6c3bcf039be1 100644
--- a/tools/aapt2/java/JavaClassGenerator.cpp
+++ b/tools/aapt2/java/JavaClassGenerator.cpp
@@ -428,7 +428,7 @@ void JavaClassGenerator::ProcessStyleable(const ResourceNameRef& name, const Res
out_rewrite_method->AppendStatement(
StringPrintf(" if ((styleable.%s[i] & 0xff000000) == 0) {", array_field_name.data()));
out_rewrite_method->AppendStatement(
- StringPrintf(" styleable.%s[i] = (styleable.%s[i] & 0x00ffffff) | (p << 24);",
+ StringPrintf(" styleable.%s[i] = (styleable.%s[i] & 0x00ffffff) | packageIdBits;",
array_field_name.data(), array_field_name.data()));
out_rewrite_method->AppendStatement(" }");
out_rewrite_method->AppendStatement("}");
@@ -487,9 +487,9 @@ void JavaClassGenerator::ProcessResource(const ResourceNameRef& name, const Reso
if (out_rewrite_method != nullptr) {
const StringPiece& type_str = to_string(name.type);
- out_rewrite_method->AppendStatement(StringPrintf("%s.%s = (%s.%s & 0x00ffffff) | (p << 24);",
- type_str.data(), field_name.data(),
- type_str.data(), field_name.data()));
+ out_rewrite_method->AppendStatement(
+ StringPrintf("%s.%s = (%s.%s & 0x00ffffff) | packageIdBits;", type_str.data(),
+ field_name.data(), type_str.data(), field_name.data()));
}
}
@@ -599,6 +599,7 @@ bool JavaClassGenerator::Generate(const StringPiece& package_name_to_generate,
rewrite_method->AppendStatement(
StringPrintf("%s.R.onResourcesLoaded(p);", package_to_callback.data()));
}
+ rewrite_method->AppendStatement("final int packageIdBits = p << 24;");
}
for (const auto& package : table_->packages) {
diff --git a/tools/aapt2/java/JavaClassGenerator_test.cpp b/tools/aapt2/java/JavaClassGenerator_test.cpp
index 4f51fc48c80e..1e1fe4740c6b 100644
--- a/tools/aapt2/java/JavaClassGenerator_test.cpp
+++ b/tools/aapt2/java/JavaClassGenerator_test.cpp
@@ -522,9 +522,15 @@ TEST(JavaClassGeneratorTest, GenerateOnResourcesLoadedCallbackForSharedLibrary)
ASSERT_TRUE(generator.Generate("android", &out));
out.Flush();
- EXPECT_THAT(output, HasSubstr("void onResourcesLoaded"));
- EXPECT_THAT(output, HasSubstr("com.foo.R.onResourcesLoaded"));
- EXPECT_THAT(output, HasSubstr("com.boo.R.onResourcesLoaded"));
+ EXPECT_THAT(output, HasSubstr(
+ R"( public static void onResourcesLoaded(int p) {
+ com.foo.R.onResourcesLoaded(p);
+ com.boo.R.onResourcesLoaded(p);
+ final int packageIdBits = p << 24;
+ attr.foo = (attr.foo & 0x00ffffff) | packageIdBits;
+ id.foo = (id.foo & 0x00ffffff) | packageIdBits;
+ style.foo = (style.foo & 0x00ffffff) | packageIdBits;
+ })"));
}
TEST(JavaClassGeneratorTest, OnlyGenerateRText) {
diff --git a/wifi/java/android/net/wifi/SynchronousExecutor.java b/wifi/java/android/net/wifi/SynchronousExecutor.java
new file mode 100644
index 000000000000..9926b1b5f7dc
--- /dev/null
+++ b/wifi/java/android/net/wifi/SynchronousExecutor.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.net.wifi;
+
+import java.util.concurrent.Executor;
+
+/**
+ * An executor implementation that runs synchronously on the current thread.
+ * @hide
+ */
+public class SynchronousExecutor implements Executor {
+ @Override
+ public void execute(Runnable r) {
+ r.run();
+ }
+}
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index dfdc075043f6..d068fc681ae7 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -39,7 +39,6 @@ import android.text.TextUtils;
import android.util.BackupUtils;
import android.util.Log;
import android.util.SparseArray;
-import android.util.TimeUtils;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
@@ -49,6 +48,7 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Arrays;
import java.util.BitSet;
+import java.util.Calendar;
import java.util.HashMap;
/**
@@ -1984,8 +1984,8 @@ public class WifiConfiguration implements Parcelable {
public boolean isLinked(WifiConfiguration config) {
if (config != null) {
if (config.linkedConfigurations != null && linkedConfigurations != null) {
- if (config.linkedConfigurations.get(configKey()) != null
- && linkedConfigurations.get(config.configKey()) != null) {
+ if (config.linkedConfigurations.get(getKey()) != null
+ && linkedConfigurations.get(config.getKey()) != null) {
return true;
}
}
@@ -2006,6 +2006,16 @@ public class WifiConfiguration implements Parcelable {
&& enterpriseConfig.getEapMethod() != WifiEnterpriseConfig.Eap.NONE;
}
+ private static String logTimeOfDay(long millis) {
+ Calendar c = Calendar.getInstance();
+ if (millis >= 0) {
+ c.setTimeInMillis(millis);
+ return String.format("%tm-%td %tH:%tM:%tS.%tL", c, c, c, c, c, c);
+ } else {
+ return Long.toString(millis);
+ }
+ }
+
@Override
public String toString() {
StringBuilder sbuf = new StringBuilder();
@@ -2042,7 +2052,7 @@ public class WifiConfiguration implements Parcelable {
if (mNetworkSelectionStatus.getConnectChoice() != null) {
sbuf.append(" connect choice: ").append(mNetworkSelectionStatus.getConnectChoice());
sbuf.append(" connect choice set time: ")
- .append(TimeUtils.logTimeOfDay(
+ .append(logTimeOfDay(
mNetworkSelectionStatus.getConnectChoiceTimestamp()));
}
sbuf.append(" hasEverConnected: ")
@@ -2081,7 +2091,7 @@ public class WifiConfiguration implements Parcelable {
sbuf.append(" mRandomizedMacAddress: ").append(mRandomizedMacAddress).append("\n");
sbuf.append(" randomizedMacExpirationTimeMs: ")
.append(randomizedMacExpirationTimeMs == 0 ? "<none>"
- : TimeUtils.logTimeOfDay(randomizedMacExpirationTimeMs)).append("\n");
+ : logTimeOfDay(randomizedMacExpirationTimeMs)).append("\n");
sbuf.append(" KeyMgmt:");
for (int k = 0; k < this.allowedKeyManagement.size(); k++) {
if (this.allowedKeyManagement.get(k)) {
@@ -2205,7 +2215,7 @@ public class WifiConfiguration implements Parcelable {
if (this.lastConnected != 0) {
sbuf.append('\n');
- sbuf.append("lastConnected: ").append(TimeUtils.logTimeOfDay(this.lastConnected));
+ sbuf.append("lastConnected: ").append(logTimeOfDay(this.lastConnected));
sbuf.append(" ");
}
sbuf.append('\n');
@@ -2344,31 +2354,18 @@ public class WifiConfiguration implements Parcelable {
return KeyMgmt.NONE;
}
- /* @hide
- * Cache the config key, this seems useful as a speed up since a lot of
- * lookups in the config store are done and based on this key.
- */
- String mCachedConfigKey;
-
- /** @hide
- * return the string used to calculate the hash in WifiConfigStore
- * and uniquely identify this WifiConfiguration
+ /**
+ * Return a String that can be used to uniquely identify this WifiConfiguration.
+ * <br />
+ * Note: Do not persist this value! This value is not guaranteed to remain backwards compatible.
*/
- public String configKey(boolean allowCached) {
- String key;
- if (allowCached && mCachedConfigKey != null) {
- key = mCachedConfigKey;
- } else if (providerFriendlyName != null) {
- key = FQDN + KeyMgmt.strings[KeyMgmt.WPA_EAP];
- if (!shared) {
- key += "-" + Integer.toString(UserHandle.getUserId(creatorUid));
- }
- } else {
- key = getSsidAndSecurityTypeString();
- if (!shared) {
- key += "-" + Integer.toString(UserHandle.getUserId(creatorUid));
- }
- mCachedConfigKey = key;
+ @NonNull
+ public String getKey() {
+ String key = providerFriendlyName == null
+ ? getSsidAndSecurityTypeString()
+ : FQDN + KeyMgmt.strings[KeyMgmt.WPA_EAP];
+ if (!shared) {
+ key += "-" + UserHandle.getUserHandleForUid(creatorUid).getIdentifier();
}
return key;
}
@@ -2397,13 +2394,6 @@ public class WifiConfiguration implements Parcelable {
return key;
}
- /** @hide
- * get configKey, force calculating the config string
- */
- public String configKey() {
- return configKey(false);
- }
-
/** @hide */
@UnsupportedAppUsage
public IpConfiguration getIpConfiguration() {
@@ -2446,13 +2436,13 @@ public class WifiConfiguration implements Parcelable {
@NonNull
@SystemApi
public IpConfiguration.IpAssignment getIpAssignment() {
- return mIpConfiguration.ipAssignment;
+ return mIpConfiguration.getIpAssignment();
}
/** @hide */
@UnsupportedAppUsage
public void setIpAssignment(IpConfiguration.IpAssignment ipAssignment) {
- mIpConfiguration.ipAssignment = ipAssignment;
+ mIpConfiguration.setIpAssignment(ipAssignment);
}
/**
@@ -2462,13 +2452,13 @@ public class WifiConfiguration implements Parcelable {
@NonNull
@SystemApi
public IpConfiguration.ProxySettings getProxySettings() {
- return mIpConfiguration.proxySettings;
+ return mIpConfiguration.getProxySettings();
}
/** @hide */
@UnsupportedAppUsage
public void setProxySettings(IpConfiguration.ProxySettings proxySettings) {
- mIpConfiguration.proxySettings = proxySettings;
+ mIpConfiguration.setProxySettings(proxySettings);
}
/**
@@ -2477,10 +2467,10 @@ public class WifiConfiguration implements Parcelable {
* WifiConfiguration, or {@code null} if no proxy is specified.
*/
public ProxyInfo getHttpProxy() {
- if (mIpConfiguration.proxySettings == IpConfiguration.ProxySettings.NONE) {
+ if (mIpConfiguration.getProxySettings() == IpConfiguration.ProxySettings.NONE) {
return null;
}
- return new ProxyInfo(mIpConfiguration.httpProxy);
+ return new ProxyInfo(mIpConfiguration.getHttpProxy());
}
/**
@@ -2505,12 +2495,12 @@ public class WifiConfiguration implements Parcelable {
if (!Uri.EMPTY.equals(httpProxy.getPacFileUrl())) {
proxySettingCopy = IpConfiguration.ProxySettings.PAC;
// Construct a new PAC URL Proxy
- httpProxyCopy = new ProxyInfo(httpProxy.getPacFileUrl(), httpProxy.getPort());
+ httpProxyCopy = ProxyInfo.buildPacProxy(httpProxy.getPacFileUrl(), httpProxy.getPort());
} else {
proxySettingCopy = IpConfiguration.ProxySettings.STATIC;
// Construct a new HTTP Proxy
- httpProxyCopy = new ProxyInfo(httpProxy.getHost(), httpProxy.getPort(),
- httpProxy.getExclusionListAsString());
+ httpProxyCopy = ProxyInfo.buildDirectProxy(httpProxy.getHost(), httpProxy.getPort(),
+ Arrays.asList(httpProxy.getExclusionList()));
}
if (!httpProxyCopy.isValid()) {
throw new IllegalArgumentException("Invalid ProxyInfo: " + httpProxyCopy.toString());
@@ -2525,8 +2515,8 @@ public class WifiConfiguration implements Parcelable {
*/
@SystemApi
public void setProxy(@NonNull ProxySettings settings, @NonNull ProxyInfo proxy) {
- mIpConfiguration.proxySettings = settings;
- mIpConfiguration.httpProxy = proxy;
+ mIpConfiguration.setProxySettings(settings);
+ mIpConfiguration.setHttpProxy(proxy);
}
/** Implement the Parcelable interface {@hide} */
@@ -2589,7 +2579,6 @@ public class WifiConfiguration implements Parcelable {
linkedConfigurations = new HashMap<String, Integer>();
linkedConfigurations.putAll(source.linkedConfigurations);
}
- mCachedConfigKey = null; //force null configKey
validatedInternetAccess = source.validatedInternetAccess;
isLegacyPasspointConfig = source.isLegacyPasspointConfig;
ephemeral = source.ephemeral;
diff --git a/wifi/java/android/net/wifi/WifiFrameworkInitializer.java b/wifi/java/android/net/wifi/WifiFrameworkInitializer.java
index 775043ae3291..002820b1bcc8 100644
--- a/wifi/java/android/net/wifi/WifiFrameworkInitializer.java
+++ b/wifi/java/android/net/wifi/WifiFrameworkInitializer.java
@@ -72,7 +72,10 @@ public class WifiFrameworkInitializer {
SystemServiceRegistry.registerContextAwareService(
Context.WIFI_SERVICE,
WifiManager.class,
- context -> new WifiManager(context, getInstanceLooper())
+ (context, serviceBinder) -> {
+ IWifiManager service = IWifiManager.Stub.asInterface(serviceBinder);
+ return new WifiManager(context, service, getInstanceLooper());
+ }
);
SystemServiceRegistry.registerStaticService(
Context.WIFI_P2P_SERVICE,
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 2a0211b77450..bf609d765502 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -36,21 +36,17 @@ import android.content.pm.ParceledListSlice;
import android.net.ConnectivityManager;
import android.net.DhcpInfo;
import android.net.Network;
-import android.net.NetworkCapabilities;
-import android.net.NetworkRequest;
import android.net.NetworkStack;
import android.net.wifi.hotspot2.IProvisioningCallback;
import android.net.wifi.hotspot2.OsuProvider;
import android.net.wifi.hotspot2.PasspointConfiguration;
import android.net.wifi.hotspot2.ProvisioningCallback;
import android.os.Binder;
-import android.os.Build;
import android.os.Handler;
import android.os.HandlerExecutor;
import android.os.IBinder;
import android.os.Looper;
import android.os.RemoteException;
-import android.os.ServiceManager;
import android.os.WorkSource;
import android.text.TextUtils;
import android.util.Log;
@@ -58,8 +54,6 @@ import android.util.Pair;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.ArrayUtils;
-import com.android.server.net.NetworkPinner;
import dalvik.system.CloseGuard;
@@ -69,6 +63,7 @@ import java.lang.ref.WeakReference;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.Collections;
+import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@@ -1211,46 +1206,24 @@ public class WifiManager {
/**
* Create a new WifiManager instance.
* Applications will almost always want to use
- * {@link android.content.Context#getSystemService Context.getSystemService()} to retrieve
+ * {@link android.content.Context#getSystemService Context.getSystemService} to retrieve
* the standard {@link android.content.Context#WIFI_SERVICE Context.WIFI_SERVICE}.
*
* @param context the application context
+ * @param service the Binder interface
* @param looper the Looper used to deliver callbacks
- *
- * @hide
+ * @hide - hide this because it takes in a parameter of type IWifiManager, which
+ * is a system private class.
*/
- public WifiManager(@NonNull Context context, @NonNull Looper looper) {
+ public WifiManager(@NonNull Context context, @NonNull IWifiManager service,
+ @NonNull Looper looper) {
mContext = context;
+ mService = service;
mLooper = looper;
mTargetSdkVersion = context.getApplicationInfo().targetSdkVersion;
- }
-
- /**
- * This is used only for unit testing.
- * @hide
- */
- @VisibleForTesting
- public WifiManager(Context context, IWifiManager service, Looper looper) {
- this(context, looper);
- mService = service;
updateVerboseLoggingEnabledFromService();
}
- private IWifiManager getIWifiManager() {
- if (mService == null) {
- synchronized (this) {
- mService = IWifiManager.Stub.asInterface(
- ServiceManager.getService(Context.WIFI_SERVICE));
- if (mService != null) {
- updateVerboseLoggingEnabledFromService();
- } else {
- Log.e(TAG, "Wifi Service not running yet, ignoring WifiManager API call");
- }
- }
- }
- return mService;
- }
-
/**
* Return a list of all the networks configured for the current foreground
* user.
@@ -1290,10 +1263,8 @@ public class WifiManager {
@RequiresPermission(allOf = {ACCESS_FINE_LOCATION, ACCESS_WIFI_STATE})
public List<WifiConfiguration> getConfiguredNetworks() {
try {
- IWifiManager iWifiManager = getIWifiManager();
- if (iWifiManager == null) return Collections.emptyList();
ParceledListSlice<WifiConfiguration> parceledList =
- iWifiManager.getConfiguredNetworks(mContext.getOpPackageName(),
+ mService.getConfiguredNetworks(mContext.getOpPackageName(),
mContext.getFeatureId());
if (parceledList == null) {
return Collections.emptyList();
@@ -1309,10 +1280,8 @@ public class WifiManager {
@RequiresPermission(allOf = {ACCESS_FINE_LOCATION, ACCESS_WIFI_STATE, READ_WIFI_CREDENTIAL})
public List<WifiConfiguration> getPrivilegedConfiguredNetworks() {
try {
- IWifiManager iWifiManager = getIWifiManager();
- if (iWifiManager == null) return Collections.emptyList();
ParceledListSlice<WifiConfiguration> parceledList =
- iWifiManager.getPrivilegedConfiguredNetworks(mContext.getOpPackageName(),
+ mService.getPrivilegedConfiguredNetworks(mContext.getOpPackageName(),
mContext.getFeatureId());
if (parceledList == null) {
return Collections.emptyList();
@@ -1344,16 +1313,14 @@ public class WifiManager {
@NonNull List<ScanResult> scanResults) {
List<Pair<WifiConfiguration, Map<Integer, List<ScanResult>>>> configs = new ArrayList<>();
try {
- IWifiManager iWifiManager = getIWifiManager();
- if (iWifiManager == null) return Collections.emptyList();
Map<String, Map<Integer, List<ScanResult>>> results =
- iWifiManager.getAllMatchingFqdnsForScanResults(
+ mService.getAllMatchingFqdnsForScanResults(
scanResults);
if (results.isEmpty()) {
return configs;
}
List<WifiConfiguration> wifiConfigurations =
- iWifiManager.getWifiConfigsForPasspointProfiles(
+ mService.getWifiConfigsForPasspointProfiles(
new ArrayList<>(results.keySet()));
for (WifiConfiguration configuration : wifiConfigurations) {
Map<Integer, List<ScanResult>> scanResultsPerNetworkType = results.get(
@@ -1388,12 +1355,10 @@ public class WifiManager {
public Map<OsuProvider, List<ScanResult>> getMatchingOsuProviders(
@Nullable List<ScanResult> scanResults) {
if (scanResults == null) {
- return Collections.emptyMap();
+ return new HashMap<>();
}
try {
- IWifiManager iWifiManager = getIWifiManager();
- if (iWifiManager == null) return Collections.emptyMap();
- return iWifiManager.getMatchingOsuProviders(scanResults);
+ return mService.getMatchingOsuProviders(scanResults);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1420,9 +1385,7 @@ public class WifiManager {
public Map<OsuProvider, PasspointConfiguration> getMatchingPasspointConfigsForOsuProviders(
@NonNull Set<OsuProvider> osuProviders) {
try {
- IWifiManager iWifiManager = getIWifiManager();
- if (iWifiManager == null) return Collections.emptyMap();
- return iWifiManager.getMatchingPasspointConfigsForOsuProviders(
+ return mService.getMatchingPasspointConfigsForOsuProviders(
new ArrayList<>(osuProviders));
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -1507,9 +1470,7 @@ public class WifiManager {
*/
private int addOrUpdateNetwork(WifiConfiguration config) {
try {
- IWifiManager iWifiManager = getIWifiManager();
- if (iWifiManager == null) return -1;
- return iWifiManager.addOrUpdateNetwork(config, mContext.getOpPackageName());
+ return mService.addOrUpdateNetwork(config, mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1756,11 +1717,7 @@ public class WifiManager {
Binder binder = new Binder();
try {
- IWifiManager iWifiManager = getIWifiManager();
- if (iWifiManager == null) {
- throw new RemoteException("Wifi service is not running");
- }
- iWifiManager.registerNetworkRequestMatchCallback(
+ mService.registerNetworkRequestMatchCallback(
binder, new NetworkRequestMatchCallbackProxy(executor, callback),
callback.hashCode());
} catch (RemoteException e) {
@@ -1787,11 +1744,7 @@ public class WifiManager {
Log.v(TAG, "unregisterNetworkRequestMatchCallback: callback=" + callback);
try {
- IWifiManager iWifiManager = getIWifiManager();
- if (iWifiManager == null) {
- throw new RemoteException("Wifi service is not running");
- }
- iWifiManager.unregisterNetworkRequestMatchCallback(callback.hashCode());
+ mService.unregisterNetworkRequestMatchCallback(callback.hashCode());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1824,9 +1777,7 @@ public class WifiManager {
public @NetworkSuggestionsStatusCode int addNetworkSuggestions(
@NonNull List<WifiNetworkSuggestion> networkSuggestions) {
try {
- IWifiManager iWifiManager = getIWifiManager();
- if (iWifiManager == null) return STATUS_NETWORK_SUGGESTIONS_ERROR_INTERNAL;
- return iWifiManager.addNetworkSuggestions(
+ return mService.addNetworkSuggestions(
networkSuggestions, mContext.getOpPackageName(), mContext.getFeatureId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -1835,8 +1786,9 @@ public class WifiManager {
/**
* Remove some or all of the network suggestions that were previously provided by the app.
- * If the current network is a suggestion being removed and if it was only provided by this app
- * and is not a saved network then the framework will immediately disconnect.
+ * If one of the suggestions being removed was used to establish connection to the current
+ * network, then the device will immediately disconnect from that network.
+ *
* See {@link WifiNetworkSuggestion} for a detailed explanation of the parameters.
* See {@link WifiNetworkSuggestion#equals(Object)} for the equivalence evaluation used.
*
@@ -1850,9 +1802,7 @@ public class WifiManager {
public @NetworkSuggestionsStatusCode int removeNetworkSuggestions(
@NonNull List<WifiNetworkSuggestion> networkSuggestions) {
try {
- IWifiManager iWifiManager = getIWifiManager();
- if (iWifiManager == null) return STATUS_NETWORK_SUGGESTIONS_ERROR_INTERNAL;
- return iWifiManager.removeNetworkSuggestions(
+ return mService.removeNetworkSuggestions(
networkSuggestions, mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -1868,9 +1818,7 @@ public class WifiManager {
@RequiresPermission(ACCESS_WIFI_STATE)
public @NonNull List<WifiNetworkSuggestion> getNetworkSuggestions() {
try {
- IWifiManager iWifiManager = getIWifiManager();
- if (iWifiManager == null) return Collections.emptyList();
- return iWifiManager.getNetworkSuggestions(mContext.getOpPackageName());
+ return mService.getNetworkSuggestions(mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
@@ -1900,13 +1848,7 @@ public class WifiManager {
*/
public void addOrUpdatePasspointConfiguration(PasspointConfiguration config) {
try {
- IWifiManager iWifiManager = getIWifiManager();
- if (iWifiManager == null) {
- if (config == null) return;
- throw new RemoteException("Wifi service is not running");
- }
- if (!iWifiManager.addOrUpdatePasspointConfiguration(
- config, mContext.getOpPackageName())) {
+ if (!mService.addOrUpdatePasspointConfiguration(config, mContext.getOpPackageName())) {
throw new IllegalArgumentException();
}
} catch (RemoteException e) {
@@ -1930,13 +1872,7 @@ public class WifiManager {
})
public void removePasspointConfiguration(String fqdn) {
try {
- IWifiManager iWifiManager = getIWifiManager();
- if (iWifiManager == null) {
- if (TextUtils.isEmpty(fqdn)) return;
- throw new RemoteException("Wifi service is not running");
- }
- if (!iWifiManager.removePasspointConfiguration(
- fqdn, mContext.getOpPackageName())) {
+ if (!mService.removePasspointConfiguration(fqdn, mContext.getOpPackageName())) {
throw new IllegalArgumentException();
}
} catch (RemoteException e) {
@@ -1959,9 +1895,7 @@ public class WifiManager {
})
public List<PasspointConfiguration> getPasspointConfigurations() {
try {
- IWifiManager iWifiManager = getIWifiManager();
- if (iWifiManager == null) Collections.emptyList();
- return iWifiManager.getPasspointConfigurations(mContext.getOpPackageName());
+ return mService.getPasspointConfigurations(mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1981,12 +1915,7 @@ public class WifiManager {
*/
public void queryPasspointIcon(long bssid, String fileName) {
try {
- IWifiManager iWifiManager = getIWifiManager();
- if (iWifiManager == null) {
- if (bssid == 0L || TextUtils.isEmpty(fileName)) return;
- throw new RemoteException("Wifi service is not running");
- }
- iWifiManager.queryPasspointIcon(bssid, fileName);
+ mService.queryPasspointIcon(bssid, fileName);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -2000,9 +1929,7 @@ public class WifiManager {
*/
public int matchProviderWithCurrentNetwork(String fqdn) {
try {
- IWifiManager iWifiManager = getIWifiManager();
- if (iWifiManager == null) return -1;
- return iWifiManager.matchProviderWithCurrentNetwork(fqdn);
+ return mService.matchProviderWithCurrentNetwork(fqdn);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -2018,11 +1945,7 @@ public class WifiManager {
*/
public void deauthenticateNetwork(long holdoff, boolean ess) {
try {
- IWifiManager iWifiManager = getIWifiManager();
- if (iWifiManager == null) {
- throw new RemoteException("Wifi service is not running");
- }
- iWifiManager.deauthenticateNetwork(holdoff, ess);
+ mService.deauthenticateNetwork(holdoff, ess);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -2052,9 +1975,7 @@ public class WifiManager {
@Deprecated
public boolean removeNetwork(int netId) {
try {
- IWifiManager iWifiManager = getIWifiManager();
- if (iWifiManager == null) return false;
- return iWifiManager.removeNetwork(netId, mContext.getOpPackageName());
+ return mService.removeNetwork(netId, mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -2097,31 +2018,11 @@ public class WifiManager {
*/
@Deprecated
public boolean enableNetwork(int netId, boolean attemptConnect) {
- final boolean pin = attemptConnect && mTargetSdkVersion < Build.VERSION_CODES.LOLLIPOP;
- if (pin) {
- NetworkRequest request = new NetworkRequest.Builder()
- .clearCapabilities()
- .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN)
- .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
- .build();
- NetworkPinner.pin(mContext, request);
- }
-
- boolean success;
try {
- IWifiManager iWifiManager = getIWifiManager();
- if (iWifiManager == null) return false;
- success = iWifiManager.enableNetwork(
- netId, attemptConnect, mContext.getOpPackageName());
+ return mService.enableNetwork(netId, attemptConnect, mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
-
- if (pin && !success) {
- NetworkPinner.unpin();
- }
-
- return success;
}
/**
@@ -2148,9 +2049,7 @@ public class WifiManager {
@Deprecated
public boolean disableNetwork(int netId) {
try {
- IWifiManager iWifiManager = getIWifiManager();
- if (iWifiManager == null) return false;
- return iWifiManager.disableNetwork(netId, mContext.getOpPackageName());
+ return mService.disableNetwork(netId, mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -2173,9 +2072,7 @@ public class WifiManager {
@Deprecated
public boolean disconnect() {
try {
- IWifiManager iWifiManager = getIWifiManager();
- if (iWifiManager == null) return false;
- return iWifiManager.disconnect(mContext.getOpPackageName());
+ return mService.disconnect(mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -2199,9 +2096,7 @@ public class WifiManager {
@Deprecated
public boolean reconnect() {
try {
- IWifiManager iWifiManager = getIWifiManager();
- if (iWifiManager == null) return false;
- return iWifiManager.reconnect(mContext.getOpPackageName());
+ return mService.reconnect(mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -2225,9 +2120,7 @@ public class WifiManager {
@Deprecated
public boolean reassociate() {
try {
- IWifiManager iWifiManager = getIWifiManager();
- if (iWifiManager == null) return false;
- return iWifiManager.reassociate(mContext.getOpPackageName());
+ return mService.reassociate(mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -2323,9 +2216,7 @@ public class WifiManager {
private long getSupportedFeatures() {
try {
- IWifiManager iWifiManager = getIWifiManager();
- if (iWifiManager == null) return 0L;
- return iWifiManager.getSupportedFeatures();
+ return mService.getSupportedFeatures();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -2482,10 +2373,8 @@ public class WifiManager {
*/
public WifiActivityEnergyInfo getControllerActivityEnergyInfo() {
try {
- IWifiManager iWifiManager = getIWifiManager();
- if (iWifiManager == null) return null;
synchronized(this) {
- return iWifiManager.reportActivityInfo();
+ return mService.reportActivityInfo();
}
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -2524,11 +2413,9 @@ public class WifiManager {
@RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS)
public boolean startScan(WorkSource workSource) {
try {
- IWifiManager iWifiManager = getIWifiManager();
- if (iWifiManager == null) return false;
String packageName = mContext.getOpPackageName();
String featureId = mContext.getFeatureId();
- return iWifiManager.startScan(packageName, featureId);
+ return mService.startScan(packageName, featureId);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -2557,9 +2444,7 @@ public class WifiManager {
*/
public WifiInfo getConnectionInfo() {
try {
- IWifiManager iWifiManager = getIWifiManager();
- if (iWifiManager == null) return null;
- return iWifiManager.getConnectionInfo(mContext.getOpPackageName(),
+ return mService.getConnectionInfo(mContext.getOpPackageName(),
mContext.getFeatureId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -2574,9 +2459,7 @@ public class WifiManager {
*/
public List<ScanResult> getScanResults() {
try {
- IWifiManager iWifiManager = getIWifiManager();
- if (iWifiManager == null) return Collections.emptyList();
- return iWifiManager.getScanResults(mContext.getOpPackageName(),
+ return mService.getScanResults(mContext.getOpPackageName(),
mContext.getFeatureId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -2596,9 +2479,7 @@ public class WifiManager {
@Deprecated
public boolean isScanAlwaysAvailable() {
try {
- IWifiManager iWifiManager = getIWifiManager();
- if (iWifiManager == null) return false;
- return iWifiManager.isScanAlwaysAvailable();
+ return mService.isScanAlwaysAvailable();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -2631,9 +2512,7 @@ public class WifiManager {
@RequiresPermission(android.Manifest.permission.CONNECTIVITY_INTERNAL)
public String getCountryCode() {
try {
- IWifiManager iWifiManager = getIWifiManager();
- if (iWifiManager == null) return null;
- return iWifiManager.getCountryCode();
+ return mService.getCountryCode();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -2648,9 +2527,7 @@ public class WifiManager {
@SystemApi
public boolean isDualBandSupported() {
try {
- IWifiManager iWifiManager = getIWifiManager();
- if (iWifiManager == null) return false;
- return iWifiManager.isDualBandSupported();
+ return mService.isDualBandSupported();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -2673,9 +2550,7 @@ public class WifiManager {
@RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
public boolean isDualModeSupported() {
try {
- IWifiManager iWifiManager = getIWifiManager();
- if (iWifiManager == null) return false;
- return iWifiManager.needs5GHzToAnyApBandConversion();
+ return mService.needs5GHzToAnyApBandConversion();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -2688,9 +2563,7 @@ public class WifiManager {
*/
public DhcpInfo getDhcpInfo() {
try {
- IWifiManager iWifiManager = getIWifiManager();
- if (iWifiManager == null) return null;
- return iWifiManager.getDhcpInfo();
+ return mService.getDhcpInfo();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -2717,9 +2590,7 @@ public class WifiManager {
@Deprecated
public boolean setWifiEnabled(boolean enabled) {
try {
- IWifiManager iWifiManager = getIWifiManager();
- if (iWifiManager == null) return false;
- return iWifiManager.setWifiEnabled(mContext.getOpPackageName(), enabled);
+ return mService.setWifiEnabled(mContext.getOpPackageName(), enabled);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -2734,9 +2605,7 @@ public class WifiManager {
*/
public int getWifiState() {
try {
- IWifiManager iWifiManager = getIWifiManager();
- if (iWifiManager == null) return WIFI_STATE_UNKNOWN;
- return iWifiManager.getWifiEnabledState();
+ return mService.getWifiEnabledState();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -2764,11 +2633,7 @@ public class WifiManager {
TxPacketCountListenerProxy listenerProxy =
new TxPacketCountListenerProxy(mLooper, listener);
try {
- IWifiManager iWifiManager = getIWifiManager();
- if (iWifiManager == null) {
- throw new RemoteException("Wifi service is not running");
- }
- iWifiManager.getTxPacketCount(mContext.getOpPackageName(), binder, listenerProxy,
+ mService.getTxPacketCount(mContext.getOpPackageName(), binder, listenerProxy,
listener.hashCode());
} catch (RemoteException e) {
listenerProxy.onFailure(ERROR);
@@ -2811,11 +2676,7 @@ public class WifiManager {
*/
public int calculateSignalLevel(int rssi) {
try {
- IWifiManager iWifiManager = getIWifiManager();
- if (iWifiManager == null) {
- throw new RemoteException("Wifi service is not running");
- }
- return iWifiManager.calculateSignalLevel(rssi);
+ return mService.calculateSignalLevel(rssi);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -2861,12 +2722,7 @@ public class WifiManager {
})
public void updateInterfaceIpState(@Nullable String ifaceName, @IfaceIpMode int mode) {
try {
- IWifiManager iWifiManager = getIWifiManager();
- if (iWifiManager == null) {
- if (TextUtils.isEmpty(ifaceName) || mode == IFACE_IP_MODE_UNSPECIFIED) return;
- throw new RemoteException("Wifi service is not running");
- }
- iWifiManager.updateInterfaceIpState(ifaceName, mode);
+ mService.updateInterfaceIpState(ifaceName, mode);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -2890,9 +2746,7 @@ public class WifiManager {
})
public boolean startSoftAp(@Nullable WifiConfiguration wifiConfig) {
try {
- IWifiManager iWifiManager = getIWifiManager();
- if (iWifiManager == null) return false;
- return iWifiManager.startSoftAp(wifiConfig);
+ return mService.startSoftAp(wifiConfig);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -2912,9 +2766,7 @@ public class WifiManager {
})
public boolean stopSoftAp() {
try {
- IWifiManager iWifiManager = getIWifiManager();
- if (iWifiManager == null) return false;
- return iWifiManager.stopSoftAp();
+ return mService.stopSoftAp();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -3032,13 +2884,9 @@ public class WifiManager {
LocalOnlyHotspotCallbackProxy proxy =
new LocalOnlyHotspotCallbackProxy(this, executor, callback);
try {
- IWifiManager iWifiManager = getIWifiManager();
- if (iWifiManager == null) {
- throw new RemoteException("Wifi service is not running");
- }
String packageName = mContext.getOpPackageName();
String featureId = mContext.getFeatureId();
- int returnCode = iWifiManager.startLocalOnlyHotspot(proxy, packageName, featureId,
+ int returnCode = mService.startLocalOnlyHotspot(proxy, packageName, featureId,
config);
if (returnCode != LocalOnlyHotspotCallback.REQUEST_REGISTERED) {
// Send message to the proxy to make sure we call back on the correct thread
@@ -3090,11 +2938,7 @@ public class WifiManager {
}
mLOHSCallbackProxy = null;
try {
- IWifiManager iWifiManager = getIWifiManager();
- if (iWifiManager == null) {
- throw new RemoteException("Wifi service is not running");
- }
- iWifiManager.stopLocalOnlyHotspot();
+ mService.stopLocalOnlyHotspot();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -3126,11 +2970,7 @@ public class WifiManager {
mLOHSObserverProxy =
new LocalOnlyHotspotObserverProxy(this, executor, observer);
try {
- IWifiManager iWifiManager = getIWifiManager();
- if (iWifiManager == null) {
- throw new RemoteException("Wifi service is not running");
- }
- iWifiManager.startWatchLocalOnlyHotspot(mLOHSObserverProxy);
+ mService.startWatchLocalOnlyHotspot(mLOHSObserverProxy);
mLOHSObserverProxy.registered();
} catch (RemoteException e) {
mLOHSObserverProxy = null;
@@ -3153,11 +2993,7 @@ public class WifiManager {
}
mLOHSObserverProxy = null;
try {
- IWifiManager iWifiManager = getIWifiManager();
- if (iWifiManager == null) {
- throw new RemoteException("Wifi service is not running");
- }
- iWifiManager.stopWatchLocalOnlyHotspot();
+ mService.stopWatchLocalOnlyHotspot();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -3177,9 +3013,7 @@ public class WifiManager {
@RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE)
public int getWifiApState() {
try {
- IWifiManager iWifiManager = getIWifiManager();
- if (iWifiManager == null) return WIFI_AP_STATE_FAILED;
- return iWifiManager.getWifiApEnabledState();
+ return mService.getWifiApEnabledState();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -3208,9 +3042,7 @@ public class WifiManager {
@RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE)
public WifiConfiguration getWifiApConfiguration() {
try {
- IWifiManager iWifiManager = getIWifiManager();
- if (iWifiManager == null) return null;
- return iWifiManager.getWifiApConfiguration();
+ return mService.getWifiApConfiguration();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -3227,10 +3059,7 @@ public class WifiManager {
@RequiresPermission(android.Manifest.permission.CHANGE_WIFI_STATE)
public boolean setWifiApConfiguration(WifiConfiguration wifiConfig) {
try {
- IWifiManager iWifiManager = getIWifiManager();
- if (iWifiManager == null) return false;
- return iWifiManager.setWifiApConfiguration(
- wifiConfig, mContext.getOpPackageName());
+ return mService.setWifiApConfiguration(wifiConfig, mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -3258,12 +3087,7 @@ public class WifiManager {
*/
public void setTdlsEnabled(InetAddress remoteIPAddress, boolean enable) {
try {
- IWifiManager iWifiManager = getIWifiManager();
- if (iWifiManager == null) {
- if (remoteIPAddress == null || !enable) return;
- throw new RemoteException("Wifi service is not running");
- }
- iWifiManager.enableTdls(remoteIPAddress.getHostAddress(), enable);
+ mService.enableTdls(remoteIPAddress.getHostAddress(), enable);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -3277,12 +3101,7 @@ public class WifiManager {
*/
public void setTdlsEnabledWithMacAddress(String remoteMacAddress, boolean enable) {
try {
- IWifiManager iWifiManager = getIWifiManager();
- if (iWifiManager == null) {
- if (TextUtils.isEmpty(remoteMacAddress) || !enable) return;
- throw new RemoteException("Wifi service is not running");
- }
- iWifiManager.enableTdlsWithMacAddress(remoteMacAddress, enable);
+ mService.enableTdlsWithMacAddress(remoteMacAddress, enable);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -3573,11 +3392,7 @@ public class WifiManager {
Binder binder = new Binder();
try {
- IWifiManager iWifiManager = getIWifiManager();
- if (iWifiManager == null) {
- throw new RemoteException("Wifi service is not running");
- }
- iWifiManager.registerSoftApCallback(
+ mService.registerSoftApCallback(
binder, new SoftApCallbackProxy(executor, callback), callback.hashCode());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -3599,11 +3414,7 @@ public class WifiManager {
Log.v(TAG, "unregisterSoftApCallback: callback=" + callback);
try {
- IWifiManager iWifiManager = getIWifiManager();
- if (iWifiManager == null) {
- throw new RemoteException("Wifi service is not running");
- }
- iWifiManager.unregisterSoftApCallback(callback.hashCode());
+ mService.unregisterSoftApCallback(callback.hashCode());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -3931,11 +3742,7 @@ public class WifiManager {
binder = new Binder();
}
try {
- IWifiManager iWifiManager = getIWifiManager();
- if (iWifiManager == null) {
- throw new RemoteException("Wifi service is not running");
- }
- iWifiManager.connect(config, networkId, binder, listenerProxy,
+ mService.connect(config, networkId, binder, listenerProxy,
listener == null ? 0 : listener.hashCode());
} catch (RemoteException e) {
if (listenerProxy != null) listenerProxy.onFailure(ERROR);
@@ -4028,11 +3835,7 @@ public class WifiManager {
binder = new Binder();
}
try {
- IWifiManager iWifiManager = getIWifiManager();
- if (iWifiManager == null) {
- throw new RemoteException("Wifi service is not running");
- }
- iWifiManager.save(config, binder, listenerProxy,
+ mService.save(config, binder, listenerProxy,
listener == null ? 0 : listener.hashCode());
} catch (RemoteException e) {
if (listenerProxy != null) listenerProxy.onFailure(ERROR);
@@ -4069,11 +3872,7 @@ public class WifiManager {
binder = new Binder();
}
try {
- IWifiManager iWifiManager = getIWifiManager();
- if (iWifiManager == null) {
- throw new RemoteException("Wifi service is not running");
- }
- iWifiManager.forget(netId, binder, listenerProxy,
+ mService.forget(netId, binder, listenerProxy,
listener == null ? 0 : listener.hashCode());
} catch (RemoteException e) {
if (listenerProxy != null) listenerProxy.onFailure(ERROR);
@@ -4126,11 +3925,7 @@ public class WifiManager {
@RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
public void allowAutojoin(int netId, boolean choice) {
try {
- IWifiManager iWifiManager = getIWifiManager();
- if (iWifiManager == null) {
- throw new RemoteException("Wifi service is not running");
- }
- iWifiManager.allowAutojoin(netId, choice);
+ mService.allowAutojoin(netId, choice);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -4153,11 +3948,7 @@ public class WifiManager {
throw new IllegalArgumentException("SSID cannot be null or empty!");
}
try {
- IWifiManager iWifiManager = getIWifiManager();
- if (iWifiManager == null) {
- throw new RemoteException("Wifi service is not running");
- }
- iWifiManager.disableEphemeralNetwork(ssid, mContext.getOpPackageName());
+ mService.disableEphemeralNetwork(ssid, mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -4245,14 +4036,10 @@ public class WifiManager {
synchronized (mBinder) {
if (mRefCounted ? (++mRefCount == 1) : (!mHeld)) {
try {
- IWifiManager iWifiManager = getIWifiManager();
- if (iWifiManager == null) {
- throw new RemoteException("Wifi service is not running");
- }
- iWifiManager.acquireWifiLock(mBinder, mLockType, mTag, mWorkSource);
+ mService.acquireWifiLock(mBinder, mLockType, mTag, mWorkSource);
synchronized (WifiManager.this) {
if (mActiveLockCount >= MAX_ACTIVE_LOCKS) {
- iWifiManager.releaseWifiLock(mBinder);
+ mService.releaseWifiLock(mBinder);
throw new UnsupportedOperationException(
"Exceeded maximum number of wifi locks");
}
@@ -4282,11 +4069,7 @@ public class WifiManager {
synchronized (mBinder) {
if (mRefCounted ? (--mRefCount == 0) : (mHeld)) {
try {
- IWifiManager iWifiManager = getIWifiManager();
- if (iWifiManager == null) {
- throw new RemoteException("Wifi service is not running");
- }
- iWifiManager.releaseWifiLock(mBinder);
+ mService.releaseWifiLock(mBinder);
synchronized (WifiManager.this) {
mActiveLockCount--;
}
@@ -4349,11 +4132,7 @@ public class WifiManager {
}
if (changed && mHeld) {
try {
- IWifiManager iWifiManager = getIWifiManager();
- if (iWifiManager == null) {
- throw new RemoteException("Wifi service is not running");
- }
- iWifiManager.updateWifiLockWorkSource(mBinder, mWorkSource);
+ mService.updateWifiLockWorkSource(mBinder, mWorkSource);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -4381,11 +4160,7 @@ public class WifiManager {
synchronized (mBinder) {
if (mHeld) {
try {
- IWifiManager iWifiManager = getIWifiManager();
- if (iWifiManager == null) {
- throw new RemoteException("Wifi service is not running");
- }
- iWifiManager.releaseWifiLock(mBinder);
+ mService.releaseWifiLock(mBinder);
synchronized (WifiManager.this) {
mActiveLockCount--;
}
@@ -4498,14 +4273,10 @@ public class WifiManager {
synchronized (mBinder) {
if (mRefCounted ? (++mRefCount == 1) : (!mHeld)) {
try {
- IWifiManager iWifiManager = getIWifiManager();
- if (iWifiManager == null) {
- throw new RemoteException("Wifi service is not running");
- }
- iWifiManager.acquireMulticastLock(mBinder, mTag);
+ mService.acquireMulticastLock(mBinder, mTag);
synchronized (WifiManager.this) {
if (mActiveLockCount >= MAX_ACTIVE_LOCKS) {
- iWifiManager.releaseMulticastLock(mTag);
+ mService.releaseMulticastLock(mTag);
throw new UnsupportedOperationException(
"Exceeded maximum number of wifi locks");
}
@@ -4547,11 +4318,7 @@ public class WifiManager {
synchronized (mBinder) {
if (mRefCounted ? (--mRefCount == 0) : (mHeld)) {
try {
- IWifiManager iWifiManager = getIWifiManager();
- if (iWifiManager == null) {
- throw new RemoteException("Wifi service is not running");
- }
- iWifiManager.releaseMulticastLock(mTag);
+ mService.releaseMulticastLock(mTag);
synchronized (WifiManager.this) {
mActiveLockCount--;
}
@@ -4628,9 +4395,7 @@ public class WifiManager {
*/
public boolean isMulticastEnabled() {
try {
- IWifiManager iWifiManager = getIWifiManager();
- if (iWifiManager == null) return false;
- return iWifiManager.isMulticastEnabled();
+ return mService.isMulticastEnabled();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -4643,9 +4408,7 @@ public class WifiManager {
@UnsupportedAppUsage
public boolean initializeMulticastFiltering() {
try {
- IWifiManager iWifiManager = getIWifiManager();
- if (iWifiManager == null) return false;
- iWifiManager.initializeMulticastFiltering();
+ mService.initializeMulticastFiltering();
return true;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -4664,12 +4427,7 @@ public class WifiManager {
@RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
public void enableVerboseLogging (int verbose) {
try {
- IWifiManager iWifiManager = getIWifiManager();
- if (iWifiManager == null) {
- if (verbose == 0) return;
- throw new RemoteException("Wifi service is not running");
- }
- iWifiManager.enableVerboseLogging(verbose);
+ mService.enableVerboseLogging(verbose);
} catch (Exception e) {
//ignore any failure here
Log.e(TAG, "enableVerboseLogging " + e.toString());
@@ -4688,9 +4446,7 @@ public class WifiManager {
@SystemApi
public int getVerboseLoggingLevel() {
try {
- IWifiManager iWifiManager = getIWifiManager();
- if (iWifiManager == null) return -1;
- return iWifiManager.getVerboseLoggingLevel();
+ return mService.getVerboseLoggingLevel();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -4706,11 +4462,7 @@ public class WifiManager {
@RequiresPermission(android.Manifest.permission.CONNECTIVITY_INTERNAL)
public void factoryReset() {
try {
- IWifiManager iWifiManager = getIWifiManager();
- if (iWifiManager == null) {
- throw new RemoteException("Wifi service is not running");
- }
- iWifiManager.factoryReset(mContext.getOpPackageName());
+ mService.factoryReset(mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -4725,9 +4477,7 @@ public class WifiManager {
@RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE)
public Network getCurrentNetwork() {
try {
- IWifiManager iWifiManager = getIWifiManager();
- if (iWifiManager == null) return null;
- return iWifiManager.getCurrentNetwork();
+ return mService.getCurrentNetwork();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -4759,12 +4509,7 @@ public class WifiManager {
*/
public void enableWifiConnectivityManager(boolean enabled) {
try {
- IWifiManager iWifiManager = getIWifiManager();
- if (iWifiManager == null) {
- if (enabled) return;
- throw new RemoteException("Wifi service is not running");
- }
- iWifiManager.enableWifiConnectivityManager(enabled);
+ mService.enableWifiConnectivityManager(enabled);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -4781,9 +4526,7 @@ public class WifiManager {
@RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
public byte[] retrieveBackupData() {
try {
- IWifiManager iWifiManager = getIWifiManager();
- if (iWifiManager == null) return new byte[0];
- return iWifiManager.retrieveBackupData();
+ return mService.retrieveBackupData();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -4798,12 +4541,7 @@ public class WifiManager {
@RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
public void restoreBackupData(@NonNull byte[] data) {
try {
- IWifiManager iWifiManager = getIWifiManager();
- if (iWifiManager == null) {
- if (ArrayUtils.isEmpty(data)) return;
- throw new RemoteException("Wifi service is not running");
- }
- iWifiManager.restoreBackupData(data);
+ mService.restoreBackupData(data);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -4824,12 +4562,7 @@ public class WifiManager {
public void restoreSupplicantBackupData(
@NonNull byte[] supplicantData, @NonNull byte[] ipConfigData) {
try {
- IWifiManager iWifiManager = getIWifiManager();
- if (iWifiManager == null) {
- if (ArrayUtils.isEmpty(supplicantData) && ArrayUtils.isEmpty(ipConfigData)) return;
- throw new RemoteException("Wifi service is not running");
- }
- iWifiManager.restoreSupplicantBackupData(supplicantData, ipConfigData);
+ mService.restoreSupplicantBackupData(supplicantData, ipConfigData);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -4858,11 +4591,7 @@ public class WifiManager {
throw new IllegalArgumentException("callback must not be null");
}
try {
- IWifiManager iWifiManager = getIWifiManager();
- if (iWifiManager == null) {
- throw new RemoteException("Wifi service is not running");
- }
- iWifiManager.startSubscriptionProvisioning(provider,
+ mService.startSubscriptionProvisioning(provider,
new ProvisioningCallbackProxy(executor, callback));
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -4996,11 +4725,7 @@ public class WifiManager {
Binder binder = new Binder();
try {
- IWifiManager iWifiManager = getIWifiManager();
- if (iWifiManager == null) {
- throw new RemoteException("Wifi service is not running");
- }
- iWifiManager.registerTrafficStateCallback(
+ mService.registerTrafficStateCallback(
binder, new TrafficStateCallbackProxy(executor, callback), callback.hashCode());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -5021,11 +4746,7 @@ public class WifiManager {
Log.v(TAG, "unregisterTrafficStateCallback: callback=" + callback);
try {
- IWifiManager iWifiManager = getIWifiManager();
- if (iWifiManager == null) {
- throw new RemoteException("Wifi service is not running");
- }
- iWifiManager.unregisterTrafficStateCallback(callback.hashCode());
+ mService.unregisterTrafficStateCallback(callback.hashCode());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -5083,9 +4804,7 @@ public class WifiManager {
@RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
public String[] getFactoryMacAddresses() {
try {
- IWifiManager iWifiManager = getIWifiManager();
- if (iWifiManager == null) return new String[0];
- return iWifiManager.getFactoryMacAddresses();
+ return mService.getFactoryMacAddresses();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -5154,12 +4873,7 @@ public class WifiManager {
@RequiresPermission(android.Manifest.permission.WIFI_SET_DEVICE_MOBILITY_STATE)
public void setDeviceMobilityState(@DeviceMobilityState int state) {
try {
- IWifiManager iWifiManager = getIWifiManager();
- if (iWifiManager == null) {
- if (state == DEVICE_MOBILITY_STATE_UNKNOWN) return;
- throw new RemoteException("Wifi service is not running");
- }
- iWifiManager.setDeviceMobilityState(state);
+ mService.setDeviceMobilityState(state);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -5214,13 +4928,8 @@ public class WifiManager {
@NonNull EasyConnectStatusCallback callback) {
Binder binder = new Binder();
try {
- IWifiManager iWifiManager = getIWifiManager();
- if (iWifiManager == null) {
- throw new RemoteException("Wifi service is not running");
- }
- iWifiManager.startDppAsConfiguratorInitiator(
- binder, enrolleeUri, selectedNetworkId, enrolleeNetworkRole,
- new EasyConnectCallbackProxy(executor, callback));
+ mService.startDppAsConfiguratorInitiator(binder, enrolleeUri, selectedNetworkId,
+ enrolleeNetworkRole, new EasyConnectCallbackProxy(executor, callback));
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -5245,11 +4954,7 @@ public class WifiManager {
@NonNull EasyConnectStatusCallback callback) {
Binder binder = new Binder();
try {
- IWifiManager iWifiManager = getIWifiManager();
- if (iWifiManager == null) {
- throw new RemoteException("Wifi service is not running");
- }
- iWifiManager.startDppAsEnrolleeInitiator(binder, configuratorUri,
+ mService.startDppAsEnrolleeInitiator(binder, configuratorUri,
new EasyConnectCallbackProxy(executor, callback));
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -5270,12 +4975,8 @@ public class WifiManager {
android.Manifest.permission.NETWORK_SETUP_WIZARD})
public void stopEasyConnectSession() {
try {
- IWifiManager iWifiManager = getIWifiManager();
- if (iWifiManager == null) {
- throw new RemoteException("Wifi service is not running");
- }
/* Request lower layers to stop/abort and clear resources */
- iWifiManager.stopDppSession();
+ mService.stopDppSession();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -5374,11 +5075,7 @@ public class WifiManager {
Log.v(TAG, "addOnWifiUsabilityStatsListener: listener=" + listener);
}
try {
- IWifiManager iWifiManager = getIWifiManager();
- if (iWifiManager == null) {
- throw new RemoteException("Wifi service is not running");
- }
- iWifiManager.addOnWifiUsabilityStatsListener(new Binder(),
+ mService.addOnWifiUsabilityStatsListener(new Binder(),
new IOnWifiUsabilityStatsListener.Stub() {
@Override
public void onWifiUsabilityStats(int seqNum, boolean isSameBssidAndFreq,
@@ -5387,9 +5084,9 @@ public class WifiManager {
Log.v(TAG, "OnWifiUsabilityStatsListener: "
+ "onWifiUsabilityStats: seqNum=" + seqNum);
}
- Binder.withCleanCallingIdentity(() ->
- executor.execute(() -> listener.onWifiUsabilityStats(seqNum,
- isSameBssidAndFreq, stats)));
+ Binder.clearCallingIdentity();
+ executor.execute(() -> listener.onWifiUsabilityStats(
+ seqNum, isSameBssidAndFreq, stats));
}
},
listener.hashCode()
@@ -5415,11 +5112,7 @@ public class WifiManager {
Log.v(TAG, "removeOnWifiUsabilityStatsListener: listener=" + listener);
}
try {
- IWifiManager iWifiManager = getIWifiManager();
- if (iWifiManager == null) {
- throw new RemoteException("Wifi service is not running");
- }
- iWifiManager.removeOnWifiUsabilityStatsListener(listener.hashCode());
+ mService.removeOnWifiUsabilityStatsListener(listener.hashCode());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -5442,11 +5135,7 @@ public class WifiManager {
@RequiresPermission(android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE)
public void updateWifiUsabilityScore(int seqNum, int score, int predictionHorizonSec) {
try {
- IWifiManager iWifiManager = getIWifiManager();
- if (iWifiManager == null) {
- throw new RemoteException("Wifi service is not running");
- }
- iWifiManager.updateWifiUsabilityScore(seqNum, score, predictionHorizonSec);
+ mService.updateWifiUsabilityScore(seqNum, score, predictionHorizonSec);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -5545,11 +5234,7 @@ public class WifiManager {
ScanResultsCallback.ScanResultsCallbackProxy proxy = callback.getProxy();
proxy.initProxy(executor, callback);
try {
- IWifiManager iWifiManager = getIWifiManager();
- if (iWifiManager == null) {
- throw new RemoteException("Wifi service is not running");
- }
- iWifiManager.registerScanResultsCallback(proxy);
+ mService.registerScanResultsCallback(proxy);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -5567,11 +5252,7 @@ public class WifiManager {
Log.v(TAG, "unregisterScanResultsCallback: Callback=" + callback);
ScanResultsCallback.ScanResultsCallbackProxy proxy = callback.getProxy();
try {
- IWifiManager iWifiManager = getIWifiManager();
- if (iWifiManager == null) {
- throw new RemoteException("Wifi service is not running");
- }
- iWifiManager.unregisterScanResultsCallback(proxy);
+ mService.unregisterScanResultsCallback(proxy);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
} finally {
@@ -5647,11 +5328,7 @@ public class WifiManager {
Log.v(TAG, "addSuggestionConnectionStatusListener listener=" + listener
+ ", executor=" + executor);
try {
- IWifiManager iWifiManager = getIWifiManager();
- if (iWifiManager == null) {
- throw new RemoteException("Wifi service is not running");
- }
- iWifiManager.registerSuggestionConnectionStatusListener(new Binder(),
+ mService.registerSuggestionConnectionStatusListener(new Binder(),
new SuggestionConnectionStatusListenerProxy(executor, listener),
listener.hashCode(), mContext.getOpPackageName(), mContext.getFeatureId());
} catch (RemoteException e) {
@@ -5672,11 +5349,7 @@ public class WifiManager {
if (listener == null) throw new IllegalArgumentException("Listener cannot be null");
Log.v(TAG, "removeSuggestionConnectionStatusListener: listener=" + listener);
try {
- IWifiManager iWifiManager = getIWifiManager();
- if (iWifiManager == null) {
- throw new RemoteException("Wifi service is not running");
- }
- iWifiManager.unregisterSuggestionConnectionStatusListener(listener.hashCode(),
+ mService.unregisterSuggestionConnectionStatusListener(listener.hashCode(),
mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
diff --git a/wifi/java/android/net/wifi/WifiNetworkSuggestion.java b/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
index 246e96f4ce3f..a5ca82c50627 100644
--- a/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
+++ b/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
@@ -116,6 +116,16 @@ public final class WifiNetworkSuggestion implements Parcelable {
*/
private int mCarrierId;
+ /**
+ * Whether this network is shared credential with user to allow user manually connect.
+ */
+ private boolean mIsUserAllowed;
+
+ /**
+ * Whether the setIsUserAllowedToManuallyConnect have been called.
+ */
+ private boolean mIsUserAllowedBeenSet;
+
public Builder() {
mSsid = null;
mBssid = null;
@@ -129,6 +139,8 @@ public final class WifiNetworkSuggestion implements Parcelable {
mIsAppInteractionRequired = false;
mIsUserInteractionRequired = false;
mIsMetered = false;
+ mIsUserAllowed = true;
+ mIsUserAllowedBeenSet = false;
mPriority = UNASSIGNED_PRIORITY;
mCarrierId = TelephonyManager.UNKNOWN_CARRIER_ID;
}
@@ -365,6 +377,27 @@ public final class WifiNetworkSuggestion implements Parcelable {
return this;
}
+ /**
+ * Specifies whether the network credentials provided with this suggestion can be used by
+ * the user to explicitly (manually) connect to this network. If true this network will
+ * appear in the Wi-Fi Picker (in Settings) and the user will be able to select and connect
+ * to it with the provided credentials. If false, the user will need to enter network
+ * credentials and the resulting configuration will become a user saved network.
+ * <p>
+ * <li>Note: Only valid for secure (non-open) networks.
+ * <li>If not set, defaults to true (i.e. allow user to manually connect) for secure
+ * networks and false for open networks.</li>
+ *
+ * @param isAllowed {@code true} to indicate that the credentials may be used by the user to
+ * manually connect to the network, {@code false} otherwise.
+ * @return Instance of {@link Builder} to enable chaining of the builder method.
+ */
+ public @NonNull Builder setIsUserAllowedToManuallyConnect(boolean isAllowed) {
+ mIsUserAllowed = isAllowed;
+ mIsUserAllowedBeenSet = true;
+ return this;
+ }
+
private void setSecurityParamsInWifiConfiguration(
@NonNull WifiConfiguration configuration) {
if (!TextUtils.isEmpty(mWpa2PskPassphrase)) { // WPA-PSK network.
@@ -516,6 +549,13 @@ public final class WifiNetworkSuggestion implements Parcelable {
throw new IllegalStateException("invalid bssid for suggestion");
}
wifiConfiguration = buildWifiConfiguration();
+ if (wifiConfiguration.isOpenNetwork()) {
+ if (mIsUserAllowedBeenSet && mIsUserAllowed) {
+ throw new IllegalStateException("Open network should not be "
+ + "setIsUserAllowedToManuallyConnect to true");
+ }
+ mIsUserAllowed = false;
+ }
}
return new WifiNetworkSuggestion(
@@ -523,6 +563,7 @@ public final class WifiNetworkSuggestion implements Parcelable {
mPasspointConfiguration,
mIsAppInteractionRequired,
mIsUserInteractionRequired,
+ mIsUserAllowed,
Process.myUid(),
ActivityThread.currentApplication().getApplicationContext().getOpPackageName());
}
@@ -564,12 +605,20 @@ public final class WifiNetworkSuggestion implements Parcelable {
*/
public final String suggestorPackageName;
+ /**
+ * Whether app share credential with the user, allow user use provided credential to
+ * connect network manually.
+ * @hide
+ */
+ public final boolean isUserAllowedToManuallyConnect;
+
/** @hide */
public WifiNetworkSuggestion() {
this.wifiConfiguration = null;
this.passpointConfiguration = null;
this.isAppInteractionRequired = false;
this.isUserInteractionRequired = false;
+ this.isUserAllowedToManuallyConnect = true;
this.suggestorUid = -1;
this.suggestorPackageName = null;
}
@@ -579,6 +628,7 @@ public final class WifiNetworkSuggestion implements Parcelable {
@Nullable PasspointConfiguration passpointConfiguration,
boolean isAppInteractionRequired,
boolean isUserInteractionRequired,
+ boolean isUserAllowedToManuallyConnect,
int suggestorUid, @NonNull String suggestorPackageName) {
checkNotNull(networkConfiguration);
checkNotNull(suggestorPackageName);
@@ -587,6 +637,7 @@ public final class WifiNetworkSuggestion implements Parcelable {
this.isAppInteractionRequired = isAppInteractionRequired;
this.isUserInteractionRequired = isUserInteractionRequired;
+ this.isUserAllowedToManuallyConnect = isUserAllowedToManuallyConnect;
this.suggestorUid = suggestorUid;
this.suggestorPackageName = suggestorPackageName;
}
@@ -600,6 +651,7 @@ public final class WifiNetworkSuggestion implements Parcelable {
in.readParcelable(null), // PasspointConfiguration
in.readBoolean(), // isAppInteractionRequired
in.readBoolean(), // isUserInteractionRequired
+ in.readBoolean(), // isSharedCredentialWithUser
in.readInt(), // suggestorUid
in.readString() // suggestorPackageName
);
@@ -622,6 +674,7 @@ public final class WifiNetworkSuggestion implements Parcelable {
dest.writeParcelable(passpointConfiguration, flags);
dest.writeBoolean(isAppInteractionRequired);
dest.writeBoolean(isUserInteractionRequired);
+ dest.writeBoolean(isUserAllowedToManuallyConnect);
dest.writeInt(suggestorUid);
dest.writeString(suggestorPackageName);
}
@@ -666,6 +719,7 @@ public final class WifiNetworkSuggestion implements Parcelable {
.append(", FQDN=").append(wifiConfiguration.FQDN)
.append(", isAppInteractionRequired=").append(isAppInteractionRequired)
.append(", isUserInteractionRequired=").append(isUserInteractionRequired)
+ .append(", isUserAllowedToManuallyConnect=").append(isUserAllowedToManuallyConnect)
.append(", suggestorUid=").append(suggestorUid)
.append(", suggestorPackageName=").append(suggestorPackageName)
.append("]");
diff --git a/wifi/java/android/net/wifi/WifiScanner.java b/wifi/java/android/net/wifi/WifiScanner.java
index 0de506610ec1..77f7b9e23fc0 100644
--- a/wifi/java/android/net/wifi/WifiScanner.java
+++ b/wifi/java/android/net/wifi/WifiScanner.java
@@ -17,13 +17,16 @@
package android.net.wifi;
import android.Manifest;
+import android.annotation.CallbackExecutor;
import android.annotation.IntDef;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.content.Context;
+import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
@@ -45,6 +48,7 @@ import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
+import java.util.concurrent.Executor;
/**
* This class provides a way to scan the Wifi universe around the device
@@ -196,24 +200,29 @@ public class WifiScanner {
*/
public static final int REPORT_EVENT_NO_BATCH = (1 << 2);
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = {"SCAN_TYPE_"}, value = {
+ SCAN_TYPE_LOW_LATENCY,
+ SCAN_TYPE_LOW_POWER,
+ SCAN_TYPE_HIGH_ACCURACY})
+ public @interface ScanType {}
+
/**
- * This is used to indicate the purpose of the scan to the wifi chip in
- * {@link ScanSettings#type}.
- * On devices with multiple hardware radio chains (and hence different modes of scan),
- * this type serves as an indication to the hardware on what mode of scan to perform.
- * Only apps holding android.Manifest.permission.NETWORK_STACK permission can set this value.
- *
- * Note: This serves as an intent and not as a stipulation, the wifi chip
- * might honor or ignore the indication based on the current radio conditions. Always
- * use the {@link ScanResult#radioChainInfos} to figure out the radio chain configuration used
- * to receive the corresponding scan result.
+ * Optimize the scan for lower latency.
+ * @see ScanSettings#type
*/
- /** {@hide} */
- public static final int TYPE_LOW_LATENCY = 0;
- /** {@hide} */
- public static final int TYPE_LOW_POWER = 1;
- /** {@hide} */
- public static final int TYPE_HIGH_ACCURACY = 2;
+ public static final int SCAN_TYPE_LOW_LATENCY = 0;
+ /**
+ * Optimize the scan for lower power usage.
+ * @see ScanSettings#type
+ */
+ public static final int SCAN_TYPE_LOW_POWER = 1;
+ /**
+ * Optimize the scan for higher accuracy.
+ * @see ScanSettings#type
+ */
+ public static final int SCAN_TYPE_HIGH_ACCURACY = 2;
/** {@hide} */
public static final String SCAN_PARAMS_SCAN_SETTINGS_KEY = "ScanSettings";
@@ -228,18 +237,14 @@ public class WifiScanner {
* scan configuration parameters to be sent to {@link #startBackgroundScan}
*/
public static class ScanSettings implements Parcelable {
- /**
- * Hidden network to be scanned for.
- * {@hide}
- */
+ /** Hidden network to be scanned for. */
public static class HiddenNetwork {
/** SSID of the network */
- public String ssid;
+ @NonNull
+ public final String ssid;
- /**
- * Default constructor for HiddenNetwork.
- */
- public HiddenNetwork(String ssid) {
+ /** Default constructor for HiddenNetwork. */
+ public HiddenNetwork(@NonNull String ssid) {
this.ssid = ssid;
}
}
@@ -249,12 +254,12 @@ public class WifiScanner {
/** list of channels; used when band is set to WIFI_BAND_UNSPECIFIED */
public ChannelSpec[] channels;
/**
- * list of hidden networks to scan for. Explicit probe requests are sent out for such
+ * List of hidden networks to scan for. Explicit probe requests are sent out for such
* networks during scan. Only valid for single scan requests.
- * {@hide}
*/
+ @NonNull
@RequiresPermission(android.Manifest.permission.NETWORK_STACK)
- public HiddenNetwork[] hiddenNetworks;
+ public final List<HiddenNetwork> hiddenNetworks = new ArrayList<>();
/** period of background scan; in millisecond, 0 => single shot scan */
public int periodInMs;
/** must have a valid REPORT_EVENT value */
@@ -285,11 +290,24 @@ public class WifiScanner {
public boolean isPnoScan;
/**
* Indicate the type of scan to be performed by the wifi chip.
- * Default value: {@link #TYPE_LOW_LATENCY}.
- * {@hide}
+ *
+ * On devices with multiple hardware radio chains (and hence different modes of scan),
+ * this type serves as an indication to the hardware on what mode of scan to perform.
+ * Only apps holding {@link android.Manifest.permission.NETWORK_STACK} permission can set
+ * this value.
+ *
+ * Note: This serves as an intent and not as a stipulation, the wifi chip
+ * might honor or ignore the indication based on the current radio conditions. Always
+ * use the {@link ScanResult#radioChainInfos} to figure out the radio chain configuration
+ * used to receive the corresponding scan result.
+ *
+ * One of {@link #SCAN_TYPE_LOW_LATENCY}, {@link #SCAN_TYPE_LOW_POWER},
+ * {@link #SCAN_TYPE_HIGH_ACCURACY}.
+ * Default value: {@link #SCAN_TYPE_LOW_LATENCY}.
*/
+ @ScanType
@RequiresPermission(android.Manifest.permission.NETWORK_STACK)
- public int type = TYPE_LOW_LATENCY;
+ public int type = SCAN_TYPE_LOW_LATENCY;
/**
* This scan request may ignore location settings while receiving scans. This should only
* be used in emergency situations.
@@ -336,13 +354,9 @@ public class WifiScanner {
} else {
dest.writeInt(0);
}
- if (hiddenNetworks != null) {
- dest.writeInt(hiddenNetworks.length);
- for (int i = 0; i < hiddenNetworks.length; i++) {
- dest.writeString(hiddenNetworks[i].ssid);
- }
- } else {
- dest.writeInt(0);
+ dest.writeInt(hiddenNetworks.size());
+ for (HiddenNetwork hiddenNetwork : hiddenNetworks) {
+ dest.writeString(hiddenNetwork.ssid);
}
}
@@ -372,10 +386,10 @@ public class WifiScanner {
settings.channels[i] = spec;
}
int numNetworks = in.readInt();
- settings.hiddenNetworks = new HiddenNetwork[numNetworks];
+ settings.hiddenNetworks.clear();
for (int i = 0; i < numNetworks; i++) {
String ssid = in.readString();
- settings.hiddenNetworks[i] = new HiddenNetwork(ssid);;
+ settings.hiddenNetworks.add(new HiddenNetwork(ssid));
}
return settings;
}
@@ -801,33 +815,44 @@ public class WifiScanner {
}
/**
- * Register a listener that will receive results from all single scans
- * Either the onSuccess/onFailure will be called once when the listener is registered. After
- * (assuming onSuccess was called) all subsequent single scan results will be delivered to the
- * listener. It is possible that onFullResult will not be called for all results of the first
- * scan if the listener was registered during the scan.
+ * Register a listener that will receive results from all single scans.
+ * Either the {@link ScanListener#onSuccess()} or {@link ScanListener#onFailure(int, String)}
+ * method will be called once when the listener is registered.
+ * Afterwards (assuming onSuccess was called), all subsequent single scan results will be
+ * delivered to the listener. It is possible that onFullResult will not be called for all
+ * results of the first scan if the listener was registered during the scan.
*
* @param listener specifies the object to report events to. This object is also treated as a
* key for this request, and must also be specified to cancel the request.
* Multiple requests should also not share this object.
- * {@hide}
*/
@RequiresPermission(Manifest.permission.NETWORK_STACK)
- public void registerScanListener(ScanListener listener) {
+ public void registerScanListener(@NonNull @CallbackExecutor Executor executor,
+ @NonNull ScanListener listener) {
+ Preconditions.checkNotNull(executor, "executor cannot be null");
Preconditions.checkNotNull(listener, "listener cannot be null");
- int key = addListener(listener);
+ int key = addListener(listener, executor);
if (key == INVALID_KEY) return;
validateChannel();
mAsyncChannel.sendMessage(CMD_REGISTER_SCAN_LISTENER, 0, key);
}
/**
+ * Overload of {@link #registerScanListener(Executor, ScanListener)} that executes the callback
+ * synchronously.
+ * @hide
+ */
+ @RequiresPermission(Manifest.permission.NETWORK_STACK)
+ public void registerScanListener(@NonNull ScanListener listener) {
+ registerScanListener(new SynchronousExecutor(), listener);
+ }
+
+ /**
* Deregister a listener for ongoing single scans
* @param listener specifies which scan to cancel; must be same object as passed in {@link
* #registerScanListener}
- * {@hide}
*/
- public void deregisterScanListener(ScanListener listener) {
+ public void unregisterScanListener(@NonNull ScanListener listener) {
Preconditions.checkNotNull(listener, "listener cannot be null");
int key = removeListener(listener);
if (key == INVALID_KEY) return;
@@ -1280,6 +1305,7 @@ public class WifiScanner {
private int mListenerKey = 1;
private final SparseArray mListenerMap = new SparseArray();
+ private final SparseArray<Executor> mExecutorMap = new SparseArray<>();
private final Object mListenerMapLock = new Object();
private AsyncChannel mAsyncChannel;
@@ -1327,10 +1353,14 @@ public class WifiScanner {
"No permission to access and change wifi or a bad initialization");
}
+ private int addListener(ActionListener listener) {
+ return addListener(listener, null);
+ }
+
// Add a listener into listener map. If the listener already exists, return INVALID_KEY and
// send an error message to internal handler; Otherwise add the listener to the listener map and
// return the key of the listener.
- private int addListener(ActionListener listener) {
+ private int addListener(ActionListener listener, Executor executor) {
synchronized (mListenerMapLock) {
boolean keyExists = (getListenerKey(listener) != INVALID_KEY);
// Note we need to put the listener into listener map even if it's a duplicate as the
@@ -1346,6 +1376,7 @@ public class WifiScanner {
message.sendToTarget();
return INVALID_KEY;
} else {
+ mExecutorMap.put(key, executor);
return key;
}
}
@@ -1363,11 +1394,22 @@ public class WifiScanner {
return key;
}
- private Object getListener(int key) {
- if (key == INVALID_KEY) return null;
+ private static class ListenerWithExecutor {
+ @Nullable final Object mListener;
+ @Nullable final Executor mExecutor;
+
+ ListenerWithExecutor(@Nullable Object listener, @Nullable Executor executor) {
+ mListener = listener;
+ mExecutor = executor;
+ }
+ }
+
+ private ListenerWithExecutor getListenerWithExecutor(int key) {
+ if (key == INVALID_KEY) return new ListenerWithExecutor(null, null);
synchronized (mListenerMapLock) {
Object listener = mListenerMap.get(key);
- return listener;
+ Executor executor = mExecutorMap.get(key);
+ return new ListenerWithExecutor(listener, executor);
}
}
@@ -1388,6 +1430,7 @@ public class WifiScanner {
synchronized (mListenerMapLock) {
Object listener = mListenerMap.get(key);
mListenerMap.remove(key);
+ mExecutorMap.remove(key);
return listener;
}
}
@@ -1400,6 +1443,7 @@ public class WifiScanner {
}
synchronized (mListenerMapLock) {
mListenerMap.remove(key);
+ mExecutorMap.remove(key);
return key;
}
}
@@ -1458,7 +1502,8 @@ public class WifiScanner {
return;
}
- Object listener = getListener(msg.arg2);
+ ListenerWithExecutor listenerWithExecutor = getListenerWithExecutor(msg.arg2);
+ Object listener = listenerWithExecutor.mListener;
if (listener == null) {
if (DBG) Log.d(TAG, "invalid listener key = " + msg.arg2);
@@ -1467,36 +1512,52 @@ public class WifiScanner {
if (DBG) Log.d(TAG, "listener key = " + msg.arg2);
}
+ Executor executor = listenerWithExecutor.mExecutor;
+ if (executor == null) {
+ executor = new SynchronousExecutor();
+ }
+
switch (msg.what) {
- /* ActionListeners grouped together */
- case CMD_OP_SUCCEEDED :
- ((ActionListener) listener).onSuccess();
- break;
- case CMD_OP_FAILED : {
- OperationResult result = (OperationResult)msg.obj;
- ((ActionListener) listener).onFailure(result.reason, result.description);
- removeListener(msg.arg2);
- }
- break;
- case CMD_SCAN_RESULT :
- ((ScanListener) listener).onResults(
- ((ParcelableScanData) msg.obj).getResults());
- return;
- case CMD_FULL_SCAN_RESULT :
+ /* ActionListeners grouped together */
+ case CMD_OP_SUCCEEDED: {
+ ActionListener actionListener = (ActionListener) listener;
+ Binder.clearCallingIdentity();
+ executor.execute(actionListener::onSuccess);
+ } break;
+ case CMD_OP_FAILED: {
+ OperationResult result = (OperationResult) msg.obj;
+ ActionListener actionListener = (ActionListener) listener;
+ removeListener(msg.arg2);
+ Binder.clearCallingIdentity();
+ executor.execute(() ->
+ actionListener.onFailure(result.reason, result.description));
+ } break;
+ case CMD_SCAN_RESULT: {
+ ScanListener scanListener = (ScanListener) listener;
+ ParcelableScanData parcelableScanData = (ParcelableScanData) msg.obj;
+ Binder.clearCallingIdentity();
+ executor.execute(() -> scanListener.onResults(parcelableScanData.getResults()));
+ } break;
+ case CMD_FULL_SCAN_RESULT: {
ScanResult result = (ScanResult) msg.obj;
- ((ScanListener) listener).onFullResult(result);
- return;
- case CMD_SINGLE_SCAN_COMPLETED:
+ ScanListener scanListener = ((ScanListener) listener);
+ Binder.clearCallingIdentity();
+ executor.execute(() -> scanListener.onFullResult(result));
+ } break;
+ case CMD_SINGLE_SCAN_COMPLETED: {
if (DBG) Log.d(TAG, "removing listener for single scan");
removeListener(msg.arg2);
- break;
- case CMD_PNO_NETWORK_FOUND:
- ((PnoScanListener) listener).onPnoNetworkFound(
- ((ParcelableScanResults) msg.obj).getResults());
- return;
- default:
+ } break;
+ case CMD_PNO_NETWORK_FOUND: {
+ PnoScanListener pnoScanListener = (PnoScanListener) listener;
+ ParcelableScanResults parcelableScanResults = (ParcelableScanResults) msg.obj;
+ Binder.clearCallingIdentity();
+ executor.execute(() ->
+ pnoScanListener.onPnoNetworkFound(parcelableScanResults.getResults()));
+ } break;
+ default: {
if (DBG) Log.d(TAG, "Ignoring message " + msg.what);
- return;
+ } break;
}
}
}
diff --git a/wifi/java/android/net/wifi/aware/TlvBufferUtils.java b/wifi/java/android/net/wifi/aware/TlvBufferUtils.java
index b3b5b2903471..2d3cc1eda643 100644
--- a/wifi/java/android/net/wifi/aware/TlvBufferUtils.java
+++ b/wifi/java/android/net/wifi/aware/TlvBufferUtils.java
@@ -18,8 +18,6 @@ package android.net.wifi.aware;
import android.annotation.Nullable;
-import libcore.io.Memory;
-
import java.nio.BufferOverflowException;
import java.nio.ByteOrder;
import java.util.ArrayList;
@@ -266,7 +264,7 @@ public class TlvBufferUtils {
public TlvConstructor putShort(int type, short data) {
checkLength(2);
addHeader(type, 2);
- Memory.pokeShort(mArray, mPosition, data, mByteOrder);
+ pokeShort(mArray, mPosition, data, mByteOrder);
mPosition += 2;
return this;
}
@@ -284,7 +282,7 @@ public class TlvBufferUtils {
public TlvConstructor putInt(int type, int data) {
checkLength(4);
addHeader(type, 4);
- Memory.pokeInt(mArray, mPosition, data, mByteOrder);
+ pokeInt(mArray, mPosition, data, mByteOrder);
mPosition += 4;
return this;
}
@@ -349,14 +347,14 @@ public class TlvBufferUtils {
if (mTypeSize == 1) {
mArray[mPosition] = (byte) type;
} else if (mTypeSize == 2) {
- Memory.pokeShort(mArray, mPosition, (short) type, mByteOrder);
+ pokeShort(mArray, mPosition, (short) type, mByteOrder);
}
mPosition += mTypeSize;
if (mLengthSize == 1) {
mArray[mPosition] = (byte) length;
} else if (mLengthSize == 2) {
- Memory.pokeShort(mArray, mPosition, (short) length, mByteOrder);
+ pokeShort(mArray, mPosition, (short) length, mByteOrder);
}
mPosition += mLengthSize;
}
@@ -445,7 +443,7 @@ public class TlvBufferUtils {
throw new IllegalArgumentException(
"Accesing a short from a TLV element of length " + length);
}
- return Memory.peekShort(mRefArray, offset, byteOrder);
+ return peekShort(mRefArray, offset, byteOrder);
}
/**
@@ -460,7 +458,7 @@ public class TlvBufferUtils {
throw new IllegalArgumentException(
"Accesing an int from a TLV element of length " + length);
}
- return Memory.peekInt(mRefArray, offset, byteOrder);
+ return peekInt(mRefArray, offset, byteOrder);
}
/**
@@ -590,7 +588,7 @@ public class TlvBufferUtils {
if (mTypeSize == 1) {
type = mArray[mOffset];
} else if (mTypeSize == 2) {
- type = Memory.peekShort(mArray, mOffset, mByteOrder);
+ type = peekShort(mArray, mOffset, mByteOrder);
}
mOffset += mTypeSize;
@@ -598,7 +596,7 @@ public class TlvBufferUtils {
if (mLengthSize == 1) {
length = mArray[mOffset];
} else if (mLengthSize == 2) {
- length = Memory.peekShort(mArray, mOffset, mByteOrder);
+ length = peekShort(mArray, mOffset, mByteOrder);
}
mOffset += mLengthSize;
@@ -661,10 +659,56 @@ public class TlvBufferUtils {
if (lengthSize == 1) {
nextTlvIndex += lengthSize + array[nextTlvIndex];
} else {
- nextTlvIndex += lengthSize + Memory.peekShort(array, nextTlvIndex, byteOrder);
+ nextTlvIndex += lengthSize + peekShort(array, nextTlvIndex, byteOrder);
}
}
return nextTlvIndex == array.length;
}
+
+ private static void pokeShort(byte[] dst, int offset, short value, ByteOrder order) {
+ if (order == ByteOrder.BIG_ENDIAN) {
+ dst[offset++] = (byte) ((value >> 8) & 0xff);
+ dst[offset ] = (byte) ((value >> 0) & 0xff);
+ } else {
+ dst[offset++] = (byte) ((value >> 0) & 0xff);
+ dst[offset ] = (byte) ((value >> 8) & 0xff);
+ }
+ }
+
+ private static void pokeInt(byte[] dst, int offset, int value, ByteOrder order) {
+ if (order == ByteOrder.BIG_ENDIAN) {
+ dst[offset++] = (byte) ((value >> 24) & 0xff);
+ dst[offset++] = (byte) ((value >> 16) & 0xff);
+ dst[offset++] = (byte) ((value >> 8) & 0xff);
+ dst[offset ] = (byte) ((value >> 0) & 0xff);
+ } else {
+ dst[offset++] = (byte) ((value >> 0) & 0xff);
+ dst[offset++] = (byte) ((value >> 8) & 0xff);
+ dst[offset++] = (byte) ((value >> 16) & 0xff);
+ dst[offset ] = (byte) ((value >> 24) & 0xff);
+ }
+ }
+
+ private static short peekShort(byte[] src, int offset, ByteOrder order) {
+ if (order == ByteOrder.BIG_ENDIAN) {
+ return (short) ((src[offset] << 8) | (src[offset + 1] & 0xff));
+ } else {
+ return (short) ((src[offset + 1] << 8) | (src[offset] & 0xff));
+ }
+ }
+
+ private static int peekInt(byte[] src, int offset, ByteOrder order) {
+ if (order == ByteOrder.BIG_ENDIAN) {
+ return ((src[offset++] & 0xff) << 24)
+ | ((src[offset++] & 0xff) << 16)
+ | ((src[offset++] & 0xff) << 8)
+ | ((src[offset ] & 0xff) << 0);
+ } else {
+ return ((src[offset++] & 0xff) << 0)
+ | ((src[offset++] & 0xff) << 8)
+ | ((src[offset++] & 0xff) << 16)
+ | ((src[offset ] & 0xff) << 24);
+ }
+ }
}
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareAgentNetworkSpecifier.java b/wifi/java/android/net/wifi/aware/WifiAwareAgentNetworkSpecifier.java
index 9164d04885b3..5ec4c8b13ee8 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareAgentNetworkSpecifier.java
+++ b/wifi/java/android/net/wifi/aware/WifiAwareAgentNetworkSpecifier.java
@@ -207,14 +207,14 @@ public class WifiAwareAgentNetworkSpecifier extends NetworkSpecifier implements
@Override
public void writeToParcel(Parcel dest, int flags) {
- dest.writeBlob(mData);
+ dest.writeByteArray(mData);
}
public static final @android.annotation.NonNull Creator<ByteArrayWrapper> CREATOR =
new Creator<ByteArrayWrapper>() {
@Override
public ByteArrayWrapper createFromParcel(Parcel in) {
- return new ByteArrayWrapper(in.readBlob());
+ return new ByteArrayWrapper(in.createByteArray());
}
@Override
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pDevice.java b/wifi/java/android/net/wifi/p2p/WifiP2pDevice.java
index 13b25209990e..98ec208f32e6 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pDevice.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pDevice.java
@@ -286,14 +286,12 @@ public class WifiP2pDevice implements Parcelable {
}
/**
- * Update device details. This will throw an exception if the device address does not match.
+ * Update this device's details using another {@link WifiP2pDevice} instance.
+ * This will throw an exception if the device address does not match.
*
- * @param device to be updated
+ * @param device another instance of {@link WifiP2pDevice} used to update this instance.
* @throws IllegalArgumentException if the device is null or the device address does not match
- *
- * @hide
*/
- @UnsupportedAppUsage
public void update(@NonNull WifiP2pDevice device) {
updateSupplicantDetails(device);
status = device.status;
diff --git a/wifi/java/android/net/wifi/rtt/package.html b/wifi/java/android/net/wifi/rtt/package.html
index e6392821ff54..4a32f5206fde 100644
--- a/wifi/java/android/net/wifi/rtt/package.html
+++ b/wifi/java/android/net/wifi/rtt/package.html
@@ -37,5 +37,9 @@ location to be queried.</p>
<pre>
getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI_RTT)
</pre>
+
+<p>For an example of this functionality, see
+<a href="{@docRoot}guide/topics/connectivity/wifi-rtt" class="external">Wi-Fi location: ranging
+with RTT</a>.</p>
</BODY>
</HTML>
diff --git a/wifi/tests/src/android/net/wifi/WifiManagerTest.java b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
index 8cdcba67386b..d326201fa574 100644
--- a/wifi/tests/src/android/net/wifi/WifiManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
@@ -1437,15 +1437,6 @@ public class WifiManagerTest {
}
/**
- * Defined for testing purpose.
- */
- class SynchronousExecutor implements Executor {
- public void execute(Runnable r) {
- r.run();
- }
- }
-
- /**
* Test behavior of isEnhancedOpenSupported
*/
@Test
diff --git a/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java b/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java
index 699008905f0a..ce085f55b0dd 100644
--- a/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java
@@ -64,12 +64,13 @@ public class WifiNetworkSuggestionTest {
assertEquals(WifiConfiguration.METERED_OVERRIDE_NONE,
suggestion.wifiConfiguration.meteredOverride);
assertEquals(-1, suggestion.wifiConfiguration.priority);
+ assertEquals(false, suggestion.isUserAllowedToManuallyConnect);
}
/**
* Validate correctness of WifiNetworkSuggestion object created by
* {@link WifiNetworkSuggestion.Builder#build()} for WPA_EAP network which requires
- * app interaction and has a priority of zero set.
+ * app interaction, not share credential and has a priority of zero set.
*/
@Test
public void
@@ -78,6 +79,7 @@ public class WifiNetworkSuggestionTest {
.setSsid(TEST_SSID)
.setWpa2Passphrase(TEST_PRESHARED_KEY)
.setIsAppInteractionRequired(true)
+ .setIsUserAllowedToManuallyConnect(false)
.setPriority(0)
.build();
@@ -91,6 +93,7 @@ public class WifiNetworkSuggestionTest {
assertEquals(WifiConfiguration.METERED_OVERRIDE_NONE,
suggestion.wifiConfiguration.meteredOverride);
assertEquals(0, suggestion.wifiConfiguration.priority);
+ assertEquals(false, suggestion.isUserAllowedToManuallyConnect);
}
/**
@@ -118,6 +121,7 @@ public class WifiNetworkSuggestionTest {
assertEquals(WifiConfiguration.METERED_OVERRIDE_METERED,
suggestion.wifiConfiguration.meteredOverride);
assertEquals(-1, suggestion.wifiConfiguration.priority);
+ assertTrue(suggestion.isUserAllowedToManuallyConnect);
}
/**
@@ -138,6 +142,7 @@ public class WifiNetworkSuggestionTest {
.get(WifiConfiguration.KeyMgmt.OWE));
assertNull(suggestion.wifiConfiguration.preSharedKey);
assertTrue(suggestion.wifiConfiguration.requirePMF);
+ assertFalse(suggestion.isUserAllowedToManuallyConnect);
}
/**
@@ -149,6 +154,7 @@ public class WifiNetworkSuggestionTest {
WifiNetworkSuggestion suggestion = new WifiNetworkSuggestion.Builder()
.setSsid(TEST_SSID)
.setWpa3Passphrase(TEST_PRESHARED_KEY)
+ .setIsUserAllowedToManuallyConnect(true)
.build();
assertEquals("\"" + TEST_SSID + "\"", suggestion.wifiConfiguration.SSID);
@@ -157,6 +163,7 @@ public class WifiNetworkSuggestionTest {
assertEquals("\"" + TEST_PRESHARED_KEY + "\"",
suggestion.wifiConfiguration.preSharedKey);
assertTrue(suggestion.wifiConfiguration.requirePMF);
+ assertTrue(suggestion.isUserAllowedToManuallyConnect);
}
@@ -186,6 +193,7 @@ public class WifiNetworkSuggestionTest {
assertNull(suggestion.wifiConfiguration.preSharedKey);
// allowedSuiteBCiphers are set according to the loaded certificate and cannot be tested
// here.
+ assertTrue(suggestion.isUserAllowedToManuallyConnect);
}
/**
@@ -205,6 +213,7 @@ public class WifiNetworkSuggestionTest {
assertTrue(suggestion.isAppInteractionRequired);
assertEquals(suggestion.wifiConfiguration.meteredOverride,
WifiConfiguration.METERED_OVERRIDE_METERED);
+ assertTrue(suggestion.isUserAllowedToManuallyConnect);
}
/**
@@ -439,7 +448,7 @@ public class WifiNetworkSuggestionTest {
configuration.BSSID = TEST_BSSID;
configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
WifiNetworkSuggestion suggestion = new WifiNetworkSuggestion(
- configuration, null, false, true, TEST_UID, TEST_PACKAGE_NAME);
+ configuration, null, false, true, true, TEST_UID, TEST_PACKAGE_NAME);
Parcel parcelW = Parcel.obtain();
suggestion.writeToParcel(parcelW, 0);
@@ -506,7 +515,7 @@ public class WifiNetworkSuggestionTest {
configuration.BSSID = TEST_BSSID;
configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
WifiNetworkSuggestion suggestion =
- new WifiNetworkSuggestion(configuration, null, true, false, TEST_UID,
+ new WifiNetworkSuggestion(configuration, null, true, false, true, TEST_UID,
TEST_PACKAGE_NAME);
WifiConfiguration configuration1 = new WifiConfiguration();
@@ -514,7 +523,7 @@ public class WifiNetworkSuggestionTest {
configuration1.BSSID = TEST_BSSID;
configuration1.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
WifiNetworkSuggestion suggestion1 =
- new WifiNetworkSuggestion(configuration1, null, false, true, TEST_UID,
+ new WifiNetworkSuggestion(configuration1, null, false, true, true, TEST_UID,
TEST_PACKAGE_NAME);
assertEquals(suggestion, suggestion1);
@@ -531,14 +540,14 @@ public class WifiNetworkSuggestionTest {
configuration.SSID = TEST_SSID;
configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
WifiNetworkSuggestion suggestion =
- new WifiNetworkSuggestion(configuration, null, false, false, TEST_UID,
+ new WifiNetworkSuggestion(configuration, null, false, false, true, TEST_UID,
TEST_PACKAGE_NAME);
WifiConfiguration configuration1 = new WifiConfiguration();
configuration1.SSID = TEST_SSID_1;
configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
WifiNetworkSuggestion suggestion1 =
- new WifiNetworkSuggestion(configuration1, null, false, false, TEST_UID,
+ new WifiNetworkSuggestion(configuration1, null, false, false, true, TEST_UID,
TEST_PACKAGE_NAME);
assertNotEquals(suggestion, suggestion1);
@@ -555,14 +564,14 @@ public class WifiNetworkSuggestionTest {
configuration.BSSID = TEST_BSSID;
configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
WifiNetworkSuggestion suggestion =
- new WifiNetworkSuggestion(configuration, null, false, false, TEST_UID,
+ new WifiNetworkSuggestion(configuration, null, false, false, true, TEST_UID,
TEST_PACKAGE_NAME);
WifiConfiguration configuration1 = new WifiConfiguration();
configuration1.SSID = TEST_SSID;
configuration1.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
WifiNetworkSuggestion suggestion1 =
- new WifiNetworkSuggestion(configuration1, null, false, false, TEST_UID,
+ new WifiNetworkSuggestion(configuration1, null, false, false, true, TEST_UID,
TEST_PACKAGE_NAME);
assertNotEquals(suggestion, suggestion1);
@@ -578,14 +587,14 @@ public class WifiNetworkSuggestionTest {
configuration.SSID = TEST_SSID;
configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
WifiNetworkSuggestion suggestion =
- new WifiNetworkSuggestion(configuration, null, false, false, TEST_UID,
+ new WifiNetworkSuggestion(configuration, null, false, false, true, TEST_UID,
TEST_PACKAGE_NAME);
WifiConfiguration configuration1 = new WifiConfiguration();
configuration1.SSID = TEST_SSID;
configuration1.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
WifiNetworkSuggestion suggestion1 =
- new WifiNetworkSuggestion(configuration1, null, false, false, TEST_UID,
+ new WifiNetworkSuggestion(configuration1, null, false, false, true, TEST_UID,
TEST_PACKAGE_NAME);
assertNotEquals(suggestion, suggestion1);
@@ -601,11 +610,11 @@ public class WifiNetworkSuggestionTest {
configuration.SSID = TEST_SSID;
configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
WifiNetworkSuggestion suggestion =
- new WifiNetworkSuggestion(configuration, null, false, false, TEST_UID,
+ new WifiNetworkSuggestion(configuration, null, false, false, true, TEST_UID,
TEST_PACKAGE_NAME);
WifiNetworkSuggestion suggestion1 =
- new WifiNetworkSuggestion(configuration, null, false, false, TEST_UID_OTHER,
+ new WifiNetworkSuggestion(configuration, null, false, false, true, TEST_UID_OTHER,
TEST_PACKAGE_NAME);
assertNotEquals(suggestion, suggestion1);
@@ -621,10 +630,10 @@ public class WifiNetworkSuggestionTest {
configuration.SSID = TEST_SSID;
configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
WifiNetworkSuggestion suggestion = new WifiNetworkSuggestion(
- configuration, null, false, false, TEST_UID, TEST_PACKAGE_NAME);
+ configuration, null, false, false, true, TEST_UID, TEST_PACKAGE_NAME);
WifiNetworkSuggestion suggestion1 = new WifiNetworkSuggestion(
- configuration, null, false, false, TEST_UID, TEST_PACKAGE_NAME_OTHER);
+ configuration, null, false, false, true, TEST_UID, TEST_PACKAGE_NAME_OTHER);
assertNotEquals(suggestion, suggestion1);
}
@@ -664,4 +673,17 @@ public class WifiNetworkSuggestionTest {
.build();
assertNotEquals(suggestion, suggestion1);
}
+
+ /**
+ * Ensure {@link WifiNetworkSuggestion.Builder#build()} throws an exception
+ * when {@link WifiNetworkSuggestion.Builder#setIsUserAllowedToManuallyConnect(boolean)} to
+ * true on a open network suggestion.
+ */
+ @Test(expected = IllegalStateException.class)
+ public void testSetIsUserAllowedToManuallyConnectToWithOpenNetwork() {
+ WifiNetworkSuggestion suggestion = new WifiNetworkSuggestion.Builder()
+ .setSsid(TEST_SSID)
+ .setIsUserAllowedToManuallyConnect(true)
+ .build();
+ }
}
diff --git a/wifi/tests/src/android/net/wifi/WifiScannerTest.java b/wifi/tests/src/android/net/wifi/WifiScannerTest.java
index f4fa38beaa40..b1436c90f5dd 100644
--- a/wifi/tests/src/android/net/wifi/WifiScannerTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiScannerTest.java
@@ -22,7 +22,9 @@ import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.validateMockitoUsage;
@@ -33,6 +35,7 @@ import android.content.Context;
import android.net.wifi.WifiScanner.PnoSettings;
import android.net.wifi.WifiScanner.PnoSettings.PnoNetwork;
import android.net.wifi.WifiScanner.ScanData;
+import android.net.wifi.WifiScanner.ScanListener;
import android.net.wifi.WifiScanner.ScanSettings;
import android.os.Bundle;
import android.os.Handler;
@@ -51,8 +54,10 @@ import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import org.mockito.Spy;
import java.util.Arrays;
+import java.util.concurrent.Executor;
/**
* Unit tests for {@link android.net.wifi.WifiScanner}.
@@ -63,6 +68,13 @@ public class WifiScannerTest {
private Context mContext;
@Mock
private IWifiScanner mService;
+ @Spy
+ private Executor mExecutor = new SynchronousExecutor();
+ @Mock
+ private ScanListener mScanListener;
+ @Mock
+ private WifiScanner.ParcelableScanData mParcelableScanData;
+ private ScanData[] mScanData = {};
private static final boolean TEST_PNOSETTINGS_IS_CONNECTED = false;
private static final int TEST_PNOSETTINGS_MIN_5GHZ_RSSI = -60;
@@ -76,6 +88,7 @@ public class WifiScannerTest {
private static final String TEST_SSID_2 = "TEST2";
private static final int[] TEST_FREQUENCIES_1 = {};
private static final int[] TEST_FREQUENCIES_2 = {2500, 5124};
+ private static final String DESCRIPTION_NOT_AUTHORIZED = "Not authorized";
private WifiScanner mWifiScanner;
private TestLooper mLooper;
@@ -95,6 +108,7 @@ public class WifiScannerTest {
when(mService.getMessenger()).thenReturn(mBidirectionalAsyncChannelServer.getMessenger());
mWifiScanner = new WifiScanner(mContext, mService, mLooper.getLooper());
mLooper.dispatchAll();
+ when(mParcelableScanData.getResults()).thenReturn(mScanData);
}
/**
@@ -111,7 +125,7 @@ public class WifiScannerTest {
@Test
public void verifyScanSettingsParcelWithBand() throws Exception {
ScanSettings writeSettings = new ScanSettings();
- writeSettings.type = WifiScanner.TYPE_LOW_POWER;
+ writeSettings.type = WifiScanner.SCAN_TYPE_LOW_POWER;
writeSettings.band = WifiScanner.WIFI_BAND_BOTH_WITH_DFS;
ScanSettings readSettings = parcelWriteRead(writeSettings);
@@ -126,7 +140,7 @@ public class WifiScannerTest {
@Test
public void verifyScanSettingsParcelWithChannels() throws Exception {
ScanSettings writeSettings = new ScanSettings();
- writeSettings.type = WifiScanner.TYPE_HIGH_ACCURACY;
+ writeSettings.type = WifiScanner.SCAN_TYPE_HIGH_ACCURACY;
writeSettings.band = WifiScanner.WIFI_BAND_UNSPECIFIED;
writeSettings.channels = new WifiScanner.ChannelSpec[] {
new WifiScanner.ChannelSpec(5),
@@ -243,13 +257,13 @@ public class WifiScannerTest {
/**
- * Test behavior of {@link WifiScanner#startScan(ScanSettings, WifiScanner.ScanListener)}
+ * Test behavior of {@link WifiScanner#startScan(ScanSettings, ScanListener)}
* @throws Exception
*/
@Test
public void testStartScan() throws Exception {
ScanSettings scanSettings = new ScanSettings();
- WifiScanner.ScanListener scanListener = mock(WifiScanner.ScanListener.class);
+ ScanListener scanListener = mock(ScanListener.class);
mWifiScanner.startScan(scanSettings, scanListener);
mLooper.dispatchAll();
@@ -273,13 +287,13 @@ public class WifiScannerTest {
}
/**
- * Test behavior of {@link WifiScanner#stopScan(WifiScanner.ScanListener)}
+ * Test behavior of {@link WifiScanner#stopScan(ScanListener)}
* @throws Exception
*/
@Test
public void testStopScan() throws Exception {
ScanSettings scanSettings = new ScanSettings();
- WifiScanner.ScanListener scanListener = mock(WifiScanner.ScanListener.class);
+ ScanListener scanListener = mock(ScanListener.class);
mWifiScanner.startScan(scanSettings, scanListener);
mLooper.dispatchAll();
@@ -302,13 +316,13 @@ public class WifiScannerTest {
}
/**
- * Test behavior of {@link WifiScanner#startScan(ScanSettings, WifiScanner.ScanListener)}
+ * Test behavior of {@link WifiScanner#startScan(ScanSettings, ScanListener)}
* @throws Exception
*/
@Test
public void testStartScanListenerOnSuccess() throws Exception {
ScanSettings scanSettings = new ScanSettings();
- WifiScanner.ScanListener scanListener = mock(WifiScanner.ScanListener.class);
+ ScanListener scanListener = mock(ScanListener.class);
mWifiScanner.startScan(scanSettings, scanListener);
mLooper.dispatchAll();
@@ -332,13 +346,13 @@ public class WifiScannerTest {
}
/**
- * Test behavior of {@link WifiScanner#startScan(ScanSettings, WifiScanner.ScanListener)}
+ * Test behavior of {@link WifiScanner#startScan(ScanSettings, ScanListener)}
* @throws Exception
*/
@Test
public void testStartScanListenerOnResults() throws Exception {
ScanSettings scanSettings = new ScanSettings();
- WifiScanner.ScanListener scanListener = mock(WifiScanner.ScanListener.class);
+ ScanListener scanListener = mock(ScanListener.class);
mWifiScanner.startScan(scanSettings, scanListener);
mLooper.dispatchAll();
@@ -425,7 +439,7 @@ public class WifiScannerTest {
}
/**
- * Test behavior of {@link WifiScanner#stopPnoScan(WifiScanner.ScanListener)}
+ * Test behavior of {@link WifiScanner#stopPnoScan(ScanListener)}
* WifiScanner.PnoScanListener)}
* @throws Exception
*/
@@ -480,4 +494,134 @@ public class WifiScannerTest {
assertEquals(scanData.getResults().length, readScanData.getResults().length);
assertEquals(scanData.getResults()[0].SSID, readScanData.getResults()[0].SSID);
}
+
+ /** Tests that upon registration success, {@link ScanListener#onSuccess()} is called. */
+ @Test
+ public void testRegisterScanListenerSuccess() throws Exception {
+ mWifiScanner.registerScanListener(mExecutor, mScanListener);
+ mLooper.dispatchAll();
+
+ ArgumentCaptor<Message> messageArgumentCaptor = ArgumentCaptor.forClass(Message.class);
+ verify(mHandler).handleMessage(messageArgumentCaptor.capture());
+ Message sentMessage = messageArgumentCaptor.getValue();
+ assertNotNull(sentMessage);
+
+ assertEquals(1, mBidirectionalAsyncChannelServer.getClientMessengers().size());
+ Messenger scannerMessenger =
+ mBidirectionalAsyncChannelServer.getClientMessengers().iterator().next();
+
+ Message responseMessage = Message.obtain();
+ responseMessage.what = WifiScanner.CMD_OP_SUCCEEDED;
+ responseMessage.arg2 = sentMessage.arg2;
+ scannerMessenger.send(responseMessage);
+ mLooper.dispatchAll();
+
+ verify(mExecutor).execute(any());
+ verify(mScanListener).onSuccess();
+ }
+
+ /**
+ * Tests that upon registration failed, {@link ScanListener#onFailure(int, String)} is called.
+ */
+ @Test
+ public void testRegisterScanListenerFailed() throws Exception {
+ mWifiScanner.registerScanListener(mExecutor, mScanListener);
+ mLooper.dispatchAll();
+
+ ArgumentCaptor<Message> messageArgumentCaptor = ArgumentCaptor.forClass(Message.class);
+ verify(mHandler).handleMessage(messageArgumentCaptor.capture());
+ Message sentMessage = messageArgumentCaptor.getValue();
+ assertNotNull(sentMessage);
+
+ assertEquals(1, mBidirectionalAsyncChannelServer.getClientMessengers().size());
+ Messenger scannerMessenger =
+ mBidirectionalAsyncChannelServer.getClientMessengers().iterator().next();
+
+ {
+ Message responseMessage = Message.obtain();
+ responseMessage.what = WifiScanner.CMD_OP_FAILED;
+ responseMessage.arg2 = sentMessage.arg2;
+ responseMessage.obj = new WifiScanner.OperationResult(
+ WifiScanner.REASON_NOT_AUTHORIZED, DESCRIPTION_NOT_AUTHORIZED);
+ scannerMessenger.send(responseMessage);
+ mLooper.dispatchAll();
+ }
+
+ verify(mExecutor).execute(any());
+ verify(mScanListener).onFailure(
+ WifiScanner.REASON_NOT_AUTHORIZED, DESCRIPTION_NOT_AUTHORIZED);
+
+ // CMD_OP_FAILED should have caused the removal of the listener, verify this
+ {
+ Message responseMessage = Message.obtain();
+ responseMessage.what = WifiScanner.CMD_SCAN_RESULT;
+ responseMessage.arg2 = sentMessage.arg2;
+ responseMessage.obj = mParcelableScanData;
+ scannerMessenger.send(responseMessage);
+ mLooper.dispatchAll();
+ }
+ // execute() called once before, not called again
+ verify(mExecutor, times(1)).execute(any());
+ // onResults() never triggered
+ verify(mScanListener, never()).onResults(any());
+ }
+
+ /**
+ * Tests that when the ScanListener is triggered, {@link ScanListener#onResults(ScanData[])}
+ * is called.
+ */
+ @Test
+ public void testRegisterScanListenerReceiveScanResults() throws Exception {
+ mWifiScanner.registerScanListener(mExecutor, mScanListener);
+ mLooper.dispatchAll();
+
+ ArgumentCaptor<Message> messageArgumentCaptor = ArgumentCaptor.forClass(Message.class);
+ verify(mHandler).handleMessage(messageArgumentCaptor.capture());
+ Message sentMessage = messageArgumentCaptor.getValue();
+ assertNotNull(sentMessage);
+
+ assertEquals(1, mBidirectionalAsyncChannelServer.getClientMessengers().size());
+ Messenger scannerMessenger =
+ mBidirectionalAsyncChannelServer.getClientMessengers().iterator().next();
+
+ Message responseMessage = Message.obtain();
+ responseMessage.what = WifiScanner.CMD_SCAN_RESULT;
+ responseMessage.arg2 = sentMessage.arg2;
+ responseMessage.obj = mParcelableScanData;
+ scannerMessenger.send(responseMessage);
+ mLooper.dispatchAll();
+
+ verify(mExecutor).execute(any());
+ verify(mScanListener).onResults(mScanData);
+ }
+
+ /**
+ * Tests that after unregistering a scan listener, {@link ScanListener#onResults(ScanData[])}
+ * is not called.
+ */
+ @Test
+ public void testUnregisterScanListener() throws Exception {
+ mWifiScanner.registerScanListener(mExecutor, mScanListener);
+ mWifiScanner.unregisterScanListener(mScanListener);
+ mLooper.dispatchAll();
+
+ assertEquals(1, mBidirectionalAsyncChannelServer.getClientMessengers().size());
+ Messenger scannerMessenger =
+ mBidirectionalAsyncChannelServer.getClientMessengers().iterator().next();
+
+ ArgumentCaptor<Message> messageArgumentCaptor = ArgumentCaptor.forClass(Message.class);
+ verify(mHandler, times(2)).handleMessage(messageArgumentCaptor.capture());
+ Message sentMessage = messageArgumentCaptor.getValue();
+ assertNotNull(sentMessage);
+
+ Message responseMessage = Message.obtain();
+ responseMessage.what = WifiScanner.CMD_SCAN_RESULT;
+ responseMessage.obj = mParcelableScanData;
+ responseMessage.arg2 = sentMessage.arg2;
+ scannerMessenger.send(responseMessage);
+ mLooper.dispatchAll();
+
+ verify(mExecutor, never()).execute(any());
+ verify(mScanListener, never()).onResults(mScanData);
+ }
}