summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ApiDocs.bp2
-rw-r--r--apct-tests/perftests/autofill/Android.bp3
-rw-r--r--apct-tests/perftests/autofill/AndroidManifest.xml5
-rw-r--r--apct-tests/perftests/autofill/AndroidTest.xml32
-rw-r--r--apct-tests/perftests/textclassifier/Android.bp2
-rw-r--r--apct-tests/perftests/textclassifier/AndroidTest.xml32
-rw-r--r--apct-tests/perftests/textclassifier/src/android/view/textclassifier/TextClassifierPerfTest.java88
-rw-r--r--api/current.txt1
-rwxr-xr-xapi/system-current.txt7
-rw-r--r--cmds/bootanimation/BootAnimation.cpp4
-rw-r--r--cmds/screencap/screencap.cpp9
-rw-r--r--cmds/uiautomator/library/Android.bp2
-rw-r--r--config/hiddenapi-force-blocked.txt (renamed from config/hiddenapi-force-blacklist.txt)0
-rw-r--r--config/hiddenapi-max-target-o.txt (renamed from config/hiddenapi-greylist-max-o.txt)0
-rw-r--r--config/hiddenapi-max-target-p.txt (renamed from config/hiddenapi-greylist-max-p.txt)0
-rw-r--r--config/hiddenapi-max-target-q.txt (renamed from config/hiddenapi-greylist-max-q.txt)0
-rw-r--r--config/hiddenapi-unsupported-packages.txt (renamed from config/hiddenapi-greylist-packages.txt)0
-rw-r--r--config/hiddenapi-unsupported.txt (renamed from config/hiddenapi-greylist.txt)0
-rw-r--r--core/java/android/app/Activity.java2
-rw-r--r--core/java/android/app/ActivityManagerInternal.java3
-rw-r--r--core/java/android/app/PropertyInvalidatedCache.java65
-rw-r--r--core/java/android/app/UiModeManager.java3
-rw-r--r--core/java/android/app/people/ConversationChannel.java97
-rw-r--r--core/java/android/app/people/IPeopleManager.aidl42
-rw-r--r--core/java/android/app/timezonedetector/TimeZoneDetectorImpl.java2
-rw-r--r--core/java/android/content/Context.java9
-rw-r--r--core/java/android/content/pm/ActivityInfo.java6
-rw-r--r--core/java/android/content/pm/PackageInstaller.java9
-rw-r--r--core/java/android/content/pm/PackageManager.java6
-rw-r--r--core/java/android/os/BatteryStats.java17
-rw-r--r--core/java/android/permission/PermissionManager.java4
-rw-r--r--core/java/android/provider/Settings.java7
-rw-r--r--core/java/android/view/InputApplicationHandle.java4
-rw-r--r--core/java/android/view/InputWindowHandle.java2
-rw-r--r--core/java/android/view/View.java2
-rw-r--r--core/java/android/view/ViewRootImpl.java25
-rw-r--r--core/java/android/widget/Editor.java22
-rw-r--r--core/java/android/widget/EditorTouchState.java55
-rw-r--r--core/java/android/widget/WidgetFlags.java22
-rw-r--r--core/java/android/widget/inline/InlineContentView.java2
-rw-r--r--core/java/com/android/internal/app/ChooserActivity.java4
-rw-r--r--core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java7
-rw-r--r--core/java/com/android/internal/os/BatterySipper.java5
-rw-r--r--core/java/com/android/internal/os/BatteryStatsHelper.java8
-rw-r--r--core/java/com/android/internal/os/BatteryStatsImpl.java460
-rw-r--r--core/java/com/android/internal/os/BinderCallsStats.java3
-rw-r--r--core/java/com/android/internal/os/BinderInternal.java3
-rw-r--r--core/java/com/android/internal/os/KernelCpuThreadReader.java32
-rw-r--r--core/java/com/android/internal/os/SystemServerCpuThreadReader.java151
-rw-r--r--core/java/com/android/internal/os/SystemServicePowerCalculator.java91
-rw-r--r--core/java/com/android/internal/os/logging/MetricsLoggerWrapper.java81
-rw-r--r--core/jni/android_hardware_input_InputApplicationHandle.cpp11
-rw-r--r--core/jni/android_hardware_input_InputWindowHandle.cpp10
-rw-r--r--core/jni/android_view_DisplayEventReceiver.cpp13
-rw-r--r--core/jni/android_view_SurfaceControl.cpp5
-rw-r--r--core/tests/coretests/src/android/widget/EditorCursorDragTest.java32
-rw-r--r--core/tests/coretests/src/android/widget/EditorTouchStateTest.java105
-rw-r--r--core/tests/coretests/src/com/android/internal/os/BatteryStatsBinderCallStatsTest.java66
-rw-r--r--core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java4
-rw-r--r--core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java6
-rw-r--r--core/tests/coretests/src/com/android/internal/os/SystemServerCpuThreadReaderTest.java136
-rw-r--r--core/tests/coretests/src/com/android/internal/os/SystemServicePowerCalculatorTest.java173
-rw-r--r--data/etc/privapp-permissions-platform.xml12
-rw-r--r--errorprone/java/com/google/errorprone/bugpatterns/android/UidChecker.java18
-rw-r--r--errorprone/tests/java/com/google/errorprone/bugpatterns/android/UidCheckerTest.java71
-rw-r--r--libs/hwui/jni/Shader.cpp9
-rw-r--r--location/java/android/location/LocationManagerInternal.java36
-rw-r--r--location/java/android/location/LocationRequest.java56
-rwxr-xr-xmedia/java/android/media/AudioManager.java65
-rw-r--r--non-updatable-api/current.txt1
-rw-r--r--non-updatable-api/system-current.txt7
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/sideloaded/SideLoadedAppDetector.java2
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/wm/BarControlPolicy.java36
-rw-r--r--packages/CarSystemUI/tests/src/com/android/AAAPlusPlusVerifySysuiRequiredTestPropertiesTest.java6
-rw-r--r--packages/CarSystemUI/tests/src/com/android/systemui/car/voicerecognition/ConnectedDeviceVoiceRecognitionNotifierTest.java33
-rw-r--r--packages/FakeOemFeatures/src/com/android/fakeoemfeatures/FakeView.java2
-rw-r--r--packages/SettingsLib/Tile/src/com/android/settingslib/drawer/PrimarySwitchController.java (renamed from packages/SettingsLib/Tile/src/com/android/settingslib/drawer/MasterSwitchController.java)4
-rw-r--r--packages/SettingsLib/Tile/src/com/android/settingslib/drawer/SwitchesProvider.java4
-rw-r--r--packages/SettingsLib/res/values-af/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-am/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-ar/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-as/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-az/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-b+sr+Latn/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-be/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-bg/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-bn/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-bs/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-ca/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-cs/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-da/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-de/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-el/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-en-rAU/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-en-rCA/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-en-rGB/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-en-rIN/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-en-rXC/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-es-rUS/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-es/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-et/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-eu/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-fa/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-fi/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-fr-rCA/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-fr/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-gl/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-gu/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-hi/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-hr/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-hu/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-hy/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-in/arrays.xml2
-rw-r--r--packages/SettingsLib/res/values-in/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-is/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-it/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-iw/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-ja/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-ka/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-kk/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-km/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-kn/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-ko/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-ky/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-lo/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-lt/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-lv/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-mk/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-ml/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-mn/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-mr/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-ms/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-my/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-nb/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-ne/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-nl/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-or/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-pa/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-pl/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-pt-rBR/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-pt-rPT/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-pt/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-ro/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-ru/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-si/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-sk/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-sl/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-sq/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-sr/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-sv/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-sw/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-ta/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-te/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-th/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-tl/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-tr/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-uk/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-ur/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-uz/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-vi/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-zh-rCN/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-zh-rHK/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-zh-rTW/strings.xml1
-rw-r--r--packages/SettingsLib/res/values-zu/strings.xml1
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/development/DeveloperOptionsPreferenceController.java2
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/fuelgauge/PowerAllowlistBackend.java (renamed from packages/SettingsLib/src/com/android/settingslib/fuelgauge/PowerWhitelistBackend.java)84
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/users/AppRestrictionsHelper.java10
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedLockUtilsTest.java4
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/PrimarySwitchControllerTest.java (renamed from packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/MasterSwitchControllerTest.java)10
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/SwitchesProviderTest.java6
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/PowerAllowlistBackendTest.java (renamed from packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/PowerWhitelistBackendTest.java)76
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/inputmethod/InputMethodAndSubtypeUtilCompatTest.java30
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/inputmethod/InputMethodAndSubtypeUtilTest.java28
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java1
-rw-r--r--packages/Shell/AndroidManifest.xml13
-rw-r--r--packages/SimAppDialog/Android.bp3
-rw-r--r--packages/SimAppDialog/AndroidManifest.xml2
-rw-r--r--packages/SimAppDialog/res/layout/install_carrier_app_activity.xml19
-rw-r--r--packages/SimAppDialog/res/layout/install_carrier_app_footer.xml43
-rw-r--r--packages/SimAppDialog/res/values/styles.xml26
-rw-r--r--packages/SimAppDialog/src/com/android/simappdialog/InstallCarrierAppActivity.java60
-rw-r--r--packages/SystemUI/res/layout/media_view.xml98
-rw-r--r--packages/SystemUI/res/layout/qs_media_panel_options.xml61
-rw-r--r--packages/SystemUI/res/values/config.xml10
-rw-r--r--packages/SystemUI/res/values/strings.xml2
-rw-r--r--packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java79
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java73
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/CustomIconCache.kt76
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/management/ControlsEditingActivity.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/management/ControlsModel.kt19
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/management/FavoritesModel.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt9
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaCarouselScrollHandler.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java58
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt22
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt7
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaViewController.kt69
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/PlayerViewHolder.kt36
-rw-r--r--packages/SystemUI/src/com/android/systemui/onehanded/OneHandedTutorialHandler.java43
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java18
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/PipUiEventLogger.java97
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java22
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java19
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java48
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt64
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java52
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/UiModeNightTile.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/settings/CurrentUserContentResolverProvider.kt24
-rw-r--r--packages/SystemUI/src/com/android/systemui/settings/CurrentUserContextTracker.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/settings/dagger/SettingsModule.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java16
-rw-r--r--packages/SystemUI/src/com/android/systemui/stackdivider/DividerController.java36
-rw-r--r--packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivityController.java53
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/usb/UsbAccessoryUriActivity.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/controls/CustomIconCacheTest.kt101
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/controls/management/FavoritesModelTest.kt15
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt101
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt14
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/MediaHierarchyManagerTest.kt7
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/pip/phone/PipTouchHandlerTest.java6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerFlagsTest.kt219
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerTest.kt76
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ScreenRecordTileTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragmentTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CallbackControllerTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/LifecycleFragmentTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/SysuiLifecycleTest.java2
-rw-r--r--packages/Tethering/res/values/config.xml3
-rw-r--r--packages/Tethering/res/values/overlayable.xml1
-rw-r--r--packages/Tethering/src/com/android/networkstack/tethering/PrivateAddressCoordinator.java19
-rw-r--r--packages/Tethering/src/com/android/networkstack/tethering/Tethering.java5
-rw-r--r--packages/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java16
-rw-r--r--packages/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java53
-rw-r--r--packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringConfigurationTest.java15
-rw-r--r--proto/src/metrics_constants/metrics_constants.proto23
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java87
-rw-r--r--services/core/Android.bp1
-rw-r--r--services/core/java/android/os/BatteryStatsInternal.java2
-rw-r--r--services/core/java/com/android/server/UiModeManagerService.java24
-rw-r--r--services/core/java/com/android/server/VibratorService.java95
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java36
-rw-r--r--services/core/java/com/android/server/am/BatteryStatsService.java5
-rw-r--r--services/core/java/com/android/server/am/CoreSettingsObserver.java4
-rw-r--r--services/core/java/com/android/server/am/OomAdjuster.java14
-rw-r--r--services/core/java/com/android/server/am/PendingTempWhitelists.java4
-rw-r--r--services/core/java/com/android/server/am/ProcessRecord.java162
-rw-r--r--services/core/java/com/android/server/am/ProcessStatsService.java287
-rw-r--r--services/core/java/com/android/server/am/ServiceRecord.java8
-rw-r--r--services/core/java/com/android/server/appop/AppOpsService.java1
-rw-r--r--services/core/java/com/android/server/audio/AudioDeviceBroker.java37
-rwxr-xr-xservices/core/java/com/android/server/audio/AudioService.java24
-rw-r--r--services/core/java/com/android/server/audio/BtHelper.java44
-rw-r--r--services/core/java/com/android/server/connectivity/Vpn.java261
-rw-r--r--services/core/java/com/android/server/input/InputManagerService.java102
-rw-r--r--services/core/java/com/android/server/location/LocationFudger.java4
-rw-r--r--services/core/java/com/android/server/location/LocationManagerService.java2246
-rw-r--r--services/core/java/com/android/server/location/LocationManagerServiceUtils.java73
-rw-r--r--services/core/java/com/android/server/location/LocationProviderManager.java1951
-rw-r--r--services/core/java/com/android/server/location/MockProvider.java3
-rw-r--r--services/core/java/com/android/server/location/MockableLocationProvider.java1
-rw-r--r--services/core/java/com/android/server/location/PassiveLocationProviderManager.java60
-rw-r--r--services/core/java/com/android/server/location/gnss/GnssListenerMultiplexer.java22
-rw-r--r--services/core/java/com/android/server/location/gnss/GnssNetworkConnectivityHandler.java2
-rw-r--r--services/core/java/com/android/server/location/listeners/ListenerMultiplexer.java40
-rw-r--r--services/core/java/com/android/server/location/listeners/ListenerRegistration.java14
-rw-r--r--services/core/java/com/android/server/location/listeners/RemovableListenerRegistration.java2
-rw-r--r--services/core/java/com/android/server/media/HandlerExecutor.java45
-rw-r--r--services/core/java/com/android/server/media/MediaSession2Record.java1
-rw-r--r--services/core/java/com/android/server/pm/ApexManager.java19
-rw-r--r--services/core/java/com/android/server/pm/OWNERS20
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerService.java8
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerSession.java52
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java220
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerShellCommand.java10
-rw-r--r--services/core/java/com/android/server/pm/PackageSetting.java4
-rw-r--r--services/core/java/com/android/server/pm/PackageSettingBase.java37
-rw-r--r--services/core/java/com/android/server/pm/Settings.java117
-rw-r--r--services/core/java/com/android/server/pm/ShortcutService.java72
-rw-r--r--services/core/java/com/android/server/pm/StagingManager.java185
-rw-r--r--services/core/java/com/android/server/pm/UserManagerService.java7
-rw-r--r--services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java174
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java17
-rw-r--r--services/core/java/com/android/server/wm/ActivityStackSupervisor.java13
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java4
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskManagerService.java65
-rw-r--r--services/core/java/com/android/server/wm/DragState.java8
-rw-r--r--services/core/java/com/android/server/wm/InputConsumerImpl.java8
-rw-r--r--services/core/java/com/android/server/wm/InputManagerCallback.java23
-rw-r--r--services/core/java/com/android/server/wm/InputMonitor.java7
-rw-r--r--services/core/java/com/android/server/wm/Letterbox.java4
-rw-r--r--services/core/java/com/android/server/wm/LockTaskController.java44
-rw-r--r--services/core/java/com/android/server/wm/PolicyControl.java42
-rw-r--r--services/core/java/com/android/server/wm/RecentTasks.java3
-rw-r--r--services/core/java/com/android/server/wm/RootWindowContainer.java2
-rw-r--r--services/core/java/com/android/server/wm/SafeActivityOptions.java4
-rw-r--r--services/core/java/com/android/server/wm/Task.java20
-rw-r--r--services/core/java/com/android/server/wm/TaskPositioner.java8
-rw-r--r--services/core/java/com/android/server/wm/TaskSnapshotSurface.java14
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java6
-rw-r--r--services/core/java/com/android/server/wm/WindowProcessController.java15
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java7
-rw-r--r--services/core/jni/Android.bp1
-rw-r--r--services/core/jni/com_android_server_VibratorService.cpp248
-rw-r--r--services/core/jni/com_android_server_input_InputManagerService.cpp5
-rw-r--r--services/java/com/android/server/SystemServer.java10
-rw-r--r--services/people/java/com/android/server/people/PeopleService.java39
-rw-r--r--services/tests/PackageManagerComponentOverrideTests/src/com/android/server/pm/test/override/PackageManagerComponentLabelIconOverrideTest.kt3
-rw-r--r--services/tests/PackageManagerServiceTests/host/Android.bp33
-rw-r--r--services/tests/PackageManagerServiceTests/host/resources/PackageManagerDummyAppVersion3Invalid.apkbin2457 -> 0 bytes
-rw-r--r--services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/HostUtils.kt56
-rw-r--r--services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/InvalidNewSystemAppTest.kt16
-rw-r--r--services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/OriginalPackageMigrationTest.kt17
-rw-r--r--services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/SystemStubMultiUserDisableUninstallTest.kt650
-rw-r--r--services/tests/PackageManagerServiceTests/host/test-apps/Android.bp16
-rw-r--r--services/tests/PackageManagerServiceTests/host/test-apps/AndroidManifestOriginalOverride.xml4
-rw-r--r--services/tests/PackageManagerServiceTests/host/test-apps/AndroidManifestVersion1.xml4
-rw-r--r--services/tests/PackageManagerServiceTests/host/test-apps/AndroidManifestVersion2.xml4
-rw-r--r--services/tests/PackageManagerServiceTests/host/test-apps/AndroidManifestVersion3.xml4
-rw-r--r--services/tests/PackageManagerServiceTests/host/test-apps/AndroidManifestVersion4.xml4
-rw-r--r--services/tests/mockingservicestests/AndroidManifest.xml2
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java3
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java10
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/location/LocationProviderManagerTest.java971
-rw-r--r--services/tests/servicestests/src/com/android/server/VibratorServiceTest.java9
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/KeySetManagerServiceTest.java3
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java3
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java40
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java3
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/PackageSettingBuilder.java14
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/PackageSignaturesTest.java6
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/ScanTests.java6
-rw-r--r--services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorServiceTest.java2
-rw-r--r--services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java14
-rw-r--r--services/tests/wmtests/AndroidManifest.xml1
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java52
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/LockTaskControllerTest.java162
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java3
-rw-r--r--startop/OWNERS2
-rw-r--r--test-runner/src/android/test/AndroidTestRunner.java2
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt2
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt2
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/OpenAppToSplitScreenTest.kt5
-rw-r--r--tests/HwAccelerationTest/src/com/android/test/hwui/ColorFiltersMutateActivity.java2
-rw-r--r--tests/Input/Android.bp12
-rw-r--r--tests/Input/AndroidManifest.xml35
-rw-r--r--tests/Input/AndroidTest.xml25
-rw-r--r--tests/Input/src/com/android/test/input/AnrTest.kt115
-rw-r--r--tests/Input/src/com/android/test/input/UnresponsiveGestureMonitorActivity.kt52
-rw-r--r--tests/StagedInstallTest/Android.bp1
-rw-r--r--tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java8
-rw-r--r--tests/net/java/com/android/server/connectivity/VpnTest.java189
-rw-r--r--tests/utils/hostutils/src/com/android/internal/util/test/SystemPreparer.java23
-rw-r--r--wifi/java/android/net/wifi/IWifiManager.aidl6
-rw-r--r--wifi/java/android/net/wifi/WifiManager.java6
-rw-r--r--wifi/tests/src/android/net/wifi/WifiManagerTest.java20
373 files changed, 10049 insertions, 4562 deletions
diff --git a/ApiDocs.bp b/ApiDocs.bp
index 029699efe3b9..ca921ff97c35 100644
--- a/ApiDocs.bp
+++ b/ApiDocs.bp
@@ -150,12 +150,10 @@ doc_defaults {
":current-support-api",
":current-androidx-api",
],
- create_stubs: false,
}
doc_defaults {
name: "framework-dokka-docs-default",
- create_stubs: false,
}
droiddoc {
diff --git a/apct-tests/perftests/autofill/Android.bp b/apct-tests/perftests/autofill/Android.bp
index 9ac8c87d3de0..4f6c21af9281 100644
--- a/apct-tests/perftests/autofill/Android.bp
+++ b/apct-tests/perftests/autofill/Android.bp
@@ -20,8 +20,9 @@ android_test {
"androidx.test.rules",
"androidx.annotation_annotation",
"apct-perftests-utils",
- "collector-device-lib-platform",
+ "collector-device-lib",
],
platform_apis: true,
test_suites: ["device-tests"],
+ data: [":perfetto_artifacts"],
}
diff --git a/apct-tests/perftests/autofill/AndroidManifest.xml b/apct-tests/perftests/autofill/AndroidManifest.xml
index 51f6a76b2782..57595a213d20 100644
--- a/apct-tests/perftests/autofill/AndroidManifest.xml
+++ b/apct-tests/perftests/autofill/AndroidManifest.xml
@@ -16,11 +16,6 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.perftests.autofill">
- <uses-sdk android:targetSdkVersion="28" />
-
- <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
- <uses-permission android:name="android.permission.REAL_GET_TASKS" />
-
<application>
<uses-library android:name="android.test.runner" />
<activity android:name="android.perftests.utils.PerfTestActivity"
diff --git a/apct-tests/perftests/autofill/AndroidTest.xml b/apct-tests/perftests/autofill/AndroidTest.xml
index 29f9f94bcac7..eee7bdc3e330 100644
--- a/apct-tests/perftests/autofill/AndroidTest.xml
+++ b/apct-tests/perftests/autofill/AndroidTest.xml
@@ -21,8 +21,40 @@
<option name="test-file-name" value="AutofillPerfTests.apk" />
</target_preparer>
+ <!-- Needed for pushing the trace config file -->
+ <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
+ <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+ <option name="push-file" key="trace_config_detailed.textproto" value="/data/misc/perfetto-traces/trace_config.textproto" />
+ </target_preparer>
+
+ <!-- Needed for pulling the collected trace config on to the host -->
+ <metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
+ <option name="pull-pattern-keys" value="perfetto_file_path" />
+ </metrics_collector>
+
+ <!-- Needed for storing the perfetto trace files in the sdcard/test_results-->
+ <option name="isolated-storage" value="false" />
+
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="package" value="com.android.perftests.autofill" />
<option name="hidden-api-checks" value="false"/>
+
+ <!-- Listener related args for collecting the traces and waiting for the device to stabilize. -->
+ <option name="device-listeners" value="android.device.collectors.ProcLoadListener,android.device.collectors.PerfettoListener" />
+ <!-- Guarantee that user defined RunListeners will be running before any of the default listeners defined in this runner. -->
+ <option name="instrumentation-arg" key="newRunListenerMode" value="true" />
+
+ <!-- ProcLoadListener related arguments -->
+ <!-- Wait for device last minute threshold to reach 3 with 2 minute timeout before starting the test run -->
+ <option name="instrumentation-arg" key="procload-collector:per_run" value="true" />
+ <option name="instrumentation-arg" key="proc-loadavg-threshold" value="3" />
+ <option name="instrumentation-arg" key="proc-loadavg-timeout" value="120000" />
+ <option name="instrumentation-arg" key="proc-loadavg-interval" value="10000" />
+
+ <!-- PerfettoListener related arguments -->
+ <option name="instrumentation-arg" key="perfetto_config_text_proto" value="true" />
+ <option name="instrumentation-arg" key="perfetto_config_file" value="trace_config.textproto" />
+
+ <option name="instrumentation-arg" key="newRunListenerMode" value="true" />
</test>
</configuration>
diff --git a/apct-tests/perftests/textclassifier/Android.bp b/apct-tests/perftests/textclassifier/Android.bp
index 49952dc1d009..c40e0252cb7e 100644
--- a/apct-tests/perftests/textclassifier/Android.bp
+++ b/apct-tests/perftests/textclassifier/Android.bp
@@ -19,7 +19,9 @@ android_test {
"androidx.test.rules",
"androidx.annotation_annotation",
"apct-perftests-utils",
+ "collector-device-lib",
],
+ data: [":perfetto_artifacts"],
platform_apis: true,
test_suites: ["device-tests"],
}
diff --git a/apct-tests/perftests/textclassifier/AndroidTest.xml b/apct-tests/perftests/textclassifier/AndroidTest.xml
index 3df51b8ae67a..3fac462448f0 100644
--- a/apct-tests/perftests/textclassifier/AndroidTest.xml
+++ b/apct-tests/perftests/textclassifier/AndroidTest.xml
@@ -21,8 +21,40 @@
<option name="test-file-name" value="TextClassifierPerfTests.apk" />
</target_preparer>
+ <!-- Needed for pushing the trace config file -->
+ <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
+ <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+ <option name="push-file" key="trace_config_detailed.textproto" value="/data/misc/perfetto-traces/trace_config.textproto" />
+ </target_preparer>
+
+ <!-- Needed for pulling the collected trace config on to the host -->
+ <metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
+ <option name="pull-pattern-keys" value="perfetto_file_path" />
+ </metrics_collector>
+
+ <!-- Needed for storing the perfetto trace files in the sdcard/test_results-->
+ <option name="isolated-storage" value="false" />
+
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="package" value="com.android.perftests.textclassifier" />
<option name="hidden-api-checks" value="false"/>
+
+ <!-- Listener related args for collecting the traces and waiting for the device to stabilize. -->
+ <option name="device-listeners" value="android.device.collectors.ProcLoadListener,android.device.collectors.PerfettoListener" />
+ <!-- Guarantee that user defined RunListeners will be running before any of the default listeners defined in this runner. -->
+ <option name="instrumentation-arg" key="newRunListenerMode" value="true" />
+
+ <!-- ProcLoadListener related arguments -->
+ <!-- Wait for device last minute threshold to reach 3 with 2 minute timeout before starting the test run -->
+ <option name="instrumentation-arg" key="procload-collector:per_run" value="true" />
+ <option name="instrumentation-arg" key="proc-loadavg-threshold" value="3" />
+ <option name="instrumentation-arg" key="proc-loadavg-timeout" value="120000" />
+ <option name="instrumentation-arg" key="proc-loadavg-interval" value="10000" />
+
+ <!-- PerfettoListener related arguments -->
+ <option name="instrumentation-arg" key="perfetto_config_text_proto" value="true" />
+ <option name="instrumentation-arg" key="perfetto_config_file" value="trace_config.textproto" />
+
+ <option name="instrumentation-arg" key="newRunListenerMode" value="true" />
</test>
</configuration>
diff --git a/apct-tests/perftests/textclassifier/src/android/view/textclassifier/TextClassifierPerfTest.java b/apct-tests/perftests/textclassifier/src/android/view/textclassifier/TextClassifierPerfTest.java
index 14a121d60c2e..324def83785f 100644
--- a/apct-tests/perftests/textclassifier/src/android/view/textclassifier/TextClassifierPerfTest.java
+++ b/apct-tests/perftests/textclassifier/src/android/view/textclassifier/TextClassifierPerfTest.java
@@ -18,6 +18,7 @@ package android.view.textclassifier;
import android.content.Context;
import android.perftests.utils.BenchmarkState;
import android.perftests.utils.PerfStatusReporter;
+import android.service.textclassifier.TextClassifierService;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.LargeTest;
@@ -25,86 +26,85 @@ import androidx.test.filters.LargeTest;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-import java.util.Arrays;
-import java.util.Collection;
import java.util.Collections;
-import java.util.Random;
-@RunWith(Parameterized.class)
@LargeTest
public class TextClassifierPerfTest {
- /** Request contains meaning text, rather than garbled text. */
- private static final int ACTUAL_REQUEST = 0;
- private static final String RANDOM_CHAR_SET = "abcdefghijklmnopqrstuvwxyz0123456789";
+ private static final String TEXT = " Oh hi Mark, the number is (323) 654-6192.\n"
+ + "Anyway, I'll meet you at 1600 Pennsylvania Avenue NW.\n"
+ + "My flight is LX 38 and I'll arrive at 8:00pm.\n"
+ + "Also, check out www.google.com.\n";
@Rule
public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
- @Parameterized.Parameters(name = "size{0}")
- public static Collection<Object[]> data() {
- return Arrays.asList(new Object[][]{{ACTUAL_REQUEST}, {10}, {100}, {1000}});
- }
-
private TextClassifier mTextClassifier;
- private final int mSize;
-
- public TextClassifierPerfTest(int size) {
- mSize = size;
- }
@Before
public void setUp() {
Context context = InstrumentationRegistry.getTargetContext();
- TextClassificationManager textClassificationManager =
- context.getSystemService(TextClassificationManager.class);
- mTextClassifier = textClassificationManager.getTextClassifier(TextClassifier.LOCAL);
+ mTextClassifier = TextClassifierService.getDefaultTextClassifierImplementation(context);
}
@Test
- public void testSuggestConversationActions() {
- String text = mSize == ACTUAL_REQUEST ? "Where are you?" : generateRandomString(mSize);
- ConversationActions.Request request = createConversationActionsRequest(text);
+ public void testClassifyText() {
+ TextClassification.Request request =
+ new TextClassification.Request.Builder(TEXT, 0, TEXT.length()).build();
BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
- mTextClassifier.suggestConversationActions(request);
+ mTextClassifier.classifyText(request);
}
}
@Test
- public void testDetectLanguage() {
- String text = mSize == ACTUAL_REQUEST
- ? "これは日本語のテキストです" : generateRandomString(mSize);
- TextLanguage.Request request = createTextLanguageRequest(text);
+ public void testSuggestSelection() {
+ // Trying to select the phone number.
+ TextSelection.Request request =
+ new TextSelection.Request.Builder(
+ TEXT,
+ /* startIndex= */ 28,
+ /* endIndex= */29)
+ .build();
BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
- mTextClassifier.detectLanguage(request);
+ mTextClassifier.suggestSelection(request);
}
}
- private static ConversationActions.Request createConversationActionsRequest(CharSequence text) {
+ @Test
+ public void testGenerateLinks() {
+ TextLinks.Request request =
+ new TextLinks.Request.Builder(TEXT).build();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ mTextClassifier.generateLinks(request);
+ }
+ }
+
+ @Test
+ public void testSuggestConversationActions() {
ConversationActions.Message message =
new ConversationActions.Message.Builder(
ConversationActions.Message.PERSON_USER_OTHERS)
- .setText(text)
+ .setText(TEXT)
.build();
- return new ConversationActions.Request.Builder(Collections.singletonList(message))
+ ConversationActions.Request request = new ConversationActions.Request.Builder(
+ Collections.singletonList(message))
.build();
- }
- private static TextLanguage.Request createTextLanguageRequest(CharSequence text) {
- return new TextLanguage.Request.Builder(text).build();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ mTextClassifier.suggestConversationActions(request);
+ }
}
- private static String generateRandomString(int length) {
- Random random = new Random();
- StringBuilder stringBuilder = new StringBuilder(length);
- for (int i = 0; i < length; i++) {
- int index = random.nextInt(RANDOM_CHAR_SET.length());
- stringBuilder.append(RANDOM_CHAR_SET.charAt(index));
+ @Test
+ public void testDetectLanguage() {
+ TextLanguage.Request request = new TextLanguage.Request.Builder(TEXT).build();
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ mTextClassifier.detectLanguage(request);
}
- return stringBuilder.toString();
}
}
diff --git a/api/current.txt b/api/current.txt
index 09de005c008c..b70103b931d4 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -11900,6 +11900,7 @@ package android.content.pm {
field public static final int INVALID_ID = -1; // 0xffffffff
field public static final int STAGED_SESSION_ACTIVATION_FAILED = 2; // 0x2
field public static final int STAGED_SESSION_NO_ERROR = 0; // 0x0
+ field public static final int STAGED_SESSION_OTHER_ERROR = 4; // 0x4
field public static final int STAGED_SESSION_UNKNOWN = 3; // 0x3
field public static final int STAGED_SESSION_VERIFICATION_FAILED = 1; // 0x1
}
diff --git a/api/system-current.txt b/api/system-current.txt
index fb0d924673b8..56059dd9d864 100755
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -4201,6 +4201,7 @@ package android.media {
method @IntRange(from=0) public long getAdditionalOutputDeviceDelay(@NonNull android.media.AudioDeviceInfo);
method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public static java.util.List<android.media.audiopolicy.AudioProductStrategy> getAudioProductStrategies();
method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public static java.util.List<android.media.audiopolicy.AudioVolumeGroup> getAudioVolumeGroups();
+ method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int getDeviceVolumeBehavior(@NonNull android.media.AudioDeviceAttributes);
method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public java.util.List<android.media.AudioDeviceAttributes> getDevicesForAttributes(@NonNull android.media.AudioAttributes);
method @IntRange(from=0) public long getMaxAdditionalOutputDeviceDelay(@NonNull android.media.AudioDeviceInfo);
method @IntRange(from=0) @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int getMaxVolumeIndexForAttributes(@NonNull android.media.AudioAttributes);
@@ -4219,6 +4220,7 @@ package android.media {
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int requestAudioFocus(@NonNull android.media.AudioFocusRequest, @Nullable android.media.audiopolicy.AudioPolicy);
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public boolean setAdditionalOutputDeviceDelay(@NonNull android.media.AudioDeviceInfo, @IntRange(from=0) long);
method public void setAudioServerStateCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.AudioManager.AudioServerStateCallback);
+ method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void setDeviceVolumeBehavior(@NonNull android.media.AudioDeviceAttributes, int);
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void setFocusRequestResult(@NonNull android.media.AudioFocusInfo, int, @NonNull android.media.audiopolicy.AudioPolicy);
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public boolean setPreferredDeviceForStrategy(@NonNull android.media.audiopolicy.AudioProductStrategy, @NonNull android.media.AudioDeviceAttributes);
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void setSupportedSystemUsages(@NonNull int[]);
@@ -4229,6 +4231,11 @@ package android.media {
field public static final int AUDIOFOCUS_FLAG_DELAY_OK = 1; // 0x1
field public static final int AUDIOFOCUS_FLAG_LOCK = 4; // 0x4
field public static final int AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS = 2; // 0x2
+ field public static final int DEVICE_VOLUME_BEHAVIOR_ABSOLUTE = 3; // 0x3
+ field public static final int DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE = 4; // 0x4
+ field public static final int DEVICE_VOLUME_BEHAVIOR_FIXED = 2; // 0x2
+ field public static final int DEVICE_VOLUME_BEHAVIOR_FULL = 1; // 0x1
+ field public static final int DEVICE_VOLUME_BEHAVIOR_VARIABLE = 0; // 0x0
field @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public static final int STREAM_ASSISTANT = 11; // 0xb
field public static final int SUCCESS = 0; // 0x0
}
diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp
index 36ff20f45ec2..9c796128df84 100644
--- a/cmds/bootanimation/BootAnimation.cpp
+++ b/cmds/bootanimation/BootAnimation.cpp
@@ -417,7 +417,7 @@ status_t BootAnimation::readyToRun() {
// this guest property specifies multi-display IDs to show the boot animation
// multiple ids can be set with comma (,) as separator, for example:
// setprop persist.boot.animation.displays 19260422155234049,19261083906282754
- Vector<uint64_t> physicalDisplayIds;
+ Vector<PhysicalDisplayId> physicalDisplayIds;
char displayValue[PROPERTY_VALUE_MAX] = "";
property_get(DISPLAYS_PROP_NAME, displayValue, "");
bool isValid = displayValue[0] != '\0';
@@ -435,7 +435,7 @@ status_t BootAnimation::readyToRun() {
}
if (isValid) {
std::istringstream stream(displayValue);
- for (PhysicalDisplayId id; stream >> id; ) {
+ for (PhysicalDisplayId id; stream >> id.value; ) {
physicalDisplayIds.add(id);
if (stream.peek() == ',')
stream.ignore();
diff --git a/cmds/screencap/screencap.cpp b/cmds/screencap/screencap.cpp
index a46a54cc2063..dec4a567fc81 100644
--- a/cmds/screencap/screencap.cpp
+++ b/cmds/screencap/screencap.cpp
@@ -51,12 +51,11 @@ static void usage(const char* pname, PhysicalDisplayId displayId)
"usage: %s [-hp] [-d display-id] [FILENAME]\n"
" -h: this message\n"
" -p: save the file as a png.\n"
- " -d: specify the physical display ID to capture (default: %"
- ANDROID_PHYSICAL_DISPLAY_ID_FORMAT ")\n"
+ " -d: specify the physical display ID to capture (default: %s)\n"
" see \"dumpsys SurfaceFlinger --display-id\" for valid display IDs.\n"
"If FILENAME ends with .png it will be saved as a png.\n"
"If FILENAME is not given, the results will be printed to stdout.\n",
- pname, displayId);
+ pname, to_string(displayId).c_str());
}
static int32_t flinger2bitmapFormat(PixelFormat f)
@@ -137,7 +136,7 @@ int main(int argc, char** argv)
png = true;
break;
case 'd':
- displayId = atoll(optarg);
+ displayId = PhysicalDisplayId(atoll(optarg));
break;
case '?':
case 'h':
@@ -183,7 +182,7 @@ int main(int argc, char** argv)
ProcessState::self()->startThreadPool();
ScreenCaptureResults captureResults;
- status_t result = ScreenshotClient::captureDisplay(*displayId, captureResults);
+ status_t result = ScreenshotClient::captureDisplay(displayId->value, captureResults);
if (result != NO_ERROR) {
close(fd);
return 1;
diff --git a/cmds/uiautomator/library/Android.bp b/cmds/uiautomator/library/Android.bp
index 04b00cb837b2..14b74da0c616 100644
--- a/cmds/uiautomator/library/Android.bp
+++ b/cmds/uiautomator/library/Android.bp
@@ -54,7 +54,6 @@ droiddoc {
],
installable: false,
custom_template: "droiddoc-templates-sdk",
- create_stubs: false,
}
java_library_static {
@@ -66,6 +65,7 @@ java_library_static {
"android.test.runner",
"junit",
],
+ java_version: "1.8",
}
java_library_static {
diff --git a/config/hiddenapi-force-blacklist.txt b/config/hiddenapi-force-blocked.txt
index b328f2ac1955..b328f2ac1955 100644
--- a/config/hiddenapi-force-blacklist.txt
+++ b/config/hiddenapi-force-blocked.txt
diff --git a/config/hiddenapi-greylist-max-o.txt b/config/hiddenapi-max-target-o.txt
index 023bf3876228..023bf3876228 100644
--- a/config/hiddenapi-greylist-max-o.txt
+++ b/config/hiddenapi-max-target-o.txt
diff --git a/config/hiddenapi-greylist-max-p.txt b/config/hiddenapi-max-target-p.txt
index 351e71dd9538..351e71dd9538 100644
--- a/config/hiddenapi-greylist-max-p.txt
+++ b/config/hiddenapi-max-target-p.txt
diff --git a/config/hiddenapi-greylist-max-q.txt b/config/hiddenapi-max-target-q.txt
index 4832dd184ec5..4832dd184ec5 100644
--- a/config/hiddenapi-greylist-max-q.txt
+++ b/config/hiddenapi-max-target-q.txt
diff --git a/config/hiddenapi-greylist-packages.txt b/config/hiddenapi-unsupported-packages.txt
index 986d2591a007..986d2591a007 100644
--- a/config/hiddenapi-greylist-packages.txt
+++ b/config/hiddenapi-unsupported-packages.txt
diff --git a/config/hiddenapi-greylist.txt b/config/hiddenapi-unsupported.txt
index a3543dc7f4ee..a3543dc7f4ee 100644
--- a/config/hiddenapi-greylist.txt
+++ b/config/hiddenapi-unsupported.txt
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 2be92826cf38..522b8cc5a46f 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -2880,7 +2880,7 @@ public class Activity extends ContextThemeWrapper
* Return the number of actions that will be displayed in the picture-in-picture UI when the
* user interacts with the activity currently in picture-in-picture mode. This number may change
* if the global configuration changes (ie. if the device is plugged into an external display),
- * but will always be larger than three.
+ * but will always be at least three.
*/
public int getMaxNumPictureInPictureActions() {
try {
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index 9cf0d2a3a36a..1f8cf8ac6d1d 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -341,7 +341,8 @@ public abstract class ActivityManagerInternal {
/** @see com.android.server.am.ActivityManagerService#monitor */
public abstract void monitor();
- /** Input dispatch timeout to a window, start the ANR process. */
+ /** Input dispatch timeout to a window, start the ANR process. Return the timeout extension,
+ * in milliseconds, or 0 to abort dispatch. */
public abstract long inputDispatchingTimedOut(int pid, boolean aboveSystem, String reason);
public abstract boolean inputDispatchingTimedOut(Object proc, String activityShortComponentName,
ApplicationInfo aInfo, String parentShortComponentName, Object parentProc,
diff --git a/core/java/android/app/PropertyInvalidatedCache.java b/core/java/android/app/PropertyInvalidatedCache.java
index bca6f39e1ded..54f3f1026050 100644
--- a/core/java/android/app/PropertyInvalidatedCache.java
+++ b/core/java/android/app/PropertyInvalidatedCache.java
@@ -215,7 +215,7 @@ public abstract class PropertyInvalidatedCache<Query, Result> {
private long mMisses = 0;
@GuardedBy("mLock")
- private long mMissDisabled[] = new long[]{ 0, 0, 0 };
+ private long mSkips[] = new long[]{ 0, 0, 0 };
@GuardedBy("mLock")
private long mMissOverflow = 0;
@@ -223,6 +223,9 @@ public abstract class PropertyInvalidatedCache<Query, Result> {
@GuardedBy("mLock")
private long mHighWaterMark = 0;
+ @GuardedBy("mLock")
+ private long mClears = 0;
+
// Most invalidation is done in a static context, so the counters need to be accessible.
@GuardedBy("sCorkLock")
private static final HashMap<String, Long> sInvalidates = new HashMap<>();
@@ -273,6 +276,13 @@ public abstract class PropertyInvalidatedCache<Query, Result> {
*/
private volatile SystemProperties.Handle mPropertyHandle;
+ /**
+ * The name by which this cache is known. This should normally be the
+ * binder call that is being cached, but the constructors default it to
+ * the property name.
+ */
+ private final String mCacheName;
+
@GuardedBy("mLock")
private final LinkedHashMap<Query, Result> mCache;
@@ -297,9 +307,23 @@ public abstract class PropertyInvalidatedCache<Query, Result> {
*
* @param maxEntries Maximum number of entries to cache; LRU discard
* @param propertyName Name of the system property holding the cache invalidation nonce
+ * Defaults the cache name to the property name.
*/
public PropertyInvalidatedCache(int maxEntries, @NonNull String propertyName) {
+ this(maxEntries, propertyName, propertyName);
+ }
+
+ /**
+ * Make a new property invalidated cache.
+ *
+ * @param maxEntries Maximum number of entries to cache; LRU discard
+ * @param propertyName Name of the system property holding the cache invalidation nonce
+ * @param cacheName Name of this cache in debug and dumpsys
+ */
+ public PropertyInvalidatedCache(int maxEntries, @NonNull String propertyName,
+ @NonNull String cacheName) {
mPropertyName = propertyName;
+ mCacheName = cacheName;
mMaxEntries = maxEntries;
mCache = new LinkedHashMap<Query, Result>(
2 /* start small */,
@@ -320,7 +344,6 @@ public abstract class PropertyInvalidatedCache<Query, Result> {
};
synchronized (sCorkLock) {
sCaches.put(this, null);
- sInvalidates.put(propertyName, (long) 0);
}
}
@@ -333,6 +356,7 @@ public abstract class PropertyInvalidatedCache<Query, Result> {
Log.d(TAG, "clearing cache for " + mPropertyName);
}
mCache.clear();
+ mClears++;
}
}
@@ -413,7 +437,7 @@ public abstract class PropertyInvalidatedCache<Query, Result> {
// Do not bother collecting statistics if the cache is
// locally disabled.
synchronized (mLock) {
- mMissDisabled[(int) currentNonce]++;
+ mSkips[(int) currentNonce]++;
}
}
@@ -742,12 +766,16 @@ public abstract class PropertyInvalidatedCache<Query, Result> {
boolean alreadyQueued = mUncorkDeadlineMs >= 0;
if (DEBUG) {
Log.w(TAG, String.format(
- "autoCork mUncorkDeadlineMs=%s", mUncorkDeadlineMs));
+ "autoCork %s mUncorkDeadlineMs=%s", mPropertyName,
+ mUncorkDeadlineMs));
}
mUncorkDeadlineMs = SystemClock.uptimeMillis() + mAutoCorkDelayMs;
if (!alreadyQueued) {
getHandlerLocked().sendEmptyMessageAtTime(0, mUncorkDeadlineMs);
PropertyInvalidatedCache.corkInvalidations(mPropertyName);
+ } else {
+ final long count = sCorkedInvalidates.getOrDefault(mPropertyName, (long) 0);
+ sCorkedInvalidates.put(mPropertyName, count + 1);
}
}
}
@@ -756,7 +784,8 @@ public abstract class PropertyInvalidatedCache<Query, Result> {
synchronized (mLock) {
if (DEBUG) {
Log.w(TAG, String.format(
- "handleMsesage mUncorkDeadlineMs=%s", mUncorkDeadlineMs));
+ "handleMsesage %s mUncorkDeadlineMs=%s",
+ mPropertyName, mUncorkDeadlineMs));
}
if (mUncorkDeadlineMs < 0) {
@@ -816,7 +845,7 @@ public abstract class PropertyInvalidatedCache<Query, Result> {
* method is public so clients can use it.
*/
public String cacheName() {
- return mPropertyName;
+ return mCacheName;
}
/**
@@ -864,16 +893,20 @@ public abstract class PropertyInvalidatedCache<Query, Result> {
}
synchronized (mLock) {
- pw.println(String.format(" Cache Property Name: %s", cacheName()));
- pw.println(String.format(" Hits: %d, Misses: %d, Invalidates: %d, Overflows: %d",
- mHits, mMisses, invalidateCount, mMissOverflow));
- pw.println(String.format(" Miss-corked: %d, Miss-unset: %d, Miss-other: %d," +
- " CorkedInvalidates: %d",
- mMissDisabled[NONCE_CORKED], mMissDisabled[NONCE_UNSET],
- mMissDisabled[NONCE_DISABLED], corkedInvalidates));
- pw.println(String.format(" Last Observed Nonce: %d", mLastSeenNonce));
- pw.println(String.format(" Current Size: %d, Max Size: %d, HW Mark: %d",
- mCache.size(), mMaxEntries, mHighWaterMark));
+ pw.println(String.format(" Cache Name: %s", cacheName()));
+ pw.println(String.format(" Property: %s", mPropertyName));
+ final long skips = mSkips[NONCE_CORKED] + mSkips[NONCE_UNSET] + mSkips[NONCE_DISABLED];
+ pw.println(String.format(" Hits: %d, Misses: %d, Skips: %d, Clears: %d",
+ mHits, mMisses, skips, mClears));
+ pw.println(String.format(" Skip-corked: %d, Skip-unset: %d, Skip-other: %d",
+ mSkips[NONCE_CORKED], mSkips[NONCE_UNSET],
+ mSkips[NONCE_DISABLED]));
+ pw.println(String.format(
+ " Nonce: 0x%016x, Invalidates: %d, CorkedInvalidates: %d",
+ mLastSeenNonce, invalidateCount, corkedInvalidates));
+ pw.println(String.format(
+ " Current Size: %d, Max Size: %d, HW Mark: %d, Overflows: %d",
+ mCache.size(), mMaxEntries, mHighWaterMark, mMissOverflow));
pw.println(String.format(" Enabled: %s", mDisabled ? "false" : "true"));
Set<Map.Entry<Query, Result>> cacheEntries = mCache.entrySet();
diff --git a/core/java/android/app/UiModeManager.java b/core/java/android/app/UiModeManager.java
index 7c6eff143724..06d1b74abc86 100644
--- a/core/java/android/app/UiModeManager.java
+++ b/core/java/android/app/UiModeManager.java
@@ -510,6 +510,9 @@ public class UiModeManager {
}
/**
+ * Activating night mode for the current user
+ *
+ * @return {@code true} if the change is successful
* @hide
*/
public boolean setNightModeActivated(boolean active) {
diff --git a/core/java/android/app/people/ConversationChannel.java b/core/java/android/app/people/ConversationChannel.java
new file mode 100644
index 000000000000..39c5c85e456c
--- /dev/null
+++ b/core/java/android/app/people/ConversationChannel.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.people;
+
+import android.app.NotificationChannel;
+import android.content.pm.ShortcutInfo;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * The non-customized notification channel of a conversation. It contains the information to render
+ * the conversation and allows the user to open and customize the conversation setting.
+ *
+ * @hide
+ */
+public final class ConversationChannel implements Parcelable {
+
+ private ShortcutInfo mShortcutInfo;
+ private NotificationChannel mParentNotificationChannel;
+ private long mLastEventTimestamp;
+ private boolean mHasActiveNotifications;
+
+ public static final Creator<ConversationChannel> CREATOR = new Creator<ConversationChannel>() {
+ @Override
+ public ConversationChannel createFromParcel(Parcel in) {
+ return new ConversationChannel(in);
+ }
+
+ @Override
+ public ConversationChannel[] newArray(int size) {
+ return new ConversationChannel[size];
+ }
+ };
+
+ public ConversationChannel(ShortcutInfo shortcutInfo,
+ NotificationChannel parentNotificationChannel, long lastEventTimestamp,
+ boolean hasActiveNotifications) {
+ mShortcutInfo = shortcutInfo;
+ mParentNotificationChannel = parentNotificationChannel;
+ mLastEventTimestamp = lastEventTimestamp;
+ mHasActiveNotifications = hasActiveNotifications;
+ }
+
+ public ConversationChannel(Parcel in) {
+ mShortcutInfo = in.readParcelable(ShortcutInfo.class.getClassLoader());
+ mParentNotificationChannel = in.readParcelable(NotificationChannel.class.getClassLoader());
+ mLastEventTimestamp = in.readLong();
+ mHasActiveNotifications = in.readBoolean();
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeParcelable(mShortcutInfo, flags);
+ dest.writeParcelable(mParentNotificationChannel, flags);
+ dest.writeLong(mLastEventTimestamp);
+ dest.writeBoolean(mHasActiveNotifications);
+ }
+
+ public ShortcutInfo getShortcutInfo() {
+ return mShortcutInfo;
+ }
+
+ public NotificationChannel getParentNotificationChannel() {
+ return mParentNotificationChannel;
+ }
+
+ public long getLastEventTimestamp() {
+ return mLastEventTimestamp;
+ }
+
+ /**
+ * Whether this conversation has any active notifications. If it's true, the shortcut for this
+ * conversation can't be uncached until all its active notifications are dismissed.
+ */
+ public boolean hasActiveNotifications() {
+ return mHasActiveNotifications;
+ }
+}
diff --git a/core/java/android/app/people/IPeopleManager.aidl b/core/java/android/app/people/IPeopleManager.aidl
new file mode 100644
index 000000000000..61dac0d64422
--- /dev/null
+++ b/core/java/android/app/people/IPeopleManager.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.people;
+
+import android.content.pm.ParceledListSlice;
+import android.net.Uri;
+import android.os.IBinder;
+
+/**
+ * System private API for talking with the people service.
+ * {@hide}
+ */
+interface IPeopleManager {
+ /**
+ * Returns the recent conversations. The conversations that have customized notification
+ * settings are excluded from the returned list.
+ */
+ ParceledListSlice getRecentConversations();
+
+ /**
+ * Removes the specified conversation from the recent conversations list and uncaches the
+ * shortcut associated with the conversation.
+ */
+ void removeRecentConversation(in String packageName, int userId, in String shortcutId);
+
+ /** Removes all the recent conversations and uncaches their cached shortcuts. */
+ void removeAllRecentConversations();
+}
diff --git a/core/java/android/app/timezonedetector/TimeZoneDetectorImpl.java b/core/java/android/app/timezonedetector/TimeZoneDetectorImpl.java
index 6bd365fad6f6..0770aff4e9bb 100644
--- a/core/java/android/app/timezonedetector/TimeZoneDetectorImpl.java
+++ b/core/java/android/app/timezonedetector/TimeZoneDetectorImpl.java
@@ -117,7 +117,7 @@ public final class TimeZoneDetectorImpl implements TimeZoneDetector {
}
private void notifyConfigurationListeners(@NonNull TimeZoneConfiguration configuration) {
- ArraySet<TimeZoneConfigurationListener> configurationListeners;
+ final ArraySet<TimeZoneConfigurationListener> configurationListeners;
synchronized (this) {
configurationListeners = new ArraySet<>(mConfigurationListeners);
}
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 16cdf2334ad8..52b04675b7a5 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -3496,6 +3496,7 @@ public abstract class Context {
//@hide: TIME_ZONE_DETECTOR_SERVICE,
PERMISSION_SERVICE,
LIGHTS_SERVICE,
+ //@hide: PEOPLE_SERVICE,
})
@Retention(RetentionPolicy.SOURCE)
public @interface ServiceName {}
@@ -5189,6 +5190,14 @@ public abstract class Context {
public static final String SMS_SERVICE = "sms";
/**
+ * Use with {@link #getSystemService(String)} to access people service.
+ *
+ * @see #getSystemService(String)
+ * @hide
+ */
+ public static final String PEOPLE_SERVICE = "people";
+
+ /**
* 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/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index bd02210259b8..31c77eeb5424 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -963,7 +963,7 @@ public class ActivityInfo extends ComponentInfo implements Parcelable {
/** @hide */
public static final int LOCK_TASK_LAUNCH_MODE_ALWAYS = 2;
/** @hide */
- public static final int LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED = 3;
+ public static final int LOCK_TASK_LAUNCH_MODE_IF_ALLOWLISTED = 3;
/** @hide */
public static final String lockTaskLaunchModeToString(int lockTaskLaunchMode) {
@@ -974,8 +974,8 @@ public class ActivityInfo extends ComponentInfo implements Parcelable {
return "LOCK_TASK_LAUNCH_MODE_NEVER";
case LOCK_TASK_LAUNCH_MODE_ALWAYS:
return "LOCK_TASK_LAUNCH_MODE_ALWAYS";
- case LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED:
- return "LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED";
+ case LOCK_TASK_LAUNCH_MODE_IF_ALLOWLISTED:
+ return "LOCK_TASK_LAUNCH_MODE_IF_ALLOWLISTED";
default:
return "unknown=" + lockTaskLaunchMode;
}
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index df9db278e095..bed7b26034e5 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -2075,7 +2075,8 @@ public class PackageInstaller {
STAGED_SESSION_NO_ERROR,
STAGED_SESSION_VERIFICATION_FAILED,
STAGED_SESSION_ACTIVATION_FAILED,
- STAGED_SESSION_UNKNOWN})
+ STAGED_SESSION_UNKNOWN,
+ STAGED_SESSION_OTHER_ERROR})
@Retention(RetentionPolicy.SOURCE)
public @interface StagedSessionErrorCode{}
/**
@@ -2101,6 +2102,12 @@ public class PackageInstaller {
*/
public static final int STAGED_SESSION_UNKNOWN = 3;
+ /**
+ * Constant indicating that a known error occurred while processing this staged session, but
+ * the error could not be matched to other categories.
+ */
+ public static final int STAGED_SESSION_OTHER_ERROR = 4;
+
/** {@hide} */
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public int sessionId;
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 42a610700051..e08af5534afd 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -8089,7 +8089,8 @@ public abstract class PackageManager {
private static final PropertyInvalidatedCache<ApplicationInfoQuery, ApplicationInfo>
sApplicationInfoCache =
new PropertyInvalidatedCache<ApplicationInfoQuery, ApplicationInfo>(
- 16, PermissionManager.CACHE_KEY_PACKAGE_INFO) {
+ 16, PermissionManager.CACHE_KEY_PACKAGE_INFO,
+ "getApplicationInfo") {
@Override
protected ApplicationInfo recompute(ApplicationInfoQuery query) {
return getApplicationInfoAsUserUncached(
@@ -8190,7 +8191,8 @@ public abstract class PackageManager {
private static final PropertyInvalidatedCache<PackageInfoQuery, PackageInfo>
sPackageInfoCache =
new PropertyInvalidatedCache<PackageInfoQuery, PackageInfo>(
- 32, PermissionManager.CACHE_KEY_PACKAGE_INFO) {
+ 32, PermissionManager.CACHE_KEY_PACKAGE_INFO,
+ "getPackageInfo") {
@Override
protected PackageInfo recompute(PackageInfoQuery query) {
return getPackageInfoAsUserUncached(
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index fbe6a5052f3d..b0d449769be4 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -743,6 +743,12 @@ public abstract class BatteryStats implements Parcelable {
@UnsupportedAppUsage
public abstract ArrayMap<String, ? extends Pkg> getPackageStats();
+ /**
+ * Returns the proportion of power consumed by the System Service
+ * calls made by this UID.
+ */
+ public abstract double getProportionalSystemServiceUsage();
+
public abstract ControllerActivityCounter getWifiControllerActivity();
public abstract ControllerActivityCounter getBluetoothControllerActivity();
public abstract ControllerActivityCounter getModemControllerActivity();
@@ -2882,6 +2888,17 @@ public abstract class BatteryStats implements Parcelable {
public abstract int getDischargeAmountScreenDozeSinceCharge();
/**
+ * Returns the approximate CPU time (in microseconds) spent by the system server handling
+ * incoming service calls from apps.
+ *
+ * @param cluster the index of the CPU cluster.
+ * @param step the index of the CPU speed. This is not the actual speed of the CPU.
+ * @see com.android.internal.os.PowerProfile#getNumCpuClusters()
+ * @see com.android.internal.os.PowerProfile#getNumSpeedStepsInCpuCluster(int)
+ */
+ public abstract long getSystemServiceTimeAtCpuSpeed(int cluster, int step);
+
+ /**
* Returns the total, last, or current battery uptime in microseconds.
*
* @param curTime the elapsed realtime in microseconds.
diff --git a/core/java/android/permission/PermissionManager.java b/core/java/android/permission/PermissionManager.java
index bf3d46fa4a44..0c190719af57 100644
--- a/core/java/android/permission/PermissionManager.java
+++ b/core/java/android/permission/PermissionManager.java
@@ -608,7 +608,7 @@ public final class PermissionManager {
/** @hide */
private static final PropertyInvalidatedCache<PermissionQuery, Integer> sPermissionCache =
new PropertyInvalidatedCache<PermissionQuery, Integer>(
- 16, CACHE_KEY_PACKAGE_INFO) {
+ 16, CACHE_KEY_PACKAGE_INFO, "checkPermission") {
@Override
protected Integer recompute(PermissionQuery query) {
return checkPermissionUncached(query.permission, query.pid, query.uid);
@@ -689,7 +689,7 @@ public final class PermissionManager {
private static PropertyInvalidatedCache<PackageNamePermissionQuery, Integer>
sPackageNamePermissionCache =
new PropertyInvalidatedCache<PackageNamePermissionQuery, Integer>(
- 16, CACHE_KEY_PACKAGE_INFO) {
+ 16, CACHE_KEY_PACKAGE_INFO, "checkPackageNamePermission") {
@Override
protected Integer recompute(PackageNamePermissionQuery query) {
return checkPackageNamePermissionUncached(
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 5acc11a868bf..660455e59a4a 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -7912,6 +7912,13 @@ public final class Settings {
public static final String TAPS_APP_TO_EXIT = "taps_app_to_exit";
/**
+ * Internal use, one handed mode tutorial showed times.
+ * @hide
+ */
+ public static final String ONE_HANDED_TUTORIAL_SHOW_COUNT =
+ "one_handed_tutorial_show_count";
+
+ /**
* The current night mode that has been selected by the user. Owned
* and controlled by UiModeManagerService. Constants are as per
* UiModeManager.
diff --git a/core/java/android/view/InputApplicationHandle.java b/core/java/android/view/InputApplicationHandle.java
index 3d05e2a0b9f6..108345e6db0e 100644
--- a/core/java/android/view/InputApplicationHandle.java
+++ b/core/java/android/view/InputApplicationHandle.java
@@ -34,7 +34,7 @@ public final class InputApplicationHandle {
public String name;
// Dispatching timeout.
- public long dispatchingTimeoutNanos;
+ public long dispatchingTimeoutMillis;
public final IBinder token;
@@ -46,7 +46,7 @@ public final class InputApplicationHandle {
public InputApplicationHandle(InputApplicationHandle handle) {
this.token = handle.token;
- this.dispatchingTimeoutNanos = handle.dispatchingTimeoutNanos;
+ this.dispatchingTimeoutMillis = handle.dispatchingTimeoutMillis;
this.name = handle.name;
}
diff --git a/core/java/android/view/InputWindowHandle.java b/core/java/android/view/InputWindowHandle.java
index a7e0305f2c09..e341845277d4 100644
--- a/core/java/android/view/InputWindowHandle.java
+++ b/core/java/android/view/InputWindowHandle.java
@@ -50,7 +50,7 @@ public final class InputWindowHandle {
public int layoutParamsType;
// Dispatching timeout.
- public long dispatchingTimeoutNanos;
+ public long dispatchingTimeoutMillis;
// Window frame.
public int frameLeft;
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 0818abeff923..89178217366f 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -23358,7 +23358,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* displaying, else return the result of calling through to the
* super class.
*
- * @return boolean If true than the Drawable is being displayed in the
+ * @return boolean If true then the Drawable is being displayed in the
* view; else false and it is not allowed to animate.
*
* @see #unscheduleDrawable(android.graphics.drawable.Drawable)
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 64ddb2f4d9d9..3f02d701f71f 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -1814,19 +1814,13 @@ public final class ViewRootImpl implements ViewParent,
/**
* Called after window layout to update the bounds surface. If the surface insets have changed
* or the surface has resized, update the bounds surface.
- *
- * @param shouldReparent Whether it should reparent the bounds layer to the main SurfaceControl.
*/
- private void updateBoundsLayer(boolean shouldReparent) {
+ private void updateBoundsLayer() {
if (mBoundsLayer != null) {
setBoundsLayerCrop();
- mTransaction.deferTransactionUntil(mBoundsLayer, getRenderSurfaceControl(),
- mSurface.getNextFrameNumber());
-
- if (shouldReparent) {
- mTransaction.reparent(mBoundsLayer, getRenderSurfaceControl());
- }
- mTransaction.apply();
+ mTransaction.deferTransactionUntil(mBoundsLayer,
+ getRenderSurfaceControl(), mSurface.getNextFrameNumber())
+ .apply();
}
}
@@ -2905,16 +2899,7 @@ public final class ViewRootImpl implements ViewParent,
}
if (surfaceSizeChanged || surfaceReplaced || surfaceCreated || windowAttributesChanged) {
- // If the surface has been replaced, there's a chance the bounds layer is not parented
- // to the new layer. When updating bounds layer, also reparent to the main VRI
- // SurfaceControl to ensure it's correctly placed in the hierarchy.
- //
- // This needs to be done on the client side since WMS won't reparent the children to the
- // new surface if it thinks the app is closing. WMS gets the signal that the app is
- // stopping, but on the client side it doesn't get stopped since it's restarted quick
- // enough. WMS doesn't want to keep around old children since they will leak when the
- // client creates new children.
- updateBoundsLayer(surfaceReplaced);
+ updateBoundsLayer();
}
final boolean didLayout = layoutRequested && (!mStopped || mReportNextDraw);
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index c4eb39626d8b..7683067958d8 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -385,6 +385,7 @@ public class Editor {
private final SuggestionHelper mSuggestionHelper = new SuggestionHelper();
private boolean mFlagCursorDragFromAnywhereEnabled;
+ private float mCursorDragDirectionMinXYRatio;
private boolean mFlagInsertionHandleGesturesEnabled;
// Specifies whether the new magnifier (with fish-eye effect) is enabled.
@@ -425,6 +426,11 @@ public class Editor {
mFlagCursorDragFromAnywhereEnabled = AppGlobals.getIntCoreSetting(
WidgetFlags.KEY_ENABLE_CURSOR_DRAG_FROM_ANYWHERE,
WidgetFlags.ENABLE_CURSOR_DRAG_FROM_ANYWHERE_DEFAULT ? 1 : 0) != 0;
+ final int cursorDragMinAngleFromVertical = AppGlobals.getIntCoreSetting(
+ WidgetFlags.KEY_CURSOR_DRAG_MIN_ANGLE_FROM_VERTICAL,
+ WidgetFlags.CURSOR_DRAG_MIN_ANGLE_FROM_VERTICAL_DEFAULT);
+ mCursorDragDirectionMinXYRatio = EditorTouchState.getXYRatio(
+ cursorDragMinAngleFromVertical);
mFlagInsertionHandleGesturesEnabled = AppGlobals.getIntCoreSetting(
WidgetFlags.KEY_ENABLE_INSERTION_HANDLE_GESTURES,
WidgetFlags.ENABLE_INSERTION_HANDLE_GESTURES_DEFAULT ? 1 : 0) != 0;
@@ -437,6 +443,8 @@ public class Editor {
if (TextView.DEBUG_CURSOR) {
logCursor("Editor", "Cursor drag from anywhere is %s.",
mFlagCursorDragFromAnywhereEnabled ? "enabled" : "disabled");
+ logCursor("Editor", "Cursor drag min angle from vertical is %d (= %f x/y ratio)",
+ cursorDragMinAngleFromVertical, mCursorDragDirectionMinXYRatio);
logCursor("Editor", "Insertion handle gestures is %s.",
mFlagInsertionHandleGesturesEnabled ? "enabled" : "disabled");
logCursor("Editor", "New magnifier is %s.",
@@ -463,6 +471,11 @@ public class Editor {
}
@VisibleForTesting
+ public void setCursorDragMinAngleFromVertical(int degreesFromVertical) {
+ mCursorDragDirectionMinXYRatio = EditorTouchState.getXYRatio(degreesFromVertical);
+ }
+
+ @VisibleForTesting
public boolean getFlagInsertionHandleGesturesEnabled() {
return mFlagInsertionHandleGesturesEnabled;
}
@@ -6127,10 +6140,11 @@ public class Editor {
if (mIsDraggingCursor) {
performCursorDrag(event);
} else if (mFlagCursorDragFromAnywhereEnabled
- && mTextView.getLayout() != null
- && mTextView.isFocused()
- && mTouchState.isMovedEnoughForDrag()
- && !mTouchState.isDragCloseToVertical()) {
+ && mTextView.getLayout() != null
+ && mTextView.isFocused()
+ && mTouchState.isMovedEnoughForDrag()
+ && (mTouchState.getInitialDragDirectionXYRatio()
+ > mCursorDragDirectionMinXYRatio || mTouchState.isOnHandle())) {
startCursorDrag(event);
}
break;
diff --git a/core/java/android/widget/EditorTouchState.java b/core/java/android/widget/EditorTouchState.java
index 9eb63087a66e..751436865ff5 100644
--- a/core/java/android/widget/EditorTouchState.java
+++ b/core/java/android/widget/EditorTouchState.java
@@ -59,7 +59,7 @@ public class EditorTouchState {
private boolean mMultiTapInSameArea;
private boolean mMovedEnoughForDrag;
- private boolean mIsDragCloseToVertical;
+ private float mInitialDragDirectionXYRatio;
public float getLastDownX() {
return mLastDownX;
@@ -98,8 +98,23 @@ public class EditorTouchState {
return mMovedEnoughForDrag;
}
- public boolean isDragCloseToVertical() {
- return mIsDragCloseToVertical && !mIsOnHandle;
+ /**
+ * When {@link #isMovedEnoughForDrag()} is {@code true}, this function returns the x/y ratio for
+ * the initial drag direction. Smaller values indicate that the direction is closer to vertical,
+ * while larger values indicate that the direction is closer to horizontal. For example:
+ * <ul>
+ * <li>if the drag direction is exactly vertical, this returns 0
+ * <li>if the drag direction is exactly horizontal, this returns {@link Float#MAX_VALUE}
+ * <li>if the drag direction is 45 deg from vertical, this returns 1
+ * <li>if the drag direction is 30 deg from vertical, this returns 0.58 (x delta is smaller
+ * than y delta)
+ * <li>if the drag direction is 60 deg from vertical, this returns 1.73 (x delta is bigger
+ * than y delta)
+ * </ul>
+ * This function never returns negative values, regardless of the direction of the drag.
+ */
+ public float getInitialDragDirectionXYRatio() {
+ return mInitialDragDirectionXYRatio;
}
public void setIsOnHandle(boolean onHandle) {
@@ -155,7 +170,7 @@ public class EditorTouchState {
mLastDownY = event.getY();
mLastDownMillis = event.getEventTime();
mMovedEnoughForDrag = false;
- mIsDragCloseToVertical = false;
+ mInitialDragDirectionXYRatio = 0.0f;
} else if (action == MotionEvent.ACTION_UP) {
if (TextView.DEBUG_CURSOR) {
logCursor("EditorTouchState", "ACTION_UP");
@@ -164,7 +179,7 @@ public class EditorTouchState {
mLastUpY = event.getY();
mLastUpMillis = event.getEventTime();
mMovedEnoughForDrag = false;
- mIsDragCloseToVertical = false;
+ mInitialDragDirectionXYRatio = 0.0f;
} else if (action == MotionEvent.ACTION_MOVE) {
if (!mMovedEnoughForDrag) {
float deltaX = event.getX() - mLastDownX;
@@ -174,9 +189,8 @@ public class EditorTouchState {
int touchSlop = config.getScaledTouchSlop();
mMovedEnoughForDrag = distanceSquared > touchSlop * touchSlop;
if (mMovedEnoughForDrag) {
- // If the direction of the swipe motion is within 45 degrees of vertical, it is
- // considered a vertical drag.
- mIsDragCloseToVertical = Math.abs(deltaX) <= Math.abs(deltaY);
+ mInitialDragDirectionXYRatio = (deltaY == 0) ? Float.MAX_VALUE :
+ Math.abs(deltaX / deltaY);
}
}
} else if (action == MotionEvent.ACTION_CANCEL) {
@@ -185,7 +199,7 @@ public class EditorTouchState {
mMultiTapStatus = MultiTapStatus.NONE;
mMultiTapInSameArea = false;
mMovedEnoughForDrag = false;
- mIsDragCloseToVertical = false;
+ mInitialDragDirectionXYRatio = 0.0f;
}
}
@@ -201,4 +215,27 @@ public class EditorTouchState {
float distanceSquared = (deltaX * deltaX) + (deltaY * deltaY);
return distanceSquared <= maxDistance * maxDistance;
}
+
+ /**
+ * Returns the x/y ratio corresponding to the given angle relative to vertical. Smaller angle
+ * values (ie, closer to vertical) will result in a smaller x/y ratio. For example:
+ * <ul>
+ * <li>if the angle is 45 deg, the ratio is 1
+ * <li>if the angle is 30 deg, the ratio is 0.58 (x delta is smaller than y delta)
+ * <li>if the angle is 60 deg, the ratio is 1.73 (x delta is bigger than y delta)
+ * </ul>
+ * If the passed-in value is <= 0, this function returns 0. If the passed-in value is >= 90,
+ * this function returns {@link Float#MAX_VALUE}.
+ *
+ * @see #getInitialDragDirectionXYRatio()
+ */
+ public static float getXYRatio(int angleFromVerticalInDegrees) {
+ if (angleFromVerticalInDegrees <= 0) {
+ return 0.0f;
+ }
+ if (angleFromVerticalInDegrees >= 90) {
+ return Float.MAX_VALUE;
+ }
+ return (float) Math.tan(Math.toRadians(angleFromVerticalInDegrees));
+ }
}
diff --git a/core/java/android/widget/WidgetFlags.java b/core/java/android/widget/WidgetFlags.java
index 832dd5190d37..1a493653d811 100644
--- a/core/java/android/widget/WidgetFlags.java
+++ b/core/java/android/widget/WidgetFlags.java
@@ -41,6 +41,28 @@ public final class WidgetFlags {
public static final boolean ENABLE_CURSOR_DRAG_FROM_ANYWHERE_DEFAULT = true;
/**
+ * Threshold for the direction of a swipe gesture in order for it to be handled as a cursor drag
+ * rather than a scroll. The direction angle of the swipe gesture must exceed this value in
+ * order to trigger cursor drag; otherwise, the swipe will be assumed to be a scroll gesture.
+ * The value units for this flag is degrees and the valid range is [0,90] inclusive. If a value
+ * < 0 is set, 0 will be used instead; if a value > 90 is set, 90 will be used instead.
+ */
+ public static final String CURSOR_DRAG_MIN_ANGLE_FROM_VERTICAL =
+ "CursorControlFeature__min_angle_from_vertical_to_start_cursor_drag";
+
+ /**
+ * The key used in app core settings for the flag
+ * {@link #CURSOR_DRAG_MIN_ANGLE_FROM_VERTICAL}.
+ */
+ public static final String KEY_CURSOR_DRAG_MIN_ANGLE_FROM_VERTICAL =
+ "widget__min_angle_from_vertical_to_start_cursor_drag";
+
+ /**
+ * Default value for the flag {@link #CURSOR_DRAG_MIN_ANGLE_FROM_VERTICAL}.
+ */
+ public static final int CURSOR_DRAG_MIN_ANGLE_FROM_VERTICAL_DEFAULT = 45;
+
+ /**
* The flag of finger-to-cursor distance in DP for cursor dragging.
* The value unit is DP and the range is {0..100}. If the value is out of range, the legacy
* value, which is based on handle size, will be used.
diff --git a/core/java/android/widget/inline/InlineContentView.java b/core/java/android/widget/inline/InlineContentView.java
index 699a7735bbee..9712311aab7c 100644
--- a/core/java/android/widget/inline/InlineContentView.java
+++ b/core/java/android/widget/inline/InlineContentView.java
@@ -59,7 +59,7 @@ import java.util.function.Consumer;
*/
public class InlineContentView extends ViewGroup {
- private static final String TAG = "InlineContentView_test2";
+ private static final String TAG = "InlineContentView";
private static final boolean DEBUG = false;
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 3a89dcd96487..49ad81b2bbc8 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -3134,7 +3134,9 @@ public class ChooserActivity extends ResolverActivity implements
// ends up disabled. That's because at some point the old tab's vertical scrolling is
// disabled and the new tab's is enabled. For context, see b/159997845
setVerticalScrollEnabled(true);
- mResolverDrawerLayout.scrollNestedScrollableChildBackToTop();
+ if (mResolverDrawerLayout != null) {
+ mResolverDrawerLayout.scrollNestedScrollableChildBackToTop();
+ }
}
@Override
diff --git a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
index ea3d2de13ce6..eb59f0f59be1 100644
--- a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
+++ b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
@@ -123,10 +123,15 @@ public final class SystemUiDeviceConfigFlags {
// Flag related to Privacy Indicators
/**
- * Whether the Permissions Hub is showing.
+ * Whether to show the complete ongoing app ops chip.
*/
public static final String PROPERTY_PERMISSIONS_HUB_ENABLED = "permissions_hub_2_enabled";
+ /**
+ * Whether to show app ops chip for just microphone + camera.
+ */
+ public static final String PROPERTY_MIC_CAMERA_ENABLED = "camera_mic_icons_enabled";
+
// Flags related to Assistant
/**
diff --git a/core/java/com/android/internal/os/BatterySipper.java b/core/java/com/android/internal/os/BatterySipper.java
index b3ea118d9c73..2620ba0749a9 100644
--- a/core/java/com/android/internal/os/BatterySipper.java
+++ b/core/java/com/android/internal/os/BatterySipper.java
@@ -129,6 +129,7 @@ public class BatterySipper implements Comparable<BatterySipper> {
public double videoPowerMah;
public double wakeLockPowerMah;
public double wifiPowerMah;
+ public double systemServiceCpuPowerMah;
// ****************
// This list must be kept current with atoms.proto (frameworks/base/cmds/statsd/src/atoms.proto)
@@ -242,6 +243,7 @@ public class BatterySipper implements Comparable<BatterySipper> {
videoPowerMah += other.videoPowerMah;
proportionalSmearMah += other.proportionalSmearMah;
totalSmearedPowerMah += other.totalSmearedPowerMah;
+ systemServiceCpuPowerMah += other.systemServiceCpuPowerMah;
}
/**
@@ -253,7 +255,8 @@ public class BatterySipper implements Comparable<BatterySipper> {
public double sumPower() {
totalPowerMah = usagePowerMah + wifiPowerMah + gpsPowerMah + cpuPowerMah +
sensorPowerMah + mobileRadioPowerMah + wakeLockPowerMah + cameraPowerMah +
- flashlightPowerMah + bluetoothPowerMah + audioPowerMah + videoPowerMah;
+ flashlightPowerMah + bluetoothPowerMah + audioPowerMah + videoPowerMah
+ + systemServiceCpuPowerMah;
totalSmearedPowerMah = totalPowerMah + screenPowerMah + proportionalSmearMah;
return totalPowerMah;
diff --git a/core/java/com/android/internal/os/BatteryStatsHelper.java b/core/java/com/android/internal/os/BatteryStatsHelper.java
index b131ab83cc79..3dfa3c3f6906 100644
--- a/core/java/com/android/internal/os/BatteryStatsHelper.java
+++ b/core/java/com/android/internal/os/BatteryStatsHelper.java
@@ -133,6 +133,7 @@ public class BatteryStatsHelper {
private double mMaxDrainedPower;
PowerCalculator mCpuPowerCalculator;
+ SystemServicePowerCalculator mSystemServicePowerCalculator;
PowerCalculator mWakelockPowerCalculator;
MobileRadioPowerCalculator mMobileRadioPowerCalculator;
PowerCalculator mWifiPowerCalculator;
@@ -396,6 +397,11 @@ public class BatteryStatsHelper {
}
mCpuPowerCalculator.reset();
+ if (mSystemServicePowerCalculator == null) {
+ mSystemServicePowerCalculator = new SystemServicePowerCalculator(mPowerProfile, mStats);
+ }
+ mSystemServicePowerCalculator.reset();
+
if (mMemoryPowerCalculator == null) {
mMemoryPowerCalculator = new MemoryPowerCalculator(mPowerProfile);
}
@@ -588,6 +594,8 @@ public class BatteryStatsHelper {
mFlashlightPowerCalculator.calculateApp(app, u, mRawRealtimeUs, mRawUptimeUs,
mStatsType);
mMediaPowerCalculator.calculateApp(app, u, mRawRealtimeUs, mRawUptimeUs, mStatsType);
+ mSystemServicePowerCalculator.calculateApp(app, u, mRawRealtimeUs, mRawUptimeUs,
+ mStatsType);
final double totalPower = app.sumPower();
if (DEBUG && totalPower != 0) {
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 58ba16bc61dd..84981515e133 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -144,6 +144,7 @@ public class BatteryStatsImpl extends BatteryStats {
private static final boolean DEBUG = false;
public static final boolean DEBUG_ENERGY = false;
private static final boolean DEBUG_ENERGY_CPU = DEBUG_ENERGY;
+ private static final boolean DEBUG_BINDER_STATS = true;
private static final boolean DEBUG_MEMORY = false;
private static final boolean DEBUG_HISTORY = false;
private static final boolean USE_OLD_HISTORY = false; // for debugging.
@@ -154,7 +155,7 @@ public class BatteryStatsImpl extends BatteryStats {
private static final int MAGIC = 0xBA757475; // 'BATSTATS'
// Current on-disk Parcel version
- static final int VERSION = 186 + (USE_OLD_HISTORY ? 1000 : 0);
+ static final int VERSION = 187 + (USE_OLD_HISTORY ? 1000 : 0);
// The maximum number of names wakelocks we will keep track of
// per uid; once the limit is reached, we batch the remaining wakelocks
@@ -218,10 +219,13 @@ public class BatteryStatsImpl extends BatteryStats {
new KernelCpuUidClusterTimeReader(true);
@VisibleForTesting
protected KernelSingleUidTimeReader mKernelSingleUidTimeReader;
+ @VisibleForTesting
+ protected SystemServerCpuThreadReader mSystemServerCpuThreadReader;
private final KernelMemoryBandwidthStats mKernelMemoryBandwidthStats
= new KernelMemoryBandwidthStats();
private final LongSparseArray<SamplingTimer> mKernelMemoryStats = new LongSparseArray<>();
+
public LongSparseArray<SamplingTimer> getKernelMemoryStats() {
return mKernelMemoryStats;
}
@@ -267,6 +271,7 @@ public class BatteryStatsImpl extends BatteryStats {
/** Container for Rail Energy Data stats. */
private final RailStats mTmpRailStats = new RailStats();
+
/**
* Use a queue to delay removing UIDs from {@link KernelCpuUidUserSysTimeReader},
* {@link KernelCpuUidActiveTimeReader}, {@link KernelCpuUidClusterTimeReader},
@@ -1007,6 +1012,16 @@ public class BatteryStatsImpl extends BatteryStats {
private long[] mCpuFreqs;
+ /**
+ * Times spent by the system server threads grouped by cluster and CPU speed.
+ */
+ private LongSamplingCounter[][] mSystemServerThreadCpuTimesUs;
+
+ /**
+ * Times spent by the system server threads handling incoming binder requests.
+ */
+ private LongSamplingCounter[][] mBinderThreadCpuTimesUs;
+
@VisibleForTesting
protected PowerProfile mPowerProfile;
@@ -6131,10 +6146,77 @@ public class BatteryStatsImpl extends BatteryStats {
* the power consumption to the calling app.
*/
public void noteBinderCallStats(int workSourceUid, long incrementalCallCount,
- Collection<BinderCallsStats.CallStat> callStats) {
+ Collection<BinderCallsStats.CallStat> callStats, int[] binderThreadNativeTids) {
synchronized (this) {
getUidStatsLocked(workSourceUid).noteBinderCallStatsLocked(incrementalCallCount,
callStats);
+ mSystemServerCpuThreadReader.setBinderThreadNativeTids(binderThreadNativeTids);
+ }
+ }
+
+ /**
+ * Estimates the proportion of system server CPU activity handling incoming binder calls
+ * that can be attributed to each app
+ */
+ @VisibleForTesting
+ public void updateSystemServiceCallStats() {
+ // Start off by computing the average duration of recorded binder calls,
+ // regardless of which binder or transaction. We will use this as a fallback
+ // for calls that were not sampled at all.
+ int totalRecordedCallCount = 0;
+ long totalRecordedCallTimeMicros = 0;
+ for (int i = 0; i < mUidStats.size(); i++) {
+ Uid uid = mUidStats.valueAt(i);
+ ArraySet<BinderCallStats> binderCallStats = uid.mBinderCallStats;
+ for (int j = binderCallStats.size() - 1; j >= 0; j--) {
+ BinderCallStats stats = binderCallStats.valueAt(j);
+ totalRecordedCallCount += stats.recordedCallCount;
+ totalRecordedCallTimeMicros += stats.recordedCpuTimeMicros;
+ }
+ }
+
+ long totalSystemServiceTimeMicros = 0;
+
+ // For every UID, use recorded durations of sampled binder calls to estimate
+ // the total time the system server spent handling requests from this UID.
+ for (int i = 0; i < mUidStats.size(); i++) {
+ Uid uid = mUidStats.valueAt(i);
+
+ long totalTimeForUid = 0;
+ int totalCallCountForUid = 0;
+ ArraySet<BinderCallStats> binderCallStats = uid.mBinderCallStats;
+ for (int j = binderCallStats.size() - 1; j >= 0; j--) {
+ BinderCallStats stats = binderCallStats.valueAt(j);
+ totalCallCountForUid += stats.callCount;
+ if (stats.recordedCallCount > 0) {
+ totalTimeForUid +=
+ stats.callCount * stats.recordedCpuTimeMicros / stats.recordedCallCount;
+ } else if (totalRecordedCallCount > 0) {
+ totalTimeForUid +=
+ stats.callCount * totalRecordedCallTimeMicros / totalRecordedCallCount;
+ }
+ }
+
+ if (totalCallCountForUid < uid.mBinderCallCount && totalRecordedCallCount > 0) {
+ // Estimate remaining calls, which were not tracked because of binder call
+ // stats sampling
+ totalTimeForUid +=
+ (uid.mBinderCallCount - totalCallCountForUid) * totalRecordedCallTimeMicros
+ / totalRecordedCallCount;
+ }
+
+ uid.mSystemServiceTimeUs = totalTimeForUid;
+ totalSystemServiceTimeMicros += totalTimeForUid;
+ }
+
+ for (int i = 0; i < mUidStats.size(); i++) {
+ Uid uid = mUidStats.valueAt(i);
+ if (totalSystemServiceTimeMicros > 0) {
+ uid.mProportionalSystemServiceUsage =
+ (double) uid.mSystemServiceTimeUs / totalSystemServiceTimeMicros;
+ } else {
+ uid.mProportionalSystemServiceUsage = 0;
+ }
}
}
@@ -6583,7 +6665,7 @@ public class BatteryStatsImpl extends BatteryStats {
/**
* Accumulates stats for a specific binder transaction.
*/
- @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
+ @VisibleForTesting
protected static class BinderCallStats {
static final Comparator<BinderCallStats> COMPARATOR =
Comparator.comparing(BinderCallStats::getClassName)
@@ -6822,6 +6904,16 @@ public class BatteryStatsImpl extends BatteryStats {
*/
private final ArraySet<BinderCallStats> mBinderCallStats = new ArraySet<>();
+ /**
+ * Estimated total time spent by the system server handling requests from this uid.
+ */
+ private long mSystemServiceTimeUs;
+
+ /**
+ * Estimated proportion of system server binder call CPU cost for this uid.
+ */
+ private double mProportionalSystemServiceUsage;
+
public Uid(BatteryStatsImpl bsi, int uid) {
mBsi = bsi;
mUid = uid;
@@ -6899,7 +6991,6 @@ public class BatteryStatsImpl extends BatteryStats {
return nullIfAllZeros(mCpuClusterTimesMs, STATS_SINCE_CHARGED);
}
-
@Override
public long[] getCpuFreqTimes(int which, int procState) {
if (which < 0 || which >= NUM_PROCESS_STATE) {
@@ -6934,10 +7025,16 @@ public class BatteryStatsImpl extends BatteryStats {
return mBinderCallCount;
}
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
public ArraySet<BinderCallStats> getBinderCallStats() {
return mBinderCallStats;
}
+ @Override
+ public double getProportionalSystemServiceUsage() {
+ return mProportionalSystemServiceUsage;
+ }
+
public void addIsolatedUid(int isolatedUid) {
if (mChildUids == null) {
mChildUids = new IntArray();
@@ -8029,9 +8126,12 @@ public class BatteryStatsImpl extends BatteryStats {
mBinderCallCount = 0;
mBinderCallStats.clear();
+ mProportionalSystemServiceUsage = 0;
+
mLastStepUserTime = mLastStepSystemTime = 0;
mCurStepUserTime = mCurStepSystemTime = 0;
+
return !active;
}
@@ -8373,28 +8473,7 @@ public class BatteryStatsImpl extends BatteryStats {
mUserCpuTime.writeToParcel(out);
mSystemCpuTime.writeToParcel(out);
- if (mCpuClusterSpeedTimesUs != null) {
- out.writeInt(1);
- out.writeInt(mCpuClusterSpeedTimesUs.length);
- for (LongSamplingCounter[] cpuSpeeds : mCpuClusterSpeedTimesUs) {
- if (cpuSpeeds != null) {
- out.writeInt(1);
- out.writeInt(cpuSpeeds.length);
- for (LongSamplingCounter c : cpuSpeeds) {
- if (c != null) {
- out.writeInt(1);
- c.writeToParcel(out);
- } else {
- out.writeInt(0);
- }
- }
- } else {
- out.writeInt(0);
- }
- }
- } else {
- out.writeInt(0);
- }
+ mBsi.writeCpuSpeedCountersToParcel(out, mCpuClusterSpeedTimesUs);
LongSamplingCounterArray.writeToParcel(out, mCpuFreqTimeMs);
LongSamplingCounterArray.writeToParcel(out, mScreenOffCpuFreqTimeMs);
@@ -8432,6 +8511,7 @@ public class BatteryStatsImpl extends BatteryStats {
} else {
out.writeInt(0);
}
+ out.writeDouble(mProportionalSystemServiceUsage);
}
void readJobCompletionsFromParcelLocked(Parcel in) {
@@ -8692,36 +8772,7 @@ public class BatteryStatsImpl extends BatteryStats {
mUserCpuTime = new LongSamplingCounter(mBsi.mOnBatteryTimeBase, in);
mSystemCpuTime = new LongSamplingCounter(mBsi.mOnBatteryTimeBase, in);
- if (in.readInt() != 0) {
- int numCpuClusters = in.readInt();
- if (mBsi.mPowerProfile != null && mBsi.mPowerProfile.getNumCpuClusters() != numCpuClusters) {
- throw new ParcelFormatException("Incompatible number of cpu clusters");
- }
-
- mCpuClusterSpeedTimesUs = new LongSamplingCounter[numCpuClusters][];
- for (int cluster = 0; cluster < numCpuClusters; cluster++) {
- if (in.readInt() != 0) {
- int numSpeeds = in.readInt();
- if (mBsi.mPowerProfile != null &&
- mBsi.mPowerProfile.getNumSpeedStepsInCpuCluster(cluster) != numSpeeds) {
- throw new ParcelFormatException("Incompatible number of cpu speeds");
- }
-
- final LongSamplingCounter[] cpuSpeeds = new LongSamplingCounter[numSpeeds];
- mCpuClusterSpeedTimesUs[cluster] = cpuSpeeds;
- for (int speed = 0; speed < numSpeeds; speed++) {
- if (in.readInt() != 0) {
- cpuSpeeds[speed] = new LongSamplingCounter(
- mBsi.mOnBatteryTimeBase, in);
- }
- }
- } else {
- mCpuClusterSpeedTimesUs[cluster] = null;
- }
- }
- } else {
- mCpuClusterSpeedTimesUs = null;
- }
+ mCpuClusterSpeedTimesUs = mBsi.readCpuSpeedCountersFromParcel(in);
mCpuFreqTimeMs = LongSamplingCounterArray.readFromParcel(in, mBsi.mOnBatteryTimeBase);
mScreenOffCpuFreqTimeMs = LongSamplingCounterArray.readFromParcel(
@@ -8762,6 +8813,8 @@ public class BatteryStatsImpl extends BatteryStats {
} else {
mWifiRadioApWakeupCount = null;
}
+
+ mProportionalSystemServiceUsage = in.readDouble();
}
public void noteJobsDeferredLocked(int numDeferred, long sinceLast) {
@@ -9904,7 +9957,6 @@ public class BatteryStatsImpl extends BatteryStats {
UserInfoProvider userInfoProvider) {
init(clocks);
-
if (systemDir == null) {
mStatsFile = null;
mBatteryStatsHistory = new BatteryStatsHistory(this, mHistoryBuffer);
@@ -10046,6 +10098,8 @@ public class BatteryStatsImpl extends BatteryStats {
firstCpuOfCluster += mPowerProfile.getNumCoresInCpuCluster(i);
}
+ mSystemServerCpuThreadReader = SystemServerCpuThreadReader.create();
+
if (mEstimatedBatteryCapacity == -1) {
// Initialize the estimated battery capacity to a known preset one.
mEstimatedBatteryCapacity = (int) mPowerProfile.getBatteryCapacity();
@@ -10726,6 +10780,9 @@ public class BatteryStatsImpl extends BatteryStats {
mTmpRailStats.reset();
+ resetIfNotNull(mSystemServerThreadCpuTimesUs, false);
+ resetIfNotNull(mBinderThreadCpuTimesUs, false);
+
mLastHistoryStepDetails = null;
mLastStepCpuUserTime = mLastStepCpuSystemTime = 0;
mCurStepCpuUserTime = mCurStepCpuSystemTime = 0;
@@ -10853,7 +10910,7 @@ public class BatteryStatsImpl extends BatteryStats {
return null;
}
- /**
+ /**
* Distribute WiFi energy info and network traffic to apps.
* @param info The energy information from the WiFi controller.
*/
@@ -11772,6 +11829,7 @@ public class BatteryStatsImpl extends BatteryStats {
for (int cluster = mKernelCpuSpeedReaders.length - 1; cluster >= 0; --cluster) {
mKernelCpuSpeedReaders[cluster].readDelta();
}
+ mSystemServerCpuThreadReader.readDelta();
return;
}
@@ -11791,6 +11849,87 @@ public class BatteryStatsImpl extends BatteryStats {
readKernelUidCpuClusterTimesLocked(onBattery);
mNumAllUidCpuTimeReads += 2;
}
+
+ updateSystemServerThreadStats();
+ }
+
+ /**
+ * Estimates the proportion of the System Server CPU activity (per cluster per speed)
+ * spent on handling incoming binder calls.
+ */
+ @VisibleForTesting
+ public void updateSystemServerThreadStats() {
+ // There are some simplifying assumptions made in this algorithm
+ // 1) We assume that if a thread handles incoming binder calls, all of its activity
+ // is spent doing that. Most incoming calls are handled by threads allocated
+ // by the native layer in the binder thread pool, so this assumption is reasonable.
+ // 2) We use the aggregate CPU time spent in different threads as a proxy for the CPU
+ // cost. In reality, in multi-core CPUs, the CPU cost may not be linearly
+ // affected by additional threads.
+
+ SystemServerCpuThreadReader.SystemServiceCpuThreadTimes systemServiceCpuThreadTimes =
+ mSystemServerCpuThreadReader.readDelta();
+
+ int index = 0;
+ int numCpuClusters = mPowerProfile.getNumCpuClusters();
+ if (mSystemServerThreadCpuTimesUs == null) {
+ mSystemServerThreadCpuTimesUs = new LongSamplingCounter[numCpuClusters][];
+ mBinderThreadCpuTimesUs = new LongSamplingCounter[numCpuClusters][];
+ }
+ for (int cluster = 0; cluster < numCpuClusters; cluster++) {
+ int numSpeeds = mPowerProfile.getNumSpeedStepsInCpuCluster(cluster);
+ if (mSystemServerThreadCpuTimesUs[cluster] == null) {
+ mSystemServerThreadCpuTimesUs[cluster] = new LongSamplingCounter[numSpeeds];
+ mBinderThreadCpuTimesUs[cluster] = new LongSamplingCounter[numSpeeds];
+ for (int speed = 0; speed < numSpeeds; speed++) {
+ mSystemServerThreadCpuTimesUs[cluster][speed] =
+ new LongSamplingCounter(mOnBatteryTimeBase);
+ mBinderThreadCpuTimesUs[cluster][speed] =
+ new LongSamplingCounter(mOnBatteryTimeBase);
+ }
+ }
+ for (int speed = 0; speed < numSpeeds; speed++) {
+ mSystemServerThreadCpuTimesUs[cluster][speed].addCountLocked(
+ systemServiceCpuThreadTimes.threadCpuTimesUs[index]);
+ mBinderThreadCpuTimesUs[cluster][speed].addCountLocked(
+ systemServiceCpuThreadTimes.binderThreadCpuTimesUs[index]);
+ index++;
+ }
+ }
+ if (DEBUG_BINDER_STATS) {
+ Slog.d(TAG, "System server threads per CPU cluster (binder threads/total threads/%)");
+ long binderThreadTime = 0;
+ long totalThreadTime = 0;
+ int cpuIndex = 0;
+ for (int cluster = 0; cluster < numCpuClusters; cluster++) {
+ StringBuilder sb = new StringBuilder();
+ sb.append("cpu").append(cpuIndex).append(": [");
+ int numSpeeds = mPowerProfile.getNumSpeedStepsInCpuCluster(cluster);
+ for (int speed = 0; speed < numSpeeds; speed++) {
+ if (speed != 0) {
+ sb.append(", ");
+ }
+ long totalCount = mSystemServerThreadCpuTimesUs[cluster][speed].getCountLocked(
+ 0) / 1000;
+ long binderCount = mBinderThreadCpuTimesUs[cluster][speed].getCountLocked(0)
+ / 1000;
+ sb.append(String.format("%d/%d(%.1f%%)",
+ binderCount,
+ totalCount,
+ totalCount != 0 ? (double) binderCount * 100 / totalCount : 0));
+
+ totalThreadTime += totalCount;
+ binderThreadTime += binderCount;
+ index++;
+ }
+ cpuIndex += mPowerProfile.getNumCoresInCpuCluster(cluster);
+ Slog.d(TAG, sb.toString());
+ }
+ Slog.d(TAG, "Total system server thread time (ms): " + totalThreadTime);
+ Slog.d(TAG, String.format("Total Binder thread time (ms): %d (%.1f%%)",
+ binderThreadTime,
+ binderThreadTime != 0 ? (double) binderThreadTime * 100 / totalThreadTime : 0));
+ }
}
/**
@@ -12998,6 +13137,75 @@ public class BatteryStatsImpl extends BatteryStats {
}
}
+
+ @Override
+ public long getSystemServiceTimeAtCpuSpeed(int cluster, int step) {
+ // Estimates the time spent by the system server handling incoming binder requests.
+ //
+ // The data that we can get from the kernel is this:
+ // - CPU duration for a (thread - cluster - CPU speed) combination
+ // - CPU duration for a (UID - cluster - CPU speed) combination
+ //
+ // The configuration we have in the Power Profile is this:
+ // - Average CPU power for a (cluster - CPU speed) combination.
+ //
+ // The model used by BatteryStats can be illustrated with this example:
+ //
+ // - Let's say the system server has 10 threads.
+ // - These 10 threads spent 1000 ms of CPU time in aggregate
+ // - Of the 10 threads 4 were execute exclusively incoming binder calls.
+ // - These 4 "binder" threads consumed 600 ms of CPU time in aggregate
+ // - The real time spent by the system server UID doing all of this is, say, 200 ms.
+ //
+ // We will assume that power consumption is proportional to the time spent by the CPU
+ // across all threads. This is a crude assumption, but we don't have more detailed data.
+ // Thus,
+ // binderRealTime = realTime * aggregateBinderThreadTime / aggregateAllThreadTime
+ //
+ // In our example,
+ // binderRealTime = 200 * 600 / 1000 = 120ms
+ //
+ // We can then multiply this estimated time by the average power to obtain an estimate
+ // of the total power consumed by incoming binder calls for the given cluster/speed
+ // combination.
+
+ if (mSystemServerThreadCpuTimesUs == null) {
+ return 0;
+ }
+
+ if (cluster < 0 || cluster >= mSystemServerThreadCpuTimesUs.length) {
+ return 0;
+ }
+
+ final LongSamplingCounter[] threadTimesForCluster = mSystemServerThreadCpuTimesUs[cluster];
+
+ if (step < 0 || step >= threadTimesForCluster.length) {
+ return 0;
+ }
+
+ Uid systemUid = mUidStats.get(Process.SYSTEM_UID);
+ if (systemUid == null) {
+ return 0;
+ }
+
+ final long uidTimeAtCpuSpeed = systemUid.getTimeAtCpuSpeed(cluster, step,
+ BatteryStats.STATS_SINCE_CHARGED);
+ if (uidTimeAtCpuSpeed == 0) {
+ return 0;
+ }
+
+ final long uidThreadTime =
+ threadTimesForCluster[step].getCountLocked(BatteryStats.STATS_SINCE_CHARGED);
+
+ if (uidThreadTime == 0) {
+ return 0;
+ }
+
+ final long binderThreadTime = mBinderThreadCpuTimesUs[cluster][step].getCountLocked(
+ BatteryStats.STATS_SINCE_CHARGED);
+ return uidTimeAtCpuSpeed * binderThreadTime / uidThreadTime;
+ }
+
/**
* Retrieve the statistics object for a particular uid, creating if needed.
*/
@@ -13327,45 +13535,7 @@ public class BatteryStatsImpl extends BatteryStats {
pw.print(uid.getUserCpuTimeUs(STATS_SINCE_CHARGED) / 1000); pw.print(" ");
pw.println(uid.getSystemCpuTimeUs(STATS_SINCE_CHARGED) / 1000);
}
- pw.println("Per UID system service calls:");
- BinderTransactionNameResolver nameResolver = new BinderTransactionNameResolver();
- for (int i = 0; i < size; i++) {
- int u = mUidStats.keyAt(i);
- Uid uid = mUidStats.get(u);
- long binderCallCount = uid.getBinderCallCount();
- if (binderCallCount != 0) {
- pw.print(" ");
- pw.print(u);
- pw.print(" system service calls: ");
- pw.print(binderCallCount);
- ArraySet<BinderCallStats> binderCallStats = uid.getBinderCallStats();
- if (!binderCallStats.isEmpty()) {
- pw.println(", including");
- BinderCallStats[] bcss = new BinderCallStats[binderCallStats.size()];
- binderCallStats.toArray(bcss);
- for (BinderCallStats bcs : bcss) {
- bcs.ensureMethodName(nameResolver);
- }
- Arrays.sort(bcss, BinderCallStats.COMPARATOR);
- for (BinderCallStats callStats : bcss) {
- pw.print(" ");
- pw.print(callStats.getClassName());
- pw.print('#');
- pw.print(callStats.getMethodName());
- pw.print(" calls: ");
- pw.print(callStats.callCount);
- if (callStats.recordedCallCount != 0) {
- pw.print(" time: ");
- pw.print(callStats.callCount * callStats.recordedCpuTimeMicros
- / callStats.recordedCallCount / 1000);
- }
- pw.println();
- }
- } else {
- pw.println();
- }
- }
- }
+
pw.println("Per UID CPU active time in ms:");
for (int i = 0; i < size; i++) {
int u = mUidStats.keyAt(i);
@@ -13390,6 +13560,30 @@ public class BatteryStatsImpl extends BatteryStats {
pw.print(" "); pw.print(u); pw.print(": "); pw.println(Arrays.toString(times));
}
}
+
+ updateSystemServiceCallStats();
+ if (mSystemServerThreadCpuTimesUs != null) {
+ pw.println("Per UID System server binder time in ms:");
+ for (int i = 0; i < size; i++) {
+ int u = mUidStats.keyAt(i);
+ Uid uid = mUidStats.get(u);
+ double proportionalSystemServiceUsage = uid.getProportionalSystemServiceUsage();
+
+ long time = 0;
+ for (int cluster = 0; cluster < mSystemServerThreadCpuTimesUs.length; cluster++) {
+ int numSpeeds = mSystemServerThreadCpuTimesUs[cluster].length;
+ for (int speed = 0; speed < numSpeeds; speed++) {
+ time += getSystemServiceTimeAtCpuSpeed(cluster, speed)
+ * proportionalSystemServiceUsage;
+ }
+ }
+
+ pw.print(" ");
+ pw.print(u);
+ pw.print(": ");
+ pw.println(time);
+ }
+ }
}
final ReentrantLock mWriteLock = new ReentrantLock();
@@ -14908,6 +15102,9 @@ public class BatteryStatsImpl extends BatteryStats {
u.readFromParcelLocked(mOnBatteryTimeBase, mOnBatteryScreenOffTimeBase, in);
mUidStats.append(uid, u);
}
+
+ mSystemServerThreadCpuTimesUs = readCpuSpeedCountersFromParcel(in);
+ mBinderThreadCpuTimesUs = readCpuSpeedCountersFromParcel(in);
}
public void writeToParcel(Parcel out, int flags) {
@@ -14923,6 +15120,8 @@ public class BatteryStatsImpl extends BatteryStats {
// Need to update with current kernel wake lock counts.
pullPendingStateUpdatesLocked();
+ updateSystemServiceCallStats();
+
// Pull the clock time. This may update the time and make a new history entry
// if we had originally pulled a time before the RTC was set.
getStartClockTime();
@@ -15105,6 +15304,73 @@ public class BatteryStatsImpl extends BatteryStats {
} else {
out.writeInt(0);
}
+ writeCpuSpeedCountersToParcel(out, mSystemServerThreadCpuTimesUs);
+ writeCpuSpeedCountersToParcel(out, mBinderThreadCpuTimesUs);
+ }
+
+ private void writeCpuSpeedCountersToParcel(Parcel out, LongSamplingCounter[][] counters) {
+ if (counters == null) {
+ out.writeInt(0);
+ return;
+ }
+
+ out.writeInt(1);
+ out.writeInt(counters.length);
+ for (int i = 0; i < counters.length; i++) {
+ LongSamplingCounter[] counterArray = counters[i];
+ if (counterArray == null) {
+ out.writeInt(0);
+ continue;
+ }
+
+ out.writeInt(1);
+ out.writeInt(counterArray.length);
+ for (int j = 0; j < counterArray.length; j++) {
+ LongSamplingCounter c = counterArray[j];
+ if (c != null) {
+ out.writeInt(1);
+ c.writeToParcel(out);
+ } else {
+ out.writeInt(0);
+ }
+ }
+ }
+ }
+
+ private LongSamplingCounter[][] readCpuSpeedCountersFromParcel(Parcel in) {
+ LongSamplingCounter[][] counters;
+ if (in.readInt() != 0) {
+ int numCpuClusters = in.readInt();
+ if (mPowerProfile != null
+ && mPowerProfile.getNumCpuClusters() != numCpuClusters) {
+ throw new ParcelFormatException("Incompatible number of cpu clusters");
+ }
+
+ counters = new LongSamplingCounter[numCpuClusters][];
+ for (int cluster = 0; cluster < numCpuClusters; cluster++) {
+ if (in.readInt() != 0) {
+ int numSpeeds = in.readInt();
+ if (mPowerProfile != null
+ && mPowerProfile.getNumSpeedStepsInCpuCluster(cluster) != numSpeeds) {
+ throw new ParcelFormatException("Incompatible number of cpu speeds");
+ }
+
+ final LongSamplingCounter[] cpuSpeeds = new LongSamplingCounter[numSpeeds];
+ counters[cluster] = cpuSpeeds;
+ for (int speed = 0; speed < numSpeeds; speed++) {
+ if (in.readInt() != 0) {
+ cpuSpeeds[speed] = new LongSamplingCounter(mOnBatteryTimeBase, in);
+ }
+ }
+ } else {
+ counters[cluster] = null;
+ }
+ }
+ } else {
+ counters = null;
+ }
+
+ return counters;
}
@UnsupportedAppUsage
diff --git a/core/java/com/android/internal/os/BinderCallsStats.java b/core/java/com/android/internal/os/BinderCallsStats.java
index e09ef49acd10..201626abd820 100644
--- a/core/java/com/android/internal/os/BinderCallsStats.java
+++ b/core/java/com/android/internal/os/BinderCallsStats.java
@@ -115,7 +115,8 @@ public class BinderCallsStats implements BinderInternal.Observer {
if (uidEntry != null) {
ArrayMap<CallStatKey, CallStat> callStats = uidEntry.mCallStats;
mCallStatsObserver.noteCallStats(uidEntry.workSourceUid,
- uidEntry.incrementalCallCount, callStats.values());
+ uidEntry.incrementalCallCount, callStats.values(),
+ mNativeTids.toArray());
uidEntry.incrementalCallCount = 0;
for (int j = callStats.size() - 1; j >= 0; j--) {
callStats.valueAt(j).incrementalCallCount = 0;
diff --git a/core/java/com/android/internal/os/BinderInternal.java b/core/java/com/android/internal/os/BinderInternal.java
index feb5aab94adc..f14d5f2bbbeb 100644
--- a/core/java/com/android/internal/os/BinderInternal.java
+++ b/core/java/com/android/internal/os/BinderInternal.java
@@ -142,7 +142,8 @@ public class BinderInternal {
* Notes incoming binder call stats associated with this work source UID.
*/
void noteCallStats(int workSourceUid, long incrementalCallCount,
- Collection<BinderCallsStats.CallStat> callStats);
+ Collection<BinderCallsStats.CallStat> callStats,
+ int[] binderThreadNativeTids);
}
/**
diff --git a/core/java/com/android/internal/os/KernelCpuThreadReader.java b/core/java/com/android/internal/os/KernelCpuThreadReader.java
index 34076700cd95..2ba372a47cf3 100644
--- a/core/java/com/android/internal/os/KernelCpuThreadReader.java
+++ b/core/java/com/android/internal/os/KernelCpuThreadReader.java
@@ -225,19 +225,22 @@ public class KernelCpuThreadReader {
/** Set the number of frequency buckets to use */
void setNumBuckets(int numBuckets) {
- if (numBuckets < 1) {
- Slog.w(TAG, "Number of buckets must be at least 1, but was " + numBuckets);
- return;
- }
// If `numBuckets` hasn't changed since the last set, do nothing
if (mFrequenciesKhz != null && mFrequenciesKhz.length == numBuckets) {
return;
}
- mFrequencyBucketCreator =
- new FrequencyBucketCreator(mProcTimeInStateReader.getFrequenciesKhz(), numBuckets);
- mFrequenciesKhz =
- mFrequencyBucketCreator.bucketFrequencies(
- mProcTimeInStateReader.getFrequenciesKhz());
+
+ final long[] frequenciesKhz = mProcTimeInStateReader.getFrequenciesKhz();
+ if (numBuckets != 0) {
+ mFrequencyBucketCreator = new FrequencyBucketCreator(frequenciesKhz, numBuckets);
+ mFrequenciesKhz = mFrequencyBucketCreator.bucketFrequencies(frequenciesKhz);
+ } else {
+ mFrequencyBucketCreator = null;
+ mFrequenciesKhz = new int[frequenciesKhz.length];
+ for (int i = 0; i < frequenciesKhz.length; i++) {
+ mFrequenciesKhz[i] = (int) frequenciesKhz[i];
+ }
+ }
}
/** Set the UID predicate for {@link #getProcessCpuUsage} */
@@ -320,8 +323,15 @@ public class KernelCpuThreadReader {
if (cpuUsagesLong == null) {
return null;
}
- int[] cpuUsages = mFrequencyBucketCreator.bucketValues(cpuUsagesLong);
-
+ final int[] cpuUsages;
+ if (mFrequencyBucketCreator != null) {
+ cpuUsages = mFrequencyBucketCreator.bucketValues(cpuUsagesLong);
+ } else {
+ cpuUsages = new int[cpuUsagesLong.length];
+ for (int i = 0; i < cpuUsagesLong.length; i++) {
+ cpuUsages[i] = (int) cpuUsagesLong[i];
+ }
+ }
return new ThreadCpuUsage(threadId, threadName, cpuUsages);
}
diff --git a/core/java/com/android/internal/os/SystemServerCpuThreadReader.java b/core/java/com/android/internal/os/SystemServerCpuThreadReader.java
new file mode 100644
index 000000000000..1cdd42c7403e
--- /dev/null
+++ b/core/java/com/android/internal/os/SystemServerCpuThreadReader.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.os;
+
+import android.os.Process;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Arrays;
+
+/**
+ * Reads /proc/UID/task/TID/time_in_state files to obtain statistics on CPU usage
+ * by various threads of the System Server.
+ */
+public class SystemServerCpuThreadReader {
+ private KernelCpuThreadReader mKernelCpuThreadReader;
+ private int[] mBinderThreadNativeTids;
+
+ private int[] mThreadCpuTimesUs;
+ private int[] mBinderThreadCpuTimesUs;
+ private long[] mLastThreadCpuTimesUs;
+ private long[] mLastBinderThreadCpuTimesUs;
+
+ /**
+ * Times (in microseconds) spent by the system server UID.
+ */
+ public static class SystemServiceCpuThreadTimes {
+ // All threads
+ public long[] threadCpuTimesUs;
+ // Just the threads handling incoming binder calls
+ public long[] binderThreadCpuTimesUs;
+ }
+
+ private SystemServiceCpuThreadTimes mDeltaCpuThreadTimes = new SystemServiceCpuThreadTimes();
+
+ /**
+ * Creates a configured instance of SystemServerCpuThreadReader.
+ */
+ public static SystemServerCpuThreadReader create() {
+ return new SystemServerCpuThreadReader(
+ KernelCpuThreadReader.create(0, uid -> uid == Process.myUid()));
+ }
+
+ @VisibleForTesting
+ public SystemServerCpuThreadReader(Path procPath, int systemServerUid) throws IOException {
+ this(new KernelCpuThreadReader(0, uid -> uid == systemServerUid, null, null,
+ new KernelCpuThreadReader.Injector() {
+ @Override
+ public int getUidForPid(int pid) {
+ return systemServerUid;
+ }
+ }));
+ }
+
+ @VisibleForTesting
+ public SystemServerCpuThreadReader(KernelCpuThreadReader kernelCpuThreadReader) {
+ mKernelCpuThreadReader = kernelCpuThreadReader;
+ }
+
+ public void setBinderThreadNativeTids(int[] nativeTids) {
+ mBinderThreadNativeTids = nativeTids;
+ }
+
+ /**
+ * Returns delta of CPU times, per thread, since the previous call to this method.
+ */
+ public SystemServiceCpuThreadTimes readDelta() {
+ if (mBinderThreadCpuTimesUs == null) {
+ int numCpuFrequencies = mKernelCpuThreadReader.getCpuFrequenciesKhz().length;
+ mThreadCpuTimesUs = new int[numCpuFrequencies];
+ mBinderThreadCpuTimesUs = new int[numCpuFrequencies];
+
+ mLastThreadCpuTimesUs = new long[numCpuFrequencies];
+ mLastBinderThreadCpuTimesUs = new long[numCpuFrequencies];
+
+ mDeltaCpuThreadTimes.threadCpuTimesUs = new long[numCpuFrequencies];
+ mDeltaCpuThreadTimes.binderThreadCpuTimesUs = new long[numCpuFrequencies];
+ }
+
+ Arrays.fill(mThreadCpuTimesUs, 0);
+ Arrays.fill(mBinderThreadCpuTimesUs, 0);
+
+ ArrayList<KernelCpuThreadReader.ProcessCpuUsage> processCpuUsage =
+ mKernelCpuThreadReader.getProcessCpuUsage();
+ int processCpuUsageSize = processCpuUsage.size();
+ for (int i = 0; i < processCpuUsageSize; i++) {
+ KernelCpuThreadReader.ProcessCpuUsage pcu = processCpuUsage.get(i);
+ ArrayList<KernelCpuThreadReader.ThreadCpuUsage> threadCpuUsages = pcu.threadCpuUsages;
+ if (threadCpuUsages != null) {
+ int threadCpuUsagesSize = threadCpuUsages.size();
+ for (int j = 0; j < threadCpuUsagesSize; j++) {
+ KernelCpuThreadReader.ThreadCpuUsage tcu = threadCpuUsages.get(j);
+ boolean isBinderThread = isBinderThread(tcu.threadId);
+
+ final int len = Math.min(tcu.usageTimesMillis.length, mThreadCpuTimesUs.length);
+ for (int k = 0; k < len; k++) {
+ int usageTimeUs = tcu.usageTimesMillis[k] * 1000;
+ mThreadCpuTimesUs[k] += usageTimeUs;
+ if (isBinderThread) {
+ mBinderThreadCpuTimesUs[k] += usageTimeUs;
+ }
+ }
+ }
+ }
+ }
+
+ for (int i = 0; i < mThreadCpuTimesUs.length; i++) {
+ if (mThreadCpuTimesUs[i] < mLastThreadCpuTimesUs[i]) {
+ mDeltaCpuThreadTimes.threadCpuTimesUs[i] = mThreadCpuTimesUs[i];
+ mDeltaCpuThreadTimes.binderThreadCpuTimesUs[i] = mBinderThreadCpuTimesUs[i];
+ } else {
+ mDeltaCpuThreadTimes.threadCpuTimesUs[i] =
+ mThreadCpuTimesUs[i] - mLastThreadCpuTimesUs[i];
+ mDeltaCpuThreadTimes.binderThreadCpuTimesUs[i] =
+ mBinderThreadCpuTimesUs[i] - mLastBinderThreadCpuTimesUs[i];
+ }
+ mLastThreadCpuTimesUs[i] = mThreadCpuTimesUs[i];
+ mLastBinderThreadCpuTimesUs[i] = mBinderThreadCpuTimesUs[i];
+ }
+
+ return mDeltaCpuThreadTimes;
+ }
+
+ private boolean isBinderThread(int threadId) {
+ if (mBinderThreadNativeTids != null) {
+ for (int i = 0; i < mBinderThreadNativeTids.length; i++) {
+ if (threadId == mBinderThreadNativeTids[i]) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+}
diff --git a/core/java/com/android/internal/os/SystemServicePowerCalculator.java b/core/java/com/android/internal/os/SystemServicePowerCalculator.java
new file mode 100644
index 000000000000..481b901b3c69
--- /dev/null
+++ b/core/java/com/android/internal/os/SystemServicePowerCalculator.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.os;
+
+import android.os.BatteryStats;
+import android.util.Log;
+
+import java.util.Arrays;
+
+/**
+ * Estimates the amount of power consumed by the System Server handling requests from
+ * a given app.
+ */
+public class SystemServicePowerCalculator extends PowerCalculator {
+ private static final boolean DEBUG = false;
+ private static final String TAG = "SystemServicePowerCalc";
+
+ private static final long MICROSEC_IN_HR = (long) 60 * 60 * 1000 * 1000;
+
+ private final PowerProfile mPowerProfile;
+ private final BatteryStats mBatteryStats;
+ // Tracks system server CPU [cluster][speed] power in milliAmp-microseconds
+ private double[][] mSystemServicePowerMaUs;
+
+ public SystemServicePowerCalculator(PowerProfile powerProfile, BatteryStats batteryStats) {
+ mPowerProfile = powerProfile;
+ mBatteryStats = batteryStats;
+ }
+
+ @Override
+ public void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs,
+ long rawUptimeUs, int statsType) {
+ final double proportionalUsage = u.getProportionalSystemServiceUsage();
+ if (proportionalUsage > 0) {
+ if (mSystemServicePowerMaUs == null) {
+ updateSystemServicePower();
+ }
+
+ double cpuPowerMaUs = 0;
+ int numCpuClusters = mPowerProfile.getNumCpuClusters();
+ for (int cluster = 0; cluster < numCpuClusters; cluster++) {
+ final int numSpeeds = mPowerProfile.getNumSpeedStepsInCpuCluster(cluster);
+ for (int speed = 0; speed < numSpeeds; speed++) {
+ cpuPowerMaUs += mSystemServicePowerMaUs[cluster][speed] * proportionalUsage;
+ }
+ }
+
+ app.systemServiceCpuPowerMah = cpuPowerMaUs / MICROSEC_IN_HR;
+ }
+ }
+
+ private void updateSystemServicePower() {
+ final int numCpuClusters = mPowerProfile.getNumCpuClusters();
+ mSystemServicePowerMaUs = new double[numCpuClusters][];
+ for (int cluster = 0; cluster < numCpuClusters; cluster++) {
+ final int numSpeeds = mPowerProfile.getNumSpeedStepsInCpuCluster(cluster);
+ mSystemServicePowerMaUs[cluster] = new double[numSpeeds];
+ for (int speed = 0; speed < numSpeeds; speed++) {
+ mSystemServicePowerMaUs[cluster][speed] =
+ mBatteryStats.getSystemServiceTimeAtCpuSpeed(cluster, speed)
+ * mPowerProfile.getAveragePowerForCpuCore(cluster, speed);
+ }
+ }
+ if (DEBUG) {
+ Log.d(TAG, "System service power per CPU cluster and frequency");
+ for (int cluster = 0; cluster < numCpuClusters; cluster++) {
+ Log.d(TAG, "Cluster[" + cluster + "]: "
+ + Arrays.toString(mSystemServicePowerMaUs[cluster]));
+ }
+ }
+ }
+
+ @Override
+ public void reset() {
+ mSystemServicePowerMaUs = null;
+ }
+}
diff --git a/core/java/com/android/internal/os/logging/MetricsLoggerWrapper.java b/core/java/com/android/internal/os/logging/MetricsLoggerWrapper.java
index ba60fa590792..b42ea7d0b769 100644
--- a/core/java/com/android/internal/os/logging/MetricsLoggerWrapper.java
+++ b/core/java/com/android/internal/os/logging/MetricsLoggerWrapper.java
@@ -16,14 +16,8 @@
package com.android.internal.os.logging;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.util.Pair;
import android.view.WindowManager.LayoutParams;
-import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.util.FrameworkStatsLog;
/**
@@ -32,81 +26,6 @@ import com.android.internal.util.FrameworkStatsLog;
*/
public class MetricsLoggerWrapper {
- private static final int METRIC_VALUE_DISMISSED_BY_TAP = 0;
- private static final int METRIC_VALUE_DISMISSED_BY_DRAG = 1;
-
- public static void logPictureInPictureDismissByTap(Context context,
- Pair<ComponentName, Integer> topActivityInfo) {
- MetricsLogger.action(context, MetricsEvent.ACTION_PICTURE_IN_PICTURE_DISMISSED,
- METRIC_VALUE_DISMISSED_BY_TAP);
- FrameworkStatsLog.write(FrameworkStatsLog.PICTURE_IN_PICTURE_STATE_CHANGED,
- getUid(context, topActivityInfo.first, topActivityInfo.second),
- topActivityInfo.first.flattenToString(),
- FrameworkStatsLog.PICTURE_IN_PICTURE_STATE_CHANGED__STATE__DISMISSED);
- }
-
- public static void logPictureInPictureDismissByDrag(Context context,
- Pair<ComponentName, Integer> topActivityInfo) {
- MetricsLogger.action(context,
- MetricsEvent.ACTION_PICTURE_IN_PICTURE_DISMISSED,
- METRIC_VALUE_DISMISSED_BY_DRAG);
- FrameworkStatsLog.write(FrameworkStatsLog.PICTURE_IN_PICTURE_STATE_CHANGED,
- getUid(context, topActivityInfo.first, topActivityInfo.second),
- topActivityInfo.first.flattenToString(),
- FrameworkStatsLog.PICTURE_IN_PICTURE_STATE_CHANGED__STATE__DISMISSED);
- }
-
- public static void logPictureInPictureMinimize(Context context, boolean isMinimized,
- Pair<ComponentName, Integer> topActivityInfo) {
- MetricsLogger.action(context, MetricsEvent.ACTION_PICTURE_IN_PICTURE_MINIMIZED,
- isMinimized);
- FrameworkStatsLog.write(FrameworkStatsLog.PICTURE_IN_PICTURE_STATE_CHANGED,
- getUid(context, topActivityInfo.first, topActivityInfo.second),
- topActivityInfo.first.flattenToString(),
- FrameworkStatsLog.PICTURE_IN_PICTURE_STATE_CHANGED__STATE__MINIMIZED);
- }
-
- /**
- * Get uid from component name and user Id
- * @return uid. -1 if not found.
- */
- private static int getUid(Context context, ComponentName componentName, int userId) {
- int uid = -1;
- if (componentName == null) {
- return uid;
- }
- try {
- uid = context.getPackageManager().getApplicationInfoAsUser(
- componentName.getPackageName(), 0, userId).uid;
- } catch (NameNotFoundException e) {
- }
- return uid;
- }
-
- public static void logPictureInPictureMenuVisible(Context context, boolean menuStateFull) {
- MetricsLogger.visibility(context, MetricsEvent.ACTION_PICTURE_IN_PICTURE_MENU,
- menuStateFull);
- }
-
- public static void logPictureInPictureEnter(Context context,
- int uid, String shortComponentName, boolean supportsEnterPipOnTaskSwitch) {
- MetricsLogger.action(context, MetricsEvent.ACTION_PICTURE_IN_PICTURE_ENTERED,
- supportsEnterPipOnTaskSwitch);
- FrameworkStatsLog.write(FrameworkStatsLog.PICTURE_IN_PICTURE_STATE_CHANGED, uid,
- shortComponentName,
- FrameworkStatsLog.PICTURE_IN_PICTURE_STATE_CHANGED__STATE__ENTERED);
- }
-
- public static void logPictureInPictureFullScreen(Context context, int uid,
- String shortComponentName) {
- MetricsLogger.action(context,
- MetricsEvent.ACTION_PICTURE_IN_PICTURE_EXPANDED_TO_FULLSCREEN);
- FrameworkStatsLog.write(FrameworkStatsLog.PICTURE_IN_PICTURE_STATE_CHANGED,
- uid,
- shortComponentName,
- FrameworkStatsLog.PICTURE_IN_PICTURE_STATE_CHANGED__STATE__EXPANDED_TO_FULL_SCREEN);
- }
-
public static void logAppOverlayEnter(int uid, String packageName, boolean changed, int type, boolean usingAlertWindow) {
if (changed) {
if (type != LayoutParams.TYPE_APPLICATION_OVERLAY) {
diff --git a/core/jni/android_hardware_input_InputApplicationHandle.cpp b/core/jni/android_hardware_input_InputApplicationHandle.cpp
index ff73c74e125e..7756a62df655 100644
--- a/core/jni/android_hardware_input_InputApplicationHandle.cpp
+++ b/core/jni/android_hardware_input_InputApplicationHandle.cpp
@@ -30,7 +30,7 @@ namespace android {
static struct {
jfieldID ptr;
jfieldID name;
- jfieldID dispatchingTimeoutNanos;
+ jfieldID dispatchingTimeoutMillis;
jfieldID token;
} gInputApplicationHandleClassInfo;
@@ -61,8 +61,8 @@ bool NativeInputApplicationHandle::updateInfo() {
mInfo.name = getStringField(env, obj, gInputApplicationHandleClassInfo.name, "<null>");
- mInfo.dispatchingTimeoutNanos =
- env->GetLongField(obj, gInputApplicationHandleClassInfo.dispatchingTimeoutNanos);
+ mInfo.dispatchingTimeoutMillis =
+ env->GetLongField(obj, gInputApplicationHandleClassInfo.dispatchingTimeoutMillis);
jobject tokenObj = env->GetObjectField(obj,
gInputApplicationHandleClassInfo.token);
@@ -144,9 +144,8 @@ int register_android_view_InputApplicationHandle(JNIEnv* env) {
GET_FIELD_ID(gInputApplicationHandleClassInfo.name, clazz,
"name", "Ljava/lang/String;");
- GET_FIELD_ID(gInputApplicationHandleClassInfo.dispatchingTimeoutNanos,
- clazz,
- "dispatchingTimeoutNanos", "J");
+ GET_FIELD_ID(gInputApplicationHandleClassInfo.dispatchingTimeoutMillis, clazz,
+ "dispatchingTimeoutMillis", "J");
GET_FIELD_ID(gInputApplicationHandleClassInfo.token, clazz,
"token", "Landroid/os/IBinder;");
diff --git a/core/jni/android_hardware_input_InputWindowHandle.cpp b/core/jni/android_hardware_input_InputWindowHandle.cpp
index 796c5c4cc521..ecdba3fcb023 100644
--- a/core/jni/android_hardware_input_InputWindowHandle.cpp
+++ b/core/jni/android_hardware_input_InputWindowHandle.cpp
@@ -47,7 +47,7 @@ static struct {
jfieldID name;
jfieldID layoutParamsFlags;
jfieldID layoutParamsType;
- jfieldID dispatchingTimeoutNanos;
+ jfieldID dispatchingTimeoutMillis;
jfieldID frameLeft;
jfieldID frameTop;
jfieldID frameRight;
@@ -118,8 +118,8 @@ bool NativeInputWindowHandle::updateInfo() {
env->GetIntField(obj, gInputWindowHandleClassInfo.layoutParamsFlags));
mInfo.type = static_cast<InputWindowInfo::Type>(
env->GetIntField(obj, gInputWindowHandleClassInfo.layoutParamsType));
- mInfo.dispatchingTimeout = decltype(mInfo.dispatchingTimeout)(
- env->GetLongField(obj, gInputWindowHandleClassInfo.dispatchingTimeoutNanos));
+ mInfo.dispatchingTimeout = std::chrono::milliseconds(
+ env->GetLongField(obj, gInputWindowHandleClassInfo.dispatchingTimeoutMillis));
mInfo.frameLeft = env->GetIntField(obj,
gInputWindowHandleClassInfo.frameLeft);
mInfo.frameTop = env->GetIntField(obj,
@@ -293,8 +293,8 @@ int register_android_view_InputWindowHandle(JNIEnv* env) {
GET_FIELD_ID(gInputWindowHandleClassInfo.layoutParamsType, clazz,
"layoutParamsType", "I");
- GET_FIELD_ID(gInputWindowHandleClassInfo.dispatchingTimeoutNanos, clazz,
- "dispatchingTimeoutNanos", "J");
+ GET_FIELD_ID(gInputWindowHandleClassInfo.dispatchingTimeoutMillis, clazz,
+ "dispatchingTimeoutMillis", "J");
GET_FIELD_ID(gInputWindowHandleClassInfo.frameLeft, clazz,
"frameLeft", "I");
diff --git a/core/jni/android_view_DisplayEventReceiver.cpp b/core/jni/android_view_DisplayEventReceiver.cpp
index 7daefd3e6544..e715be21f146 100644
--- a/core/jni/android_view_DisplayEventReceiver.cpp
+++ b/core/jni/android_view_DisplayEventReceiver.cpp
@@ -95,8 +95,8 @@ void NativeDisplayEventReceiver::dispatchVsync(nsecs_t timestamp, PhysicalDispla
ScopedLocalRef<jobject> receiverObj(env, jniGetReferent(env, mReceiverWeakGlobal));
if (receiverObj.get()) {
ALOGV("receiver %p ~ Invoking vsync handler.", this);
- env->CallVoidMethod(receiverObj.get(),
- gDisplayEventReceiverClassInfo.dispatchVsync, timestamp, displayId, count);
+ env->CallVoidMethod(receiverObj.get(), gDisplayEventReceiverClassInfo.dispatchVsync,
+ timestamp, displayId.value, count);
ALOGV("receiver %p ~ Returned from vsync handler.", this);
}
@@ -110,8 +110,8 @@ void NativeDisplayEventReceiver::dispatchHotplug(nsecs_t timestamp, PhysicalDisp
ScopedLocalRef<jobject> receiverObj(env, jniGetReferent(env, mReceiverWeakGlobal));
if (receiverObj.get()) {
ALOGV("receiver %p ~ Invoking hotplug handler.", this);
- env->CallVoidMethod(receiverObj.get(),
- gDisplayEventReceiverClassInfo.dispatchHotplug, timestamp, displayId, connected);
+ env->CallVoidMethod(receiverObj.get(), gDisplayEventReceiverClassInfo.dispatchHotplug,
+ timestamp, displayId.value, connected);
ALOGV("receiver %p ~ Returned from hotplug handler.", this);
}
@@ -126,9 +126,8 @@ void NativeDisplayEventReceiver::dispatchConfigChanged(
jniGetReferent(env, mReceiverWeakGlobal));
if (receiverObj.get()) {
ALOGV("receiver %p ~ Invoking config changed handler.", this);
- env->CallVoidMethod(receiverObj.get(),
- gDisplayEventReceiverClassInfo.dispatchConfigChanged,
- timestamp, displayId, configId);
+ env->CallVoidMethod(receiverObj.get(), gDisplayEventReceiverClassInfo.dispatchConfigChanged,
+ timestamp, displayId.value, configId);
ALOGV("receiver %p ~ Returned from config changed handler.", this);
}
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index 814a07e7f2df..d6a773fb91e0 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -703,7 +703,7 @@ static jlongArray nativeGetPhysicalDisplayIds(JNIEnv* env, jclass clazz) {
jlong* values = env->GetLongArrayElements(array, 0);
for (size_t i = 0; i < displayIds.size(); ++i) {
- values[i] = static_cast<jlong>(displayIds[i]);
+ values[i] = static_cast<jlong>(displayIds[i].value);
}
env->ReleaseLongArrayElements(array, values, 0);
@@ -711,7 +711,8 @@ static jlongArray nativeGetPhysicalDisplayIds(JNIEnv* env, jclass clazz) {
}
static jobject nativeGetPhysicalDisplayToken(JNIEnv* env, jclass clazz, jlong physicalDisplayId) {
- sp<IBinder> token = SurfaceComposerClient::getPhysicalDisplayToken(physicalDisplayId);
+ sp<IBinder> token =
+ SurfaceComposerClient::getPhysicalDisplayToken(PhysicalDisplayId(physicalDisplayId));
return javaObjectForIBinder(env, token);
}
diff --git a/core/tests/coretests/src/android/widget/EditorCursorDragTest.java b/core/tests/coretests/src/android/widget/EditorCursorDragTest.java
index df2946c97d20..c37a34a68549 100644
--- a/core/tests/coretests/src/android/widget/EditorCursorDragTest.java
+++ b/core/tests/coretests/src/android/widget/EditorCursorDragTest.java
@@ -201,6 +201,38 @@ public class EditorCursorDragTest {
}
@Test
+ public void testCursorDrag_diagonal_thresholdConfig() throws Throwable {
+ TextView tv = mActivity.findViewById(R.id.textview);
+ Editor editor = tv.getEditorForTesting();
+
+ StringBuilder sb = new StringBuilder();
+ for (int i = 1; i <= 9; i++) {
+ sb.append("here is some text").append(i).append("\n");
+ }
+ sb.append(Strings.repeat("abcdefghij\n", 400)).append("Last");
+ String text = sb.toString();
+ onView(withId(R.id.textview)).perform(replaceText(text));
+
+ int index = text.indexOf("text9");
+ onView(withId(R.id.textview)).perform(clickOnTextAtIndex(index));
+ onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(index));
+
+ // Configure the drag direction threshold to require the drag to be exactly horizontal. With
+ // this set, a swipe that is slightly off horizontal should not trigger cursor drag.
+ editor.setCursorDragMinAngleFromVertical(90);
+ int startIdx = text.indexOf("5");
+ int endIdx = text.indexOf("here is some text3");
+ onView(withId(R.id.textview)).perform(dragOnText(startIdx, endIdx));
+ onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(index));
+
+ // Configure the drag direction threshold to require the drag to be 45 degrees or more from
+ // vertical. With this set, the same swipe gesture as above should now trigger cursor drag.
+ editor.setCursorDragMinAngleFromVertical(45);
+ onView(withId(R.id.textview)).perform(dragOnText(startIdx, endIdx));
+ onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(endIdx));
+ }
+
+ @Test
public void testCursorDrag_vertical_whenTextViewContentsFitOnScreen() throws Throwable {
String text = "012345_aaa\n"
+ "0123456789\n"
diff --git a/core/tests/coretests/src/android/widget/EditorTouchStateTest.java b/core/tests/coretests/src/android/widget/EditorTouchStateTest.java
index 35fd4bd7dc14..94f43def240d 100644
--- a/core/tests/coretests/src/android/widget/EditorTouchStateTest.java
+++ b/core/tests/coretests/src/android/widget/EditorTouchStateTest.java
@@ -165,7 +165,7 @@ public class EditorTouchStateTest {
long event2Time = 1001;
MotionEvent event2 = moveEvent(event1Time, event2Time, 200f, 31f);
mTouchState.update(event2, mConfig);
- assertDrag(mTouchState, 20f, 30f, 0, 0, false);
+ assertDrag(mTouchState, 20f, 30f, 0, 0, 180f);
// Simulate an ACTION_UP event with a delay that's longer than the double-tap timeout.
long event3Time = 5000;
@@ -280,7 +280,7 @@ public class EditorTouchStateTest {
long event3Time = 1002;
MotionEvent event3 = moveEvent(event3Time, event3Time, newX, newY);
mTouchState.update(event3, mConfig);
- assertDrag(mTouchState, 20f, 30f, 0, 0, false);
+ assertDrag(mTouchState, 20f, 30f, 0, 0, Float.MAX_VALUE);
// Simulate an ACTION_UP event.
long event4Time = 1003;
@@ -301,15 +301,15 @@ public class EditorTouchStateTest {
long event2Time = 1002;
MotionEvent event2 = moveEvent(event1Time, event2Time, 100f, 174f);
mTouchState.update(event2, mConfig);
- assertDrag(mTouchState, 0f, 0f, 0, 0, true);
+ assertDrag(mTouchState, 0f, 0f, 0, 0, 100f / 174f);
// Simulate another ACTION_MOVE event that is horizontal from the original down event.
- // The value of `isDragCloseToVertical` should NOT change since it should only reflect the
- // initial direction of movement.
+ // The drag direction ratio should NOT change since it should only reflect the initial
+ // direction of movement.
long event3Time = 1003;
MotionEvent event3 = moveEvent(event1Time, event3Time, 200f, 0f);
mTouchState.update(event3, mConfig);
- assertDrag(mTouchState, 0f, 0f, 0, 0, true);
+ assertDrag(mTouchState, 0f, 0f, 0, 0, 100f / 174f);
// Simulate an ACTION_UP event.
long event4Time = 1004;
@@ -330,15 +330,15 @@ public class EditorTouchStateTest {
long event2Time = 1002;
MotionEvent event2 = moveEvent(event1Time, event2Time, 100f, 90f);
mTouchState.update(event2, mConfig);
- assertDrag(mTouchState, 0f, 0f, 0, 0, false);
+ assertDrag(mTouchState, 0f, 0f, 0, 0, 100f / 90f);
// Simulate another ACTION_MOVE event that is vertical from the original down event.
- // The value of `isDragCloseToVertical` should NOT change since it should only reflect the
- // initial direction of movement.
+ // The drag direction ratio should NOT change since it should only reflect the initial
+ // direction of movement.
long event3Time = 1003;
MotionEvent event3 = moveEvent(event1Time, event3Time, 0f, 200f);
mTouchState.update(event3, mConfig);
- assertDrag(mTouchState, 0f, 0f, 0, 0, false);
+ assertDrag(mTouchState, 0f, 0f, 0, 0, 100f / 90f);
// Simulate an ACTION_UP event.
long event4Time = 1004;
@@ -374,7 +374,7 @@ public class EditorTouchStateTest {
long event2Time = 1002;
MotionEvent event2 = moveEvent(event2Time, event2Time, 200f, 30f);
mTouchState.update(event2, mConfig);
- assertDrag(mTouchState, 20f, 30f, 0, 0, false);
+ assertDrag(mTouchState, 20f, 30f, 0, 0, Float.MAX_VALUE);
// Simulate an ACTION_CANCEL event.
long event3Time = 1003;
@@ -411,6 +411,84 @@ public class EditorTouchStateTest {
assertSingleTap(mTouchState, 22f, 33f, 20f, 30f);
}
+ @Test
+ public void testGetXYRatio() throws Exception {
+ doTestGetXYRatio(-1, 0.0f);
+ doTestGetXYRatio(0, 0.0f);
+ doTestGetXYRatio(30, 0.58f);
+ doTestGetXYRatio(45, 1.0f);
+ doTestGetXYRatio(60, 1.73f);
+ doTestGetXYRatio(90, Float.MAX_VALUE);
+ doTestGetXYRatio(91, Float.MAX_VALUE);
+ }
+
+ private void doTestGetXYRatio(int angleFromVerticalInDegrees, float expectedXYRatioRounded) {
+ float result = EditorTouchState.getXYRatio(angleFromVerticalInDegrees);
+ String msg = String.format(
+ "%d deg should give an x/y ratio of %f; actual unrounded result is %f",
+ angleFromVerticalInDegrees, expectedXYRatioRounded, result);
+ float roundedResult = (result == 0.0f || result == Float.MAX_VALUE) ? result :
+ Math.round(result * 100) / 100f;
+ assertThat(msg, roundedResult, is(expectedXYRatioRounded));
+ }
+
+ @Test
+ public void testUpdate_dragDirection() throws Exception {
+ // Simulate moving straight up.
+ doTestDragDirection(100f, 100f, 100f, 50f, 0f);
+
+ // Simulate moving straight down.
+ doTestDragDirection(100f, 100f, 100f, 150f, 0f);
+
+ // Simulate moving straight left.
+ doTestDragDirection(100f, 100f, 50f, 100f, Float.MAX_VALUE);
+
+ // Simulate moving straight right.
+ doTestDragDirection(100f, 100f, 150f, 100f, Float.MAX_VALUE);
+
+ // Simulate moving up and right, < 45 deg from vertical.
+ doTestDragDirection(100f, 100f, 110f, 50f, 10f / 50f);
+
+ // Simulate moving up and right, > 45 deg from vertical.
+ doTestDragDirection(100f, 100f, 150f, 90f, 50f / 10f);
+
+ // Simulate moving down and right, < 45 deg from vertical.
+ doTestDragDirection(100f, 100f, 110f, 150f, 10f / 50f);
+
+ // Simulate moving down and right, > 45 deg from vertical.
+ doTestDragDirection(100f, 100f, 150f, 110f, 50f / 10f);
+
+ // Simulate moving down and left, < 45 deg from vertical.
+ doTestDragDirection(100f, 100f, 90f, 150f, 10f / 50f);
+
+ // Simulate moving down and left, > 45 deg from vertical.
+ doTestDragDirection(100f, 100f, 50f, 110f, 50f / 10f);
+
+ // Simulate moving up and left, < 45 deg from vertical.
+ doTestDragDirection(100f, 100f, 90f, 50f, 10f / 50f);
+
+ // Simulate moving up and left, > 45 deg from vertical.
+ doTestDragDirection(100f, 100f, 50f, 90f, 50f / 10f);
+ }
+
+ private void doTestDragDirection(float downX, float downY, float moveX, float moveY,
+ float expectedInitialDragDirectionXYRatio) {
+ EditorTouchState touchState = new EditorTouchState();
+
+ // Simulate an ACTION_DOWN event.
+ long event1Time = 1001;
+ MotionEvent event1 = downEvent(event1Time, event1Time, downX, downY);
+ touchState.update(event1, mConfig);
+
+ // Simulate an ACTION_MOVE event.
+ long event2Time = 1002;
+ MotionEvent event2 = moveEvent(event1Time, event2Time, moveX, moveY);
+ touchState.update(event2, mConfig);
+ String msg = String.format("(%.0f,%.0f)=>(%.0f,%.0f)", downX, downY, moveX, moveY);
+ assertThat(msg, touchState.getInitialDragDirectionXYRatio(),
+ is(expectedInitialDragDirectionXYRatio));
+ }
+
private static MotionEvent downEvent(long downTime, long eventTime, float x, float y) {
return MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_DOWN, x, y, 0);
}
@@ -441,7 +519,7 @@ public class EditorTouchStateTest {
}
private static void assertDrag(EditorTouchState touchState, float lastDownX,
- float lastDownY, float lastUpX, float lastUpY, boolean isDragCloseToVertical) {
+ float lastDownY, float lastUpX, float lastUpY, float initialDragDirectionXYRatio) {
assertThat(touchState.getLastDownX(), is(lastDownX));
assertThat(touchState.getLastDownY(), is(lastDownY));
assertThat(touchState.getLastUpX(), is(lastUpX));
@@ -451,7 +529,7 @@ public class EditorTouchStateTest {
assertThat(touchState.isMultiTap(), is(false));
assertThat(touchState.isMultiTapInSameArea(), is(false));
assertThat(touchState.isMovedEnoughForDrag(), is(true));
- assertThat(touchState.isDragCloseToVertical(), is(isDragCloseToVertical));
+ assertThat(touchState.getInitialDragDirectionXYRatio(), is(initialDragDirectionXYRatio));
}
private static void assertMultiTap(EditorTouchState touchState,
@@ -467,6 +545,5 @@ public class EditorTouchStateTest {
|| multiTapStatus == MultiTapStatus.TRIPLE_CLICK));
assertThat(touchState.isMultiTapInSameArea(), is(isMultiTapInSameArea));
assertThat(touchState.isMovedEnoughForDrag(), is(false));
- assertThat(touchState.isDragCloseToVertical(), is(false));
}
}
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsBinderCallStatsTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsBinderCallStatsTest.java
index 3e67b8bffa63..22c41f3c9622 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsBinderCallStatsTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsBinderCallStatsTest.java
@@ -38,7 +38,8 @@ import java.util.Collection;
@SmallTest
public class BatteryStatsBinderCallStatsTest extends TestCase {
- private static final int TRANSACTION_CODE = 100;
+ private static final int TRANSACTION_CODE1 = 100;
+ private static final int TRANSACTION_CODE2 = 101;
/**
* Test BatteryStatsImpl.Uid.noteBinderCallStats.
@@ -53,23 +54,23 @@ public class BatteryStatsBinderCallStatsTest extends TestCase {
Collection<BinderCallsStats.CallStat> callStats = new ArrayList<>();
BinderCallsStats.CallStat stat1 = new BinderCallsStats.CallStat(callingUid,
- MockBinder.class, TRANSACTION_CODE, true /*screenInteractive */);
+ MockBinder.class, TRANSACTION_CODE1, true /*screenInteractive */);
stat1.incrementalCallCount = 21;
stat1.recordedCallCount = 5;
stat1.cpuTimeMicros = 1000;
callStats.add(stat1);
- bi.noteBinderCallStats(workSourceUid, 42, callStats);
+ bi.noteBinderCallStats(workSourceUid, 42, callStats, null);
callStats.clear();
BinderCallsStats.CallStat stat2 = new BinderCallsStats.CallStat(callingUid,
- MockBinder.class, TRANSACTION_CODE, true /*screenInteractive */);
+ MockBinder.class, TRANSACTION_CODE1, true /*screenInteractive */);
stat2.incrementalCallCount = 9;
stat2.recordedCallCount = 8;
stat2.cpuTimeMicros = 500;
callStats.add(stat2);
- bi.noteBinderCallStats(workSourceUid, 8, callStats);
+ bi.noteBinderCallStats(workSourceUid, 8, callStats, null);
BatteryStatsImpl.Uid uid = bi.getUidStatsLocked(workSourceUid);
assertEquals(42 + 8, uid.getBinderCallCount());
@@ -85,9 +86,62 @@ public class BatteryStatsBinderCallStatsTest extends TestCase {
assertEquals(500, value.recordedCpuTimeMicros);
}
+
+ @Test
+ public void testProportionalSystemServiceUsage_noStatsForSomeMethods() throws Exception {
+ final MockClocks clocks = new MockClocks(); // holds realtime and uptime in ms
+ MockBatteryStatsImpl bi = new MockBatteryStatsImpl(clocks);
+
+ int callingUid = Process.FIRST_APPLICATION_UID + 1;
+ int workSourceUid1 = Process.FIRST_APPLICATION_UID + 1;
+ int workSourceUid2 = Process.FIRST_APPLICATION_UID + 2;
+ int workSourceUid3 = Process.FIRST_APPLICATION_UID + 3;
+
+ Collection<BinderCallsStats.CallStat> callStats = new ArrayList<>();
+ BinderCallsStats.CallStat stat1a = new BinderCallsStats.CallStat(callingUid,
+ MockBinder.class, TRANSACTION_CODE1, true /*screenInteractive */);
+ stat1a.incrementalCallCount = 10;
+ stat1a.recordedCallCount = 5;
+ stat1a.cpuTimeMicros = 1000;
+ callStats.add(stat1a);
+
+ BinderCallsStats.CallStat stat1b = new BinderCallsStats.CallStat(callingUid,
+ MockBinder.class, TRANSACTION_CODE2, true /*screenInteractive */);
+ stat1b.incrementalCallCount = 30;
+ stat1b.recordedCallCount = 15;
+ stat1b.cpuTimeMicros = 1500;
+ callStats.add(stat1b);
+
+ bi.noteBinderCallStats(workSourceUid1, 65, callStats, null);
+
+ // No recorded stats for some methods. Must use the global average.
+ callStats.clear();
+ BinderCallsStats.CallStat stat2 = new BinderCallsStats.CallStat(callingUid,
+ MockBinder.class, TRANSACTION_CODE1, true /*screenInteractive */);
+ stat2.incrementalCallCount = 10;
+ callStats.add(stat2);
+
+ bi.noteBinderCallStats(workSourceUid2, 40, callStats, null);
+
+ // No stats for any calls. Must use the global average
+ callStats.clear();
+ bi.noteBinderCallStats(workSourceUid3, 50, callStats, null);
+
+ bi.updateSystemServiceCallStats();
+
+ double prop1 = bi.getUidStatsLocked(workSourceUid1).getProportionalSystemServiceUsage();
+ double prop2 = bi.getUidStatsLocked(workSourceUid2).getProportionalSystemServiceUsage();
+ double prop3 = bi.getUidStatsLocked(workSourceUid3).getProportionalSystemServiceUsage();
+
+ assertEquals(0.419, prop1, 0.01);
+ assertEquals(0.258, prop2, 0.01);
+ assertEquals(0.323, prop3, 0.01);
+ assertEquals(1.000, prop1 + prop2 + prop3, 0.01);
+ }
+
private static class MockBinder extends Binder {
public static String getDefaultTransactionName(int txCode) {
- return txCode == TRANSACTION_CODE ? "testMethod" : "unknown";
+ return txCode == TRANSACTION_CODE1 ? "testMethod" : "unknown";
}
}
}
diff --git a/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java b/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java
index a5117a3e7cc3..188ba9e0ca0e 100644
--- a/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BinderCallsStatsTest.java
@@ -768,8 +768,8 @@ public class BinderCallsStatsTest {
final ArrayList<BinderCallsStats.CallStat> callStatsList = new ArrayList<>();
bcs.setCallStatsObserver(
- (workSourceUid, incrementalCallCount, callStats) -> callStatsList.addAll(
- callStats));
+ (workSourceUid, incrementalCallCount, callStats, binderThreadIds) ->
+ callStatsList.addAll(callStats));
Binder binder = new Binder();
diff --git a/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java b/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java
index bc0e0a496d80..75dd7fb82f30 100644
--- a/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java
+++ b/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java
@@ -133,6 +133,12 @@ public class MockBatteryStatsImpl extends BatteryStatsImpl {
return this;
}
+ public MockBatteryStatsImpl setSystemServerCpuThreadReader(
+ SystemServerCpuThreadReader systemServerCpuThreadReader) {
+ mSystemServerCpuThreadReader = systemServerCpuThreadReader;
+ return this;
+ }
+
public MockBatteryStatsImpl setUserInfoProvider(UserInfoProvider provider) {
mUserInfoProvider = provider;
return this;
diff --git a/core/tests/coretests/src/com/android/internal/os/SystemServerCpuThreadReaderTest.java b/core/tests/coretests/src/com/android/internal/os/SystemServerCpuThreadReaderTest.java
new file mode 100644
index 000000000000..10ba54865dbe
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/os/SystemServerCpuThreadReaderTest.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.os;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertTrue;
+
+import android.content.Context;
+import android.os.FileUtils;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class SystemServerCpuThreadReaderTest {
+ private File mProcDirectory;
+
+ @Before
+ public void setUp() {
+ Context context = InstrumentationRegistry.getContext();
+ mProcDirectory = context.getDir("proc", Context.MODE_PRIVATE);
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ FileUtils.deleteContents(mProcDirectory);
+ }
+
+ @Test
+ public void testReaderDelta_firstTime() throws IOException {
+ int uid = 42;
+ setupDirectory(
+ mProcDirectory.toPath().resolve(String.valueOf(uid)),
+ new int[]{42, 1, 2, 3},
+ new int[]{1000, 2000},
+ // Units are 10ms aka 10000Us
+ new int[][]{{100, 200}, {0, 200}, {0, 300}, {0, 400}});
+
+ SystemServerCpuThreadReader reader = new SystemServerCpuThreadReader(
+ mProcDirectory.toPath(), uid);
+ reader.setBinderThreadNativeTids(new int[]{1, 3});
+ SystemServerCpuThreadReader.SystemServiceCpuThreadTimes systemServiceCpuThreadTimes =
+ reader.readDelta();
+ assertArrayEquals(new long[]{100 * 10000, 1100 * 10000},
+ systemServiceCpuThreadTimes.threadCpuTimesUs);
+ assertArrayEquals(new long[]{0, 600 * 10000},
+ systemServiceCpuThreadTimes.binderThreadCpuTimesUs);
+ }
+
+ @Test
+ public void testReaderDelta_nextTime() throws IOException {
+ int uid = 42;
+ setupDirectory(
+ mProcDirectory.toPath().resolve(String.valueOf(uid)),
+ new int[]{42, 1, 2, 3},
+ new int[]{1000, 2000},
+ new int[][]{{100, 200}, {0, 200}, {0, 300}, {0, 400}});
+
+ SystemServerCpuThreadReader reader = new SystemServerCpuThreadReader(
+ mProcDirectory.toPath(), uid);
+ reader.setBinderThreadNativeTids(new int[]{1, 3});
+
+ // First time, populate "last" snapshot
+ reader.readDelta();
+
+ FileUtils.deleteContents(mProcDirectory);
+ setupDirectory(
+ mProcDirectory.toPath().resolve(String.valueOf(uid)),
+ new int[]{42, 1, 2, 3},
+ new int[]{1000, 2000},
+ new int[][]{{500, 600}, {700, 800}, {900, 1000}, {1100, 1200}});
+
+ // Second time, get the actual delta
+ SystemServerCpuThreadReader.SystemServiceCpuThreadTimes systemServiceCpuThreadTimes =
+ reader.readDelta();
+
+ assertArrayEquals(new long[]{3100 * 10000, 2500 * 10000},
+ systemServiceCpuThreadTimes.threadCpuTimesUs);
+ assertArrayEquals(new long[]{1800 * 10000, 1400 * 10000},
+ systemServiceCpuThreadTimes.binderThreadCpuTimesUs);
+ }
+
+ private void setupDirectory(Path processPath, int[] threadIds, int[] cpuFrequencies,
+ int[][] cpuTimes) throws IOException {
+ // Make /proc/$PID
+ assertTrue(processPath.toFile().mkdirs());
+
+ // Make /proc/$PID/task
+ final Path selfThreadsPath = processPath.resolve("task");
+ assertTrue(selfThreadsPath.toFile().mkdirs());
+
+ // Make thread directories in reverse order, as they are read in order of creation by
+ // CpuThreadProcReader
+ for (int i = 0; i < threadIds.length; i++) {
+ // Make /proc/$PID/task/$TID
+ final Path threadPath = selfThreadsPath.resolve(String.valueOf(threadIds[i]));
+ assertTrue(threadPath.toFile().mkdirs());
+
+ // Make /proc/$PID/task/$TID/time_in_state
+ final OutputStream timeInStateStream =
+ Files.newOutputStream(threadPath.resolve("time_in_state"));
+ for (int j = 0; j < cpuFrequencies.length; j++) {
+ final String line = cpuFrequencies[j] + " " + cpuTimes[i][j] + "\n";
+ timeInStateStream.write(line.getBytes());
+ }
+ timeInStateStream.close();
+ }
+ }
+}
diff --git a/core/tests/coretests/src/com/android/internal/os/SystemServicePowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/SystemServicePowerCalculatorTest.java
new file mode 100644
index 000000000000..ac5443e1c7ce
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/os/SystemServicePowerCalculatorTest.java
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.os;
+
+import static org.junit.Assert.assertEquals;
+
+import android.content.Context;
+import android.os.BatteryStats;
+import android.os.Binder;
+import android.os.Process;
+
+import androidx.annotation.Nullable;
+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 java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class SystemServicePowerCalculatorTest {
+
+ private PowerProfile mProfile;
+ private MockBatteryStatsImpl mMockBatteryStats;
+ private MockKernelCpuUidFreqTimeReader mMockCpuUidFreqTimeReader;
+ private MockServerCpuThreadReader mMockServerCpuThreadReader;
+ private SystemServicePowerCalculator mSystemServicePowerCalculator;
+
+ @Before
+ public void setUp() throws IOException {
+ Context context = InstrumentationRegistry.getContext();
+ mProfile = new PowerProfile(context, true /* forTest */);
+ mMockServerCpuThreadReader = new MockServerCpuThreadReader();
+ mMockCpuUidFreqTimeReader = new MockKernelCpuUidFreqTimeReader();
+ mMockBatteryStats = new MockBatteryStatsImpl(new MockClocks())
+ .setPowerProfile(mProfile)
+ .setSystemServerCpuThreadReader(mMockServerCpuThreadReader)
+ .setKernelCpuUidFreqTimeReader(mMockCpuUidFreqTimeReader)
+ .setUserInfoProvider(new MockUserInfoProvider());
+ mMockBatteryStats.getOnBatteryTimeBase().setRunning(true, 0, 0);
+ mSystemServicePowerCalculator =
+ new SystemServicePowerCalculator(mProfile, mMockBatteryStats);
+ }
+
+ @Test
+ public void testCalculateApp() {
+ // Test Power Profile has two CPU clusters with 3 and 4 speeds, thus 7 freq times total
+ mMockServerCpuThreadReader.setThreadTimes(
+ new long[]{30000, 40000, 50000, 60000, 70000, 80000, 90000},
+ new long[]{20000, 30000, 40000, 50000, 60000, 70000, 80000});
+
+ mMockCpuUidFreqTimeReader.setSystemServerCpuTimes(
+ new long[]{10000, 20000, 30000, 40000, 50000, 60000, 70000}
+ );
+
+ mMockBatteryStats.readKernelUidCpuFreqTimesLocked(null, true, false);
+
+ int workSourceUid1 = 100;
+ int workSourceUid2 = 200;
+ int transactionCode = 42;
+
+ Collection<BinderCallsStats.CallStat> callStats = new ArrayList<>();
+ BinderCallsStats.CallStat stat1 = new BinderCallsStats.CallStat(workSourceUid1,
+ Binder.class, transactionCode, true /*screenInteractive */);
+ stat1.incrementalCallCount = 100;
+ stat1.recordedCallCount = 100;
+ stat1.cpuTimeMicros = 1000000;
+ callStats.add(stat1);
+
+ mMockBatteryStats.noteBinderCallStats(workSourceUid1, 100, callStats, null);
+
+ callStats.clear();
+ BinderCallsStats.CallStat stat2 = new BinderCallsStats.CallStat(workSourceUid2,
+ Binder.class, transactionCode, true /*screenInteractive */);
+ stat2.incrementalCallCount = 100;
+ stat2.recordedCallCount = 100;
+ stat2.cpuTimeMicros = 9000000;
+ callStats.add(stat2);
+
+ mMockBatteryStats.noteBinderCallStats(workSourceUid2, 100, callStats, null);
+
+ mMockBatteryStats.updateSystemServiceCallStats();
+ mMockBatteryStats.updateSystemServerThreadStats();
+
+ BatterySipper app1 = new BatterySipper(BatterySipper.DrainType.APP,
+ mMockBatteryStats.getUidStatsLocked(workSourceUid1), 0);
+ mSystemServicePowerCalculator.calculateApp(app1, app1.uidObj, 0, 0,
+ BatteryStats.STATS_SINCE_CHARGED);
+ assertEquals(0.27162, app1.systemServiceCpuPowerMah, 0.00001);
+
+ BatterySipper app2 = new BatterySipper(BatterySipper.DrainType.APP,
+ mMockBatteryStats.getUidStatsLocked(workSourceUid2), 0);
+ mSystemServicePowerCalculator.calculateApp(app2, app2.uidObj, 0, 0,
+ BatteryStats.STATS_SINCE_CHARGED);
+ assertEquals(2.44458, app2.systemServiceCpuPowerMah, 0.00001);
+ }
+
+ private static class MockKernelCpuUidFreqTimeReader extends
+ KernelCpuUidTimeReader.KernelCpuUidFreqTimeReader {
+ private long[] mSystemServerCpuTimes;
+
+ MockKernelCpuUidFreqTimeReader() {
+ super(/*throttle */false);
+ }
+
+ void setSystemServerCpuTimes(long[] systemServerCpuTimes) {
+ mSystemServerCpuTimes = systemServerCpuTimes;
+ }
+
+ @Override
+ public boolean perClusterTimesAvailable() {
+ return true;
+ }
+
+ @Override
+ public void readDelta(@Nullable Callback<long[]> cb) {
+ if (cb != null) {
+ cb.onUidCpuTime(Process.SYSTEM_UID, mSystemServerCpuTimes);
+ }
+ }
+ }
+
+ private static class MockServerCpuThreadReader extends SystemServerCpuThreadReader {
+ private SystemServiceCpuThreadTimes mThreadTimes = new SystemServiceCpuThreadTimes();
+
+ MockServerCpuThreadReader() {
+ super(null);
+ }
+
+ public void setThreadTimes(long[] threadCpuTimesUs, long[] binderThreadCpuTimesUs) {
+ mThreadTimes.threadCpuTimesUs = threadCpuTimesUs;
+ mThreadTimes.binderThreadCpuTimesUs = binderThreadCpuTimesUs;
+ }
+
+ @Override
+ public SystemServiceCpuThreadTimes readDelta() {
+ return mThreadTimes;
+ }
+ }
+
+ private static class MockUserInfoProvider extends BatteryStatsImpl.UserInfoProvider {
+ @Nullable
+ @Override
+ protected int[] getUserIds() {
+ return new int[0];
+ }
+
+ @Override
+ public boolean exists(int userId) {
+ return true;
+ }
+ }
+}
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index f834ce798a27..b3c82631011a 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -432,18 +432,6 @@ applications that come with the platform
<permission name="android.permission.CAPTURE_AUDIO_OUTPUT" />
<!-- Permissions required for CTS test - AdbManagerTest -->
<permission name="android.permission.MANAGE_DEBUGGING" />
- <!-- Permissions required for ATS tests - AtsCarHostTestCases, AtsCarDeviceApp -->
- <permission name="android.car.permission.CAR_DRIVING_STATE" />
- <!-- Permissions required for ATS tests - AtsDeviceInfo, AtsAudioDeviceTestCases -->
- <permission name="android.car.permission.CAR_CONTROL_AUDIO_VOLUME" />
- <!-- Permissions required for ATS tests - AtsDeviceInfo -->
- <permission name="android.car.permission.CAR_DIAGNOSTICS" />
- <!-- Permissions required for ATS tests - AtsDeviceInfo -->
- <permission name="android.car.permission.CLEAR_CAR_DIAGNOSTICS" />
- <!-- Permissions required for ATS tests - AtsCarHostTestCases -->
- <permission name="android.car.permission.CONTROL_APP_BLOCKING" />
- <!-- Permissions required for ATS tests - AtsCarHostTestCases -->
- <permission name="android.car.permission.CAR_UX_RESTRICTIONS_CONFIGURATION" />
</privapp-permissions>
<privapp-permissions package="com.android.statementservice">
diff --git a/errorprone/java/com/google/errorprone/bugpatterns/android/UidChecker.java b/errorprone/java/com/google/errorprone/bugpatterns/android/UidChecker.java
index 3ffb8ea40789..a2ee065cd1cc 100644
--- a/errorprone/java/com/google/errorprone/bugpatterns/android/UidChecker.java
+++ b/errorprone/java/com/google/errorprone/bugpatterns/android/UidChecker.java
@@ -23,12 +23,15 @@ import com.google.errorprone.BugPattern;
import com.google.errorprone.VisitorState;
import com.google.errorprone.bugpatterns.BugChecker;
import com.google.errorprone.bugpatterns.BugChecker.MethodInvocationTreeMatcher;
+import com.google.errorprone.bugpatterns.BugChecker.NewClassTreeMatcher;
import com.google.errorprone.matchers.Description;
import com.google.errorprone.util.ASTHelpers;
import com.sun.source.tree.ExpressionTree;
import com.sun.source.tree.IdentifierTree;
import com.sun.source.tree.MemberSelectTree;
import com.sun.source.tree.MethodInvocationTree;
+import com.sun.source.tree.NewClassTree;
+import com.sun.source.tree.Tree;
import com.sun.tools.javac.code.Symbol.VarSymbol;
import java.util.List;
@@ -44,11 +47,20 @@ import java.util.regex.Pattern;
name = "AndroidFrameworkUid",
summary = "Verifies that PID, UID and user ID arguments aren't crossed",
severity = WARNING)
-public final class UidChecker extends BugChecker implements MethodInvocationTreeMatcher {
+public final class UidChecker extends BugChecker implements MethodInvocationTreeMatcher,
+ NewClassTreeMatcher {
@Override
public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState state) {
- final List<VarSymbol> vars = ASTHelpers.getSymbol(tree).params();
- final List<? extends ExpressionTree> args = tree.getArguments();
+ return matchArguments(ASTHelpers.getSymbol(tree).params(), tree.getArguments(), tree);
+ }
+
+ @Override
+ public Description matchNewClass(NewClassTree tree, VisitorState state) {
+ return matchArguments(ASTHelpers.getSymbol(tree).params(), tree.getArguments(), tree);
+ }
+
+ private Description matchArguments(List<VarSymbol> vars,
+ List<? extends ExpressionTree> args, Tree tree) {
for (int i = 0; i < Math.min(vars.size(), args.size()); i++) {
final Flavor varFlavor = getFlavor(vars.get(i));
final Flavor argFlavor = getFlavor(args.get(i));
diff --git a/errorprone/tests/java/com/google/errorprone/bugpatterns/android/UidCheckerTest.java b/errorprone/tests/java/com/google/errorprone/bugpatterns/android/UidCheckerTest.java
index 74da94731092..75341fd1f317 100644
--- a/errorprone/tests/java/com/google/errorprone/bugpatterns/android/UidCheckerTest.java
+++ b/errorprone/tests/java/com/google/errorprone/bugpatterns/android/UidCheckerTest.java
@@ -34,7 +34,7 @@ public class UidCheckerTest {
}
@Test
- public void testTypical() {
+ public void testTypical_methodInvocation() {
compilationHelper
.addSourceLines("Example.java",
"public abstract class Example {",
@@ -57,7 +57,30 @@ public class UidCheckerTest {
}
@Test
- public void testCallingUid() {
+ public void testTypical_newClass() {
+ compilationHelper
+ .addSourceLines("Example.java",
+ "public abstract class Example {",
+ " class Bar { Bar(int pid, int uid, int userId) {} }",
+ " abstract int getUserId();",
+ " void foo(int pid, int uid, int userId, int unrelated) {",
+ " new Bar(0, 0, 0);",
+ " new Bar(pid, uid, userId);",
+ " new Bar(pid, uid, getUserId());",
+ " new Bar(unrelated, unrelated, unrelated);",
+ " // BUG: Diagnostic contains:",
+ " new Bar(uid, pid, userId);",
+ " // BUG: Diagnostic contains:",
+ " new Bar(pid, userId, uid);",
+ " // BUG: Diagnostic contains:",
+ " new Bar(getUserId(), 0, 0);",
+ " }",
+ "}")
+ .doTest();
+ }
+
+ @Test
+ public void testCallingUid_methodInvocation() {
compilationHelper
.addSourceFile("/android/os/Binder.java")
.addSourceFile("/android/os/UserHandle.java")
@@ -98,4 +121,48 @@ public class UidCheckerTest {
"}")
.doTest();
}
+
+
+ @Test
+ public void testCallingUid_newClass() {
+ compilationHelper
+ .addSourceFile("/android/os/Binder.java")
+ .addSourceFile("/android/os/UserHandle.java")
+ .addSourceLines("Example.java",
+ "import android.os.Binder;",
+ "import android.os.UserHandle;",
+ "public abstract class Example {",
+ " int callingUserId;",
+ " int callingUid;",
+ " class Foo { Foo(int callingUserId) {} }",
+ " class Bar { Bar(int callingUid) {} }",
+ " void doUserId(int callingUserId) {",
+ " new Foo(UserHandle.getUserId(Binder.getCallingUid()));",
+ " new Foo(this.callingUserId);",
+ " new Foo(callingUserId);",
+ " // BUG: Diagnostic contains:",
+ " new Foo(Binder.getCallingUid());",
+ " // BUG: Diagnostic contains:",
+ " new Foo(this.callingUid);",
+ " // BUG: Diagnostic contains:",
+ " new Foo(callingUid);",
+ " }",
+ " void doUid(int callingUserId) {",
+ " new Bar(Binder.getCallingUid());",
+ " new Bar(this.callingUid);",
+ " new Bar(callingUid);",
+ " // BUG: Diagnostic contains:",
+ " new Bar(UserHandle.getUserId(Binder.getCallingUid()));",
+ " // BUG: Diagnostic contains:",
+ " new Bar(this.callingUserId);",
+ " // BUG: Diagnostic contains:",
+ " new Bar(callingUserId);",
+ " }",
+ " void doInner() {",
+ " // BUG: Diagnostic contains:",
+ " new Foo(UserHandle.getUserId(callingUserId));",
+ " }",
+ "}")
+ .doTest();
+ }
}
diff --git a/libs/hwui/jni/Shader.cpp b/libs/hwui/jni/Shader.cpp
index 0f6837640524..e76aace601be 100644
--- a/libs/hwui/jni/Shader.cpp
+++ b/libs/hwui/jni/Shader.cpp
@@ -228,9 +228,12 @@ static jlong RuntimeShader_create(JNIEnv* env, jobject, jlong shaderFactory, jlo
static jlong RuntimeShader_createShaderFactory(JNIEnv* env, jobject, jstring sksl) {
ScopedUtfChars strSksl(env, sksl);
- sk_sp<SkRuntimeEffect> effect = std::get<0>(SkRuntimeEffect::Make(SkString(strSksl.c_str())));
- ThrowIAE_IfNull(env, effect);
-
+ auto result = SkRuntimeEffect::Make(SkString(strSksl.c_str()));
+ sk_sp<SkRuntimeEffect> effect = std::get<0>(result);
+ if (!effect) {
+ const auto& err = std::get<1>(result);
+ doThrowIAE(env, err.c_str());
+ }
return reinterpret_cast<jlong>(effect.release());
}
diff --git a/location/java/android/location/LocationManagerInternal.java b/location/java/android/location/LocationManagerInternal.java
index 542737b479e2..ef68814bce84 100644
--- a/location/java/android/location/LocationManagerInternal.java
+++ b/location/java/android/location/LocationManagerInternal.java
@@ -21,6 +21,8 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.location.util.identity.CallerIdentity;
+import java.util.List;
+
/**
* Location manager local system service interface.
*
@@ -29,6 +31,16 @@ import android.location.util.identity.CallerIdentity;
public abstract class LocationManagerInternal {
/**
+ * Listener for changes in provider enabled state.
+ */
+ public interface ProviderEnabledListener {
+ /**
+ * Called when the provider enabled state changes for a particular user.
+ */
+ void onProviderEnabledChanged(String provider, int userId, boolean enabled);
+ }
+
+ /**
* Returns true if the given provider is enabled for the given user.
*
* @param provider A location provider as listed by {@link LocationManager#getAllProviders()}
@@ -38,6 +50,24 @@ public abstract class LocationManagerInternal {
public abstract boolean isProviderEnabledForUser(@NonNull String provider, int userId);
/**
+ * Adds a provider enabled listener. The given provider must exist.
+ *
+ * @param provider The provider to listen for changes
+ * @param listener The listener
+ */
+ public abstract void addProviderEnabledListener(String provider,
+ ProviderEnabledListener listener);
+
+ /**
+ * Removes a provider enabled listener. The given provider must exist.
+ *
+ * @param provider The provider to listen for changes
+ * @param listener The listener
+ */
+ public abstract void removeProviderEnabledListener(String provider,
+ ProviderEnabledListener listener);
+
+ /**
* Returns true if the given identity is a location provider.
*
* @param provider The provider to check, or null to check every provider
@@ -52,4 +82,10 @@ public abstract class LocationManagerInternal {
*/
// TODO: there is no reason for this to exist as part of any API. move all the logic into gnss
public abstract void sendNiResponse(int notifId, int userResponse);
+
+ /**
+ * Should only be used by GNSS code.
+ */
+ // TODO: there is no reason for this to exist as part of any API. create a real batching API
+ public abstract void reportGnssBatchLocations(List<Location> locations);
}
diff --git a/location/java/android/location/LocationRequest.java b/location/java/android/location/LocationRequest.java
index bb36c2a1fc39..280bd058ef0f 100644
--- a/location/java/android/location/LocationRequest.java
+++ b/location/java/android/location/LocationRequest.java
@@ -32,6 +32,8 @@ import android.util.TimeUtils;
import com.android.internal.util.Preconditions;
+import java.util.Objects;
+
/**
* A data object that contains quality of service parameters for requests
@@ -150,8 +152,6 @@ public final class LocationRequest implements Parcelable {
@UnsupportedAppUsage
private String mProvider;
- // if true, client requests coarse location, if false, client requests fine location
- private boolean mCoarseLocation;
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private int mQuality;
@UnsupportedAppUsage
@@ -257,7 +257,6 @@ public final class LocationRequest implements Parcelable {
public LocationRequest() {
this(
/* provider= */ LocationManager.FUSED_PROVIDER,
- /* coarseLocation= */ false,
/* quality= */ POWER_LOW,
/* interval= */ DEFAULT_INTERVAL_MS,
/* fastestInterval= */ (long) (DEFAULT_INTERVAL_MS / FASTEST_INTERVAL_FACTOR),
@@ -276,7 +275,6 @@ public final class LocationRequest implements Parcelable {
public LocationRequest(LocationRequest src) {
this(
src.mProvider,
- src.mCoarseLocation,
src.mQuality,
src.mInterval,
src.mFastestInterval,
@@ -293,7 +291,6 @@ public final class LocationRequest implements Parcelable {
private LocationRequest(
@NonNull String provider,
- boolean coarseLocation,
int quality,
long intervalMs,
long fastestIntervalMs,
@@ -310,7 +307,6 @@ public final class LocationRequest implements Parcelable {
checkQuality(quality);
mProvider = provider;
- mCoarseLocation = coarseLocation;
mQuality = quality;
mInterval = intervalMs;
mFastestInterval = fastestIntervalMs;
@@ -327,20 +323,6 @@ public final class LocationRequest implements Parcelable {
}
/**
- * @hide
- */
- public boolean isCoarse() {
- return mCoarseLocation;
- }
-
- /**
- * @hide
- */
- public void setCoarse(boolean coarse) {
- mCoarseLocation = coarse;
- }
-
- /**
* Set the quality of the request.
*
* <p>Use with a accuracy constant such as {@link #ACCURACY_FINE}, or a power
@@ -720,7 +702,6 @@ public final class LocationRequest implements Parcelable {
public LocationRequest createFromParcel(Parcel in) {
return new LocationRequest(
/* provider= */ in.readString(),
- /* coarseLocation= */ in.readBoolean(),
/* quality= */ in.readInt(),
/* interval= */ in.readLong(),
/* fastestInterval= */ in.readLong(),
@@ -749,7 +730,6 @@ public final class LocationRequest implements Parcelable {
@Override
public void writeToParcel(Parcel parcel, int flags) {
parcel.writeString(mProvider);
- parcel.writeBoolean(mCoarseLocation);
parcel.writeInt(mQuality);
parcel.writeLong(mInterval);
parcel.writeLong(mFastestInterval);
@@ -784,6 +764,36 @@ public final class LocationRequest implements Parcelable {
}
}
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ LocationRequest that = (LocationRequest) o;
+ return mQuality == that.mQuality
+ && mInterval == that.mInterval
+ && mFastestInterval == that.mFastestInterval
+ && mExplicitFastestInterval == that.mExplicitFastestInterval
+ && mExpireAt == that.mExpireAt
+ && mExpireIn == that.mExpireIn
+ && mNumUpdates == that.mNumUpdates
+ && Float.compare(that.mSmallestDisplacement, mSmallestDisplacement) == 0
+ && mHideFromAppOps == that.mHideFromAppOps
+ && mLocationSettingsIgnored == that.mLocationSettingsIgnored
+ && mLowPowerMode == that.mLowPowerMode
+ && mProvider.equals(that.mProvider)
+ && Objects.equals(mWorkSource, that.mWorkSource);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mProvider, mInterval, mWorkSource);
+ }
+
@NonNull
@Override
public String toString() {
@@ -794,7 +804,7 @@ public final class LocationRequest implements Parcelable {
if (mQuality != POWER_NONE) {
s.append(" interval=");
TimeUtils.formatDuration(mInterval, s);
- if (mExplicitFastestInterval) {
+ if (mExplicitFastestInterval && mFastestInterval != mInterval) {
s.append(" fastestInterval=");
TimeUtils.formatDuration(mFastestInterval, s);
}
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index c6fb3ef8f694..408f34be6b65 100755
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -4601,36 +4601,41 @@ public class AudioManager {
/**
* @hide
* Volume behavior for an audio device that has no particular volume behavior set. Invalid as
- * an argument to {@link #setDeviceVolumeBehavior(int, String, int)}.
+ * an argument to {@link #setDeviceVolumeBehavior(AudioDeviceAttributes, int)} and should not
+ * be returned by {@link #getDeviceVolumeBehavior(AudioDeviceAttributes)}.
*/
public static final int DEVICE_VOLUME_BEHAVIOR_UNSET = -1;
/**
* @hide
* Volume behavior for an audio device where a software attenuation is applied
- * @see #setDeviceVolumeBehavior(int, String, int)
+ * @see #setDeviceVolumeBehavior(AudioDeviceAttributes, int)
*/
+ @SystemApi
public static final int DEVICE_VOLUME_BEHAVIOR_VARIABLE = 0;
/**
* @hide
* Volume behavior for an audio device where the volume is always set to provide no attenuation
* nor gain (e.g. unit gain).
- * @see #setDeviceVolumeBehavior(int, String, int)
+ * @see #setDeviceVolumeBehavior(AudioDeviceAttributes, int)
*/
+ @SystemApi
public static final int DEVICE_VOLUME_BEHAVIOR_FULL = 1;
/**
* @hide
* Volume behavior for an audio device where the volume is either set to muted, or to provide
* no attenuation nor gain (e.g. unit gain).
- * @see #setDeviceVolumeBehavior(int, String, int)
+ * @see #setDeviceVolumeBehavior(AudioDeviceAttributes, int)
*/
+ @SystemApi
public static final int DEVICE_VOLUME_BEHAVIOR_FIXED = 2;
/**
* @hide
* Volume behavior for an audio device where no software attenuation is applied, and
* the volume is kept synchronized between the host and the device itself through a
* device-specific protocol such as BT AVRCP.
- * @see #setDeviceVolumeBehavior(int, String, int)
+ * @see #setDeviceVolumeBehavior(AudioDeviceAttributes, int)
*/
+ @SystemApi
public static final int DEVICE_VOLUME_BEHAVIOR_ABSOLUTE = 3;
/**
* @hide
@@ -4639,8 +4644,9 @@ public class AudioManager {
* device-specific protocol (such as for hearing aids), based on the audio mode (e.g.
* normal vs in phone call).
* @see #setMode(int)
- * @see #setDeviceVolumeBehavior(int, String, int)
+ * @see #setDeviceVolumeBehavior(AudioDeviceAttributes, int)
*/
+ @SystemApi
public static final int DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE = 4;
/** @hide */
@@ -4687,27 +4693,15 @@ public class AudioManager {
/**
* @hide
* Sets the volume behavior for an audio output device.
- * @param deviceType the type of audio device to be affected. Currently only supports
- * {@link AudioDeviceInfo#TYPE_HDMI}, {@link AudioDeviceInfo#TYPE_HDMI_ARC},
- * {@link AudioDeviceInfo#TYPE_LINE_DIGITAL} and {@link AudioDeviceInfo#TYPE_AUX_LINE}
- * @param deviceAddress the address of the device, if any
- * @param deviceVolumeBehavior one of the device behaviors
- */
- @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
- public void setDeviceVolumeBehavior(int deviceType, @Nullable String deviceAddress,
- @DeviceVolumeBehavior int deviceVolumeBehavior) {
- setDeviceVolumeBehavior(new AudioDeviceAttributes(AudioDeviceAttributes.ROLE_OUTPUT,
- deviceType, deviceAddress), deviceVolumeBehavior);
- }
-
- /**
- * @hide
- * Sets the volume behavior for an audio output device.
- * @param device the device to be affected. Currently only supports devices of type
- * {@link AudioDeviceInfo#TYPE_HDMI}, {@link AudioDeviceInfo#TYPE_HDMI_ARC},
- * {@link AudioDeviceInfo#TYPE_LINE_DIGITAL} and {@link AudioDeviceInfo#TYPE_AUX_LINE}
+ * @see #DEVICE_VOLUME_BEHAVIOR_VARIABLE
+ * @see #DEVICE_VOLUME_BEHAVIOR_FULL
+ * @see #DEVICE_VOLUME_BEHAVIOR_FIXED
+ * @see #DEVICE_VOLUME_BEHAVIOR_ABSOLUTE
+ * @see #DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE
+ * @param device the device to be affected
* @param deviceVolumeBehavior one of the device behaviors
*/
+ @SystemApi
@RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
public void setDeviceVolumeBehavior(@NonNull AudioDeviceAttributes device,
@DeviceVolumeBehavior int deviceVolumeBehavior) {
@@ -4726,29 +4720,14 @@ public class AudioManager {
/**
* @hide
- * Returns the volume device behavior for the given device type and address
- * @param deviceType an audio output device type, as defined in {@link AudioDeviceInfo}
- * @param deviceAddress the address of the audio device, if any.
- * @return the volume behavior for the device
- */
- @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
- public @DeviceVolumeBehaviorState int getDeviceVolumeBehavior(int deviceType,
- @Nullable String deviceAddress) {
- // verify arguments
- AudioDeviceInfo.enforceValidAudioDeviceTypeOut(deviceType);
- return getDeviceVolumeBehavior(new AudioDeviceAttributes(AudioDeviceAttributes.ROLE_OUTPUT,
- deviceType, deviceAddress));
- }
-
- /**
- * @hide
* Returns the volume device behavior for the given audio device
* @param device the audio device
* @return the volume behavior for the device
*/
+ @SystemApi
@RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
- public @DeviceVolumeBehaviorState int getDeviceVolumeBehavior(
- @NonNull AudioDeviceAttributes device) {
+ public @DeviceVolumeBehavior
+ int getDeviceVolumeBehavior(@NonNull AudioDeviceAttributes device) {
// verify arguments (validity of device type is enforced in server)
Objects.requireNonNull(device);
// communicate with service
diff --git a/non-updatable-api/current.txt b/non-updatable-api/current.txt
index 54618a5da3a3..70ef69d8ce72 100644
--- a/non-updatable-api/current.txt
+++ b/non-updatable-api/current.txt
@@ -11900,6 +11900,7 @@ package android.content.pm {
field public static final int INVALID_ID = -1; // 0xffffffff
field public static final int STAGED_SESSION_ACTIVATION_FAILED = 2; // 0x2
field public static final int STAGED_SESSION_NO_ERROR = 0; // 0x0
+ field public static final int STAGED_SESSION_OTHER_ERROR = 4; // 0x4
field public static final int STAGED_SESSION_UNKNOWN = 3; // 0x3
field public static final int STAGED_SESSION_VERIFICATION_FAILED = 1; // 0x1
}
diff --git a/non-updatable-api/system-current.txt b/non-updatable-api/system-current.txt
index 385ae278975c..844e929774a1 100644
--- a/non-updatable-api/system-current.txt
+++ b/non-updatable-api/system-current.txt
@@ -4141,6 +4141,7 @@ package android.media {
method @IntRange(from=0) public long getAdditionalOutputDeviceDelay(@NonNull android.media.AudioDeviceInfo);
method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public static java.util.List<android.media.audiopolicy.AudioProductStrategy> getAudioProductStrategies();
method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public static java.util.List<android.media.audiopolicy.AudioVolumeGroup> getAudioVolumeGroups();
+ method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int getDeviceVolumeBehavior(@NonNull android.media.AudioDeviceAttributes);
method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public java.util.List<android.media.AudioDeviceAttributes> getDevicesForAttributes(@NonNull android.media.AudioAttributes);
method @IntRange(from=0) public long getMaxAdditionalOutputDeviceDelay(@NonNull android.media.AudioDeviceInfo);
method @IntRange(from=0) @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int getMaxVolumeIndexForAttributes(@NonNull android.media.AudioAttributes);
@@ -4159,6 +4160,7 @@ package android.media {
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int requestAudioFocus(@NonNull android.media.AudioFocusRequest, @Nullable android.media.audiopolicy.AudioPolicy);
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public boolean setAdditionalOutputDeviceDelay(@NonNull android.media.AudioDeviceInfo, @IntRange(from=0) long);
method public void setAudioServerStateCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.AudioManager.AudioServerStateCallback);
+ method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void setDeviceVolumeBehavior(@NonNull android.media.AudioDeviceAttributes, int);
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void setFocusRequestResult(@NonNull android.media.AudioFocusInfo, int, @NonNull android.media.audiopolicy.AudioPolicy);
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public boolean setPreferredDeviceForStrategy(@NonNull android.media.audiopolicy.AudioProductStrategy, @NonNull android.media.AudioDeviceAttributes);
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void setSupportedSystemUsages(@NonNull int[]);
@@ -4169,6 +4171,11 @@ package android.media {
field public static final int AUDIOFOCUS_FLAG_DELAY_OK = 1; // 0x1
field public static final int AUDIOFOCUS_FLAG_LOCK = 4; // 0x4
field public static final int AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS = 2; // 0x2
+ field public static final int DEVICE_VOLUME_BEHAVIOR_ABSOLUTE = 3; // 0x3
+ field public static final int DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE = 4; // 0x4
+ field public static final int DEVICE_VOLUME_BEHAVIOR_FIXED = 2; // 0x2
+ field public static final int DEVICE_VOLUME_BEHAVIOR_FULL = 1; // 0x1
+ field public static final int DEVICE_VOLUME_BEHAVIOR_VARIABLE = 0; // 0x0
field @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public static final int STREAM_ASSISTANT = 11; // 0xb
field public static final int SUCCESS = 0; // 0x0
}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/sideloaded/SideLoadedAppDetector.java b/packages/CarSystemUI/src/com/android/systemui/car/sideloaded/SideLoadedAppDetector.java
index 5dcb9de4755e..a2cd0446d1e8 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/sideloaded/SideLoadedAppDetector.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/sideloaded/SideLoadedAppDetector.java
@@ -39,7 +39,7 @@ import javax.inject.Singleton;
/**
* A class that detects unsafe apps.
- * An app is considered safe if is a system app or installed through whitelisted sources.
+ * An app is considered safe if is a system app or installed through allowed sources.
*/
@Singleton
public class SideLoadedAppDetector {
diff --git a/packages/CarSystemUI/src/com/android/systemui/wm/BarControlPolicy.java b/packages/CarSystemUI/src/com/android/systemui/wm/BarControlPolicy.java
index 5f9665ff7632..0452b83b125f 100644
--- a/packages/CarSystemUI/src/com/android/systemui/wm/BarControlPolicy.java
+++ b/packages/CarSystemUI/src/com/android/systemui/wm/BarControlPolicy.java
@@ -172,32 +172,32 @@ public class BarControlPolicy {
private static class Filter {
private static final String ALL = "*";
- private final ArraySet<String> mWhitelist;
- private final ArraySet<String> mBlacklist;
+ private final ArraySet<String> mToInclude;
+ private final ArraySet<String> mToExclude;
- private Filter(ArraySet<String> whitelist, ArraySet<String> blacklist) {
- mWhitelist = whitelist;
- mBlacklist = blacklist;
+ private Filter(ArraySet<String> toInclude, ArraySet<String> toExclude) {
+ mToInclude = toInclude;
+ mToExclude = toExclude;
}
boolean matches(String packageName) {
if (packageName == null) return false;
- if (onBlacklist(packageName)) return false;
- return onWhitelist(packageName);
+ if (toExclude(packageName)) return false;
+ return toInclude(packageName);
}
- private boolean onBlacklist(String packageName) {
- return mBlacklist.contains(packageName) || mBlacklist.contains(ALL);
+ private boolean toExclude(String packageName) {
+ return mToExclude.contains(packageName) || mToExclude.contains(ALL);
}
- private boolean onWhitelist(String packageName) {
- return mWhitelist.contains(ALL) || mWhitelist.contains(packageName);
+ private boolean toInclude(String packageName) {
+ return mToInclude.contains(ALL) || mToInclude.contains(packageName);
}
void dump(PrintWriter pw) {
pw.print("Filter[");
- dump("whitelist", mWhitelist, pw); pw.print(',');
- dump("blacklist", mBlacklist, pw); pw.print(']');
+ dump("toInclude", mToInclude, pw); pw.print(',');
+ dump("toExclude", mToExclude, pw); pw.print(']');
}
private void dump(String name, ArraySet<String> set, PrintWriter pw) {
@@ -221,18 +221,18 @@ public class BarControlPolicy {
// e.g. "com.package1", or "com.android.systemui, com.android.keyguard" or "*"
static Filter parse(String value) {
if (value == null) return null;
- ArraySet<String> whitelist = new ArraySet<String>();
- ArraySet<String> blacklist = new ArraySet<String>();
+ ArraySet<String> toInclude = new ArraySet<String>();
+ ArraySet<String> toExclude = new ArraySet<String>();
for (String token : value.split(",")) {
token = token.trim();
if (token.startsWith("-") && token.length() > 1) {
token = token.substring(1);
- blacklist.add(token);
+ toExclude.add(token);
} else {
- whitelist.add(token);
+ toInclude.add(token);
}
}
- return new Filter(whitelist, blacklist);
+ return new Filter(toInclude, toExclude);
}
}
diff --git a/packages/CarSystemUI/tests/src/com/android/AAAPlusPlusVerifySysuiRequiredTestPropertiesTest.java b/packages/CarSystemUI/tests/src/com/android/AAAPlusPlusVerifySysuiRequiredTestPropertiesTest.java
index d769cacadf1d..86b86d482eee 100644
--- a/packages/CarSystemUI/tests/src/com/android/AAAPlusPlusVerifySysuiRequiredTestPropertiesTest.java
+++ b/packages/CarSystemUI/tests/src/com/android/AAAPlusPlusVerifySysuiRequiredTestPropertiesTest.java
@@ -63,7 +63,7 @@ public class AAAPlusPlusVerifySysuiRequiredTestPropertiesTest extends SysuiTestC
private static final String TAG = "AAA++VerifyTest";
- private static final Class[] BASE_CLS_WHITELIST = {
+ private static final Class[] BASE_CLS_TO_INCLUDE = {
SysuiTestCase.class,
SysuiBaseFragmentTest.class,
};
@@ -85,7 +85,7 @@ public class AAAPlusPlusVerifySysuiRequiredTestPropertiesTest extends SysuiTestC
if (!isTestClass(cls)) continue;
boolean hasParent = false;
- for (Class<?> parent : BASE_CLS_WHITELIST) {
+ for (Class<?> parent : BASE_CLS_TO_INCLUDE) {
if (parent.isAssignableFrom(cls)) {
hasParent = true;
break;
@@ -129,7 +129,7 @@ public class AAAPlusPlusVerifySysuiRequiredTestPropertiesTest extends SysuiTestC
}
private String getClsStr() {
- return TextUtils.join(",", Arrays.asList(BASE_CLS_WHITELIST)
+ return TextUtils.join(",", Arrays.asList(BASE_CLS_TO_INCLUDE)
.stream().map(cls -> cls.getSimpleName()).toArray());
}
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/voicerecognition/ConnectedDeviceVoiceRecognitionNotifierTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/voicerecognition/ConnectedDeviceVoiceRecognitionNotifierTest.java
index 31f1170c9603..f77294e37b98 100644
--- a/packages/CarSystemUI/tests/src/com/android/systemui/car/voicerecognition/ConnectedDeviceVoiceRecognitionNotifierTest.java
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/voicerecognition/ConnectedDeviceVoiceRecognitionNotifierTest.java
@@ -19,6 +19,8 @@ package com.android.systemui.car.voicerecognition;
import static com.android.systemui.car.voicerecognition.ConnectedDeviceVoiceRecognitionNotifier.INVALID_VALUE;
import static com.android.systemui.car.voicerecognition.ConnectedDeviceVoiceRecognitionNotifier.VOICE_RECOGNITION_STARTED;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
@@ -40,11 +42,13 @@ import com.android.systemui.car.CarSystemUiTest;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
@CarSystemUiTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
@SmallTest
+// TODO(b/162866441): Refactor to use the Executor pattern instead.
public class ConnectedDeviceVoiceRecognitionNotifierTest extends SysuiTestCase {
private static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH;
@@ -52,13 +56,15 @@ public class ConnectedDeviceVoiceRecognitionNotifierTest extends SysuiTestCase {
private ConnectedDeviceVoiceRecognitionNotifier mVoiceRecognitionNotifier;
private TestableLooper mTestableLooper;
+ private Handler mHandler;
private Handler mTestHandler;
private BluetoothDevice mBluetoothDevice;
@Before
public void setUp() throws Exception {
mTestableLooper = TestableLooper.get(this);
- mTestHandler = spy(new Handler(mTestableLooper.getLooper()));
+ mHandler = new Handler(mTestableLooper.getLooper());
+ mTestHandler = spy(mHandler);
mBluetoothDevice = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(
BLUETOOTH_REMOTE_ADDRESS);
mVoiceRecognitionNotifier = new ConnectedDeviceVoiceRecognitionNotifier(
@@ -74,8 +80,14 @@ public class ConnectedDeviceVoiceRecognitionNotifierTest extends SysuiTestCase {
mContext.sendBroadcast(intent, BLUETOOTH_PERM);
mTestableLooper.processAllMessages();
-
- verify(mTestHandler).post(any());
+ waitForIdleSync();
+
+ mHandler.post(() -> {
+ ArgumentCaptor<Runnable> argumentCaptor = ArgumentCaptor.forClass(Runnable.class);
+ verify(mTestHandler).post(argumentCaptor.capture());
+ assertThat(argumentCaptor.getValue()).isNotNull();
+ assertThat(argumentCaptor.getValue()).isNotEqualTo(this);
+ });
}
@Test
@@ -86,8 +98,11 @@ public class ConnectedDeviceVoiceRecognitionNotifierTest extends SysuiTestCase {
mContext.sendBroadcast(intent, BLUETOOTH_PERM);
mTestableLooper.processAllMessages();
+ waitForIdleSync();
- verify(mTestHandler, never()).post(any());
+ mHandler.post(() -> {
+ verify(mTestHandler, never()).post(any());
+ });
}
@Test
@@ -97,8 +112,11 @@ public class ConnectedDeviceVoiceRecognitionNotifierTest extends SysuiTestCase {
mContext.sendBroadcast(intent, BLUETOOTH_PERM);
mTestableLooper.processAllMessages();
+ waitForIdleSync();
- verify(mTestHandler, never()).post(any());
+ mHandler.post(() -> {
+ verify(mTestHandler, never()).post(any());
+ });
}
@Test
@@ -108,7 +126,10 @@ public class ConnectedDeviceVoiceRecognitionNotifierTest extends SysuiTestCase {
mContext.sendBroadcast(intent, BLUETOOTH_PERM);
mTestableLooper.processAllMessages();
+ waitForIdleSync();
- verify(mTestHandler, never()).post(any());
+ mHandler.post(() -> {
+ verify(mTestHandler, never()).post(any());
+ });
}
}
diff --git a/packages/FakeOemFeatures/src/com/android/fakeoemfeatures/FakeView.java b/packages/FakeOemFeatures/src/com/android/fakeoemfeatures/FakeView.java
index 276d55ee9a5e..9fe7ab655e46 100644
--- a/packages/FakeOemFeatures/src/com/android/fakeoemfeatures/FakeView.java
+++ b/packages/FakeOemFeatures/src/com/android/fakeoemfeatures/FakeView.java
@@ -26,7 +26,7 @@ import android.os.Message;
import android.view.View;
/**
- * Dummy view to emulate stuff an OEM may want to do.
+ * Fake view to emulate stuff an OEM may want to do.
*/
public class FakeView extends View {
static final long TICK_DELAY = 30*1000; // 30 seconds
diff --git a/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/MasterSwitchController.java b/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/PrimarySwitchController.java
index a12aa83e9d4b..a08f566b8375 100644
--- a/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/MasterSwitchController.java
+++ b/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/PrimarySwitchController.java
@@ -19,9 +19,9 @@ package com.android.settingslib.drawer;
import android.os.Bundle;
/**
- * A controller that manages event for master switch.
+ * A controller that manages event for Primary switch.
*/
-public abstract class MasterSwitchController extends SwitchController {
+public abstract class PrimarySwitchController extends SwitchController {
@Override
protected final MetaData getMetaData() {
diff --git a/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/SwitchesProvider.java b/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/SwitchesProvider.java
index 73f1a904b04b..f2b3e30dc252 100644
--- a/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/SwitchesProvider.java
+++ b/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/SwitchesProvider.java
@@ -88,7 +88,7 @@ public abstract class SwitchesProvider extends ContentProvider {
controller.setAuthority(mAuthority);
mControllerMap.put(key, controller);
- if (!(controller instanceof MasterSwitchController)) {
+ if (!(controller instanceof PrimarySwitchController)) {
mSwitchDataList.add(controller.getBundle());
}
});
@@ -116,7 +116,7 @@ public abstract class SwitchesProvider extends ContentProvider {
switch (method) {
case METHOD_GET_SWITCH_DATA:
- if (!(controller instanceof MasterSwitchController)) {
+ if (!(controller instanceof PrimarySwitchController)) {
return controller.getBundle();
}
break;
diff --git a/packages/SettingsLib/res/values-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml
index 704d264d1983..6751fa4583c5 100644
--- a/packages/SettingsLib/res/values-af/strings.xml
+++ b/packages/SettingsLib/res/values-af/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Wys Bluetooth-toestelle sonder name"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Deaktiveer absolute volume"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Aktiveer Gabeldorsche"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Verbeterde konnektiwiteit"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Bluetooth AVRCP-weergawe"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Kies Bluetooth AVRCP-weergawe"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Bluetooth MAP-weergawe"</string>
diff --git a/packages/SettingsLib/res/values-am/strings.xml b/packages/SettingsLib/res/values-am/strings.xml
index 585924d7efb9..470e780fc049 100644
--- a/packages/SettingsLib/res/values-am/strings.xml
+++ b/packages/SettingsLib/res/values-am/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"የብሉቱዝ መሣሪያዎችን ያለ ስሞች አሳይ"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"ፍጹማዊ ድምፅን አሰናክል"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Gabeldorscheን አንቃ"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"የተሻሻለ ተገናኝነት"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"የብሉቱዝ AVRCP ስሪት"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"የብሉቱዝ AVRCP ስሪት ይምረጡ"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"የብሉቱዝ MAP ስሪት"</string>
diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml
index 39777cd5f881..9acfa0da7747 100644
--- a/packages/SettingsLib/res/values-ar/strings.xml
+++ b/packages/SettingsLib/res/values-ar/strings.xml
@@ -152,7 +152,7 @@
<string name="user_guest" msgid="6939192779649870792">"ضيف"</string>
<string name="unknown" msgid="3544487229740637809">"غير معروف"</string>
<string name="running_process_item_user_label" msgid="3988506293099805796">"المستخدم: <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
- <string name="launch_defaults_some" msgid="3631650616557252926">"تم تعيين بعض الإعدادات التلقائية"</string>
+ <string name="launch_defaults_some" msgid="3631650616557252926">"تم ضبط بعض الإعدادات التلقائية"</string>
<string name="launch_defaults_none" msgid="8049374306261262709">"لم يتم تعيين إعدادات تلقائية"</string>
<string name="tts_settings" msgid="8130616705989351312">"إعدادات تحويل النص إلى كلام"</string>
<string name="tts_settings_title" msgid="7602210956640483039">"تحويل النص إلى كلام"</string>
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"عرض أجهزة البلوتوث بدون أسماء"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"إيقاف مستوى الصوت المطلق"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"‏تفعيل Gabeldorsche"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"إمكانية اتصال محسّن"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"‏إصدار Bluetooth AVRCP"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"‏اختيار إصدار Bluetooth AVRCP"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"‏إصدار Bluetooth MAP"</string>
diff --git a/packages/SettingsLib/res/values-as/strings.xml b/packages/SettingsLib/res/values-as/strings.xml
index e0455cb5f19c..f993dba39476 100644
--- a/packages/SettingsLib/res/values-as/strings.xml
+++ b/packages/SettingsLib/res/values-as/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"নামবিহীন ব্লুটুথ ডিভাইচসমূহ দেখুৱাওক"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"পূৰ্ণ মাত্ৰাৰ ভলিউম অক্ষম কৰক"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Gabeldorsche সক্ষম কৰক"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"উন্নত সংযোগ"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"ব্লুটুথ AVRCP সংস্কৰণ"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"ব্লুটুথ AVRCP সংস্কৰণ বাছনি কৰক"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"ব্লুটুথ MAP সংস্কৰণ"</string>
diff --git a/packages/SettingsLib/res/values-az/strings.xml b/packages/SettingsLib/res/values-az/strings.xml
index 6565d530f6a1..6a506614f970 100644
--- a/packages/SettingsLib/res/values-az/strings.xml
+++ b/packages/SettingsLib/res/values-az/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Bluetooth cihazlarını adsız göstərin"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Mütləq səs həcmi deaktiv edin"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Gabeldorsche\'ni aktiv edin"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Təkmilləşdirilmiş Bağlantı"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Bluetooth AVRCP Versiya"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Bluetooth AVRCP Versiyasını seçin"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Bluetooth MAP Versiyası"</string>
diff --git a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
index 3ced29b47dd6..cf988ab3589f 100644
--- a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
+++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Prikaži Bluetooth uređaje bez naziva"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Onemogući glavno podešavanje jačine zvuka"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Omogući Gabeldorsche"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Poboljšano povezivanje"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Verzija Bluetooth AVRCP-a"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Izaberite verziju Bluetooth AVRCP-a"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Verzija Bluetooth MAP-a"</string>
diff --git a/packages/SettingsLib/res/values-be/strings.xml b/packages/SettingsLib/res/values-be/strings.xml
index 01d7682416fa..8f71509772fc 100644
--- a/packages/SettingsLib/res/values-be/strings.xml
+++ b/packages/SettingsLib/res/values-be/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Паказваць прылады Bluetooth без назваў"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Адключыць абсалютны гук"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Уключыць Gabeldorsche"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Палепшанае падключэнне"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Версія Bluetooth AVRCP"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Выбраць версію Bluetooth AVRCP"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Версія Bluetooth MAP"</string>
diff --git a/packages/SettingsLib/res/values-bg/strings.xml b/packages/SettingsLib/res/values-bg/strings.xml
index d042c0f89b1e..747cb266b6de 100644
--- a/packages/SettingsLib/res/values-bg/strings.xml
+++ b/packages/SettingsLib/res/values-bg/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Показване на устройствата с Bluetooth без имена"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Деактивиране на пълната сила на звука"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Активиране на Gabeldorsche"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Подобрена свързаност"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Версия на AVRCP за Bluetooth"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Избиране на версия на AVRCP за Bluetooth"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"MAP версия за Bluetooth"</string>
diff --git a/packages/SettingsLib/res/values-bn/strings.xml b/packages/SettingsLib/res/values-bn/strings.xml
index 2db23f73e683..87f3b7a4f2e8 100644
--- a/packages/SettingsLib/res/values-bn/strings.xml
+++ b/packages/SettingsLib/res/values-bn/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"নামহীন ব্লুটুথ ডিভাইসগুলি দেখুন"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"চূড়ান্ত ভলিউম অক্ষম করুন"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Gabeldorsche ফিচার চালু করুন"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"কানেক্টিভিটি উন্নত করা হয়েছে"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"ব্লুটুথ AVRCP ভার্সন"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"ব্লুটুথ AVRCP ভার্সন বেছে নিন"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"ব্লুটুথ MAP ভার্সন"</string>
diff --git a/packages/SettingsLib/res/values-bs/strings.xml b/packages/SettingsLib/res/values-bs/strings.xml
index f26fe9d58533..e329c993eedb 100644
--- a/packages/SettingsLib/res/values-bs/strings.xml
+++ b/packages/SettingsLib/res/values-bs/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Prikaži Bluetooth uređaje bez naziva"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Onemogući apsolutnu jačinu zvuka"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Omogući Gabeldorsche"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Poboljšana povezivost"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Bluetooth AVRCP verzija"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Odaberite Bluetooth AVRCP verziju"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Bluetooth MAP verzija"</string>
diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml
index 3ca9d5272d48..5ffdacd19c22 100644
--- a/packages/SettingsLib/res/values-ca/strings.xml
+++ b/packages/SettingsLib/res/values-ca/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Mostra els dispositius Bluetooth sense el nom"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Desactiva el volum absolut"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Activa Gabeldorsche"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Connectivitat millorada"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Versió AVRCP de Bluetooth"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Selecciona la versió AVRCP de Bluetooth"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Versió MAP de Bluetooth"</string>
diff --git a/packages/SettingsLib/res/values-cs/strings.xml b/packages/SettingsLib/res/values-cs/strings.xml
index a5532e0bff02..0aef99feb04f 100644
--- a/packages/SettingsLib/res/values-cs/strings.xml
+++ b/packages/SettingsLib/res/values-cs/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Zobrazovat zařízení Bluetooth bez názvů"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Zakázat absolutní hlasitost"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Zapnout funkci Gabeldorsche"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Lepší připojování"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Verze profilu Bluetooth AVRCP"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Vyberte verzi profilu Bluetooth AVRCP"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Verze MAP pro Bluetooth"</string>
diff --git a/packages/SettingsLib/res/values-da/strings.xml b/packages/SettingsLib/res/values-da/strings.xml
index 8ca22d7ba797..98068cb172fa 100644
--- a/packages/SettingsLib/res/values-da/strings.xml
+++ b/packages/SettingsLib/res/values-da/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Vis Bluetooth-enheder uden navne"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Deaktiver absolut lydstyrke"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Aktivér Gabeldorsche"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Enhanced Connectivity"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"AVRCP-version for Bluetooth"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Vælg AVRCP-version for Bluetooth"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"MAP-version for Bluetooth"</string>
diff --git a/packages/SettingsLib/res/values-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml
index 6b0ae2e24bb6..0837ad33ab06 100644
--- a/packages/SettingsLib/res/values-de/strings.xml
+++ b/packages/SettingsLib/res/values-de/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Bluetooth-Geräte ohne Namen anzeigen"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Absolute Lautstärkeregelung deaktivieren"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Bluetooth-Gabeldorsche aktivieren"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Verbesserte Konnektivität"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Bluetooth AVRCP-Version"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Bluetooth AVRCP-Version auswählen"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Bluetooth MAP-Version"</string>
diff --git a/packages/SettingsLib/res/values-el/strings.xml b/packages/SettingsLib/res/values-el/strings.xml
index 4d7c88287f72..1f9d97764016 100644
--- a/packages/SettingsLib/res/values-el/strings.xml
+++ b/packages/SettingsLib/res/values-el/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Εμφάνιση συσκευών Bluetooth χωρίς ονόματα"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Απενεργοποίηση απόλυτης έντασης"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Ενεργοποίηση Gabeldorsche"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Βελτιωμένη συνδεσιμότητα"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Έκδοση AVRCP Bluetooth"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Επιλογή έκδοσης AVRCP Bluetooth"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Έκδοση MAP Bluetooth"</string>
diff --git a/packages/SettingsLib/res/values-en-rAU/strings.xml b/packages/SettingsLib/res/values-en-rAU/strings.xml
index cc3b2aa33695..abe61a97096c 100644
--- a/packages/SettingsLib/res/values-en-rAU/strings.xml
+++ b/packages/SettingsLib/res/values-en-rAU/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Show Bluetooth devices without names"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Disable absolute volume"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Enable Gabeldorsche"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Enhanced connectivity"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Bluetooth AVRCP version"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Select Bluetooth AVRCP Version"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Bluetooth MAP version"</string>
diff --git a/packages/SettingsLib/res/values-en-rCA/strings.xml b/packages/SettingsLib/res/values-en-rCA/strings.xml
index a9f039a6522c..959ad46bcf61 100644
--- a/packages/SettingsLib/res/values-en-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-en-rCA/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Show Bluetooth devices without names"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Disable absolute volume"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Enable Gabeldorsche"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Enhanced connectivity"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Bluetooth AVRCP version"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Select Bluetooth AVRCP Version"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Bluetooth MAP version"</string>
diff --git a/packages/SettingsLib/res/values-en-rGB/strings.xml b/packages/SettingsLib/res/values-en-rGB/strings.xml
index cc3b2aa33695..abe61a97096c 100644
--- a/packages/SettingsLib/res/values-en-rGB/strings.xml
+++ b/packages/SettingsLib/res/values-en-rGB/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Show Bluetooth devices without names"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Disable absolute volume"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Enable Gabeldorsche"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Enhanced connectivity"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Bluetooth AVRCP version"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Select Bluetooth AVRCP Version"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Bluetooth MAP version"</string>
diff --git a/packages/SettingsLib/res/values-en-rIN/strings.xml b/packages/SettingsLib/res/values-en-rIN/strings.xml
index cc3b2aa33695..abe61a97096c 100644
--- a/packages/SettingsLib/res/values-en-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-en-rIN/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Show Bluetooth devices without names"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Disable absolute volume"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Enable Gabeldorsche"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Enhanced connectivity"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Bluetooth AVRCP version"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Select Bluetooth AVRCP Version"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Bluetooth MAP version"</string>
diff --git a/packages/SettingsLib/res/values-en-rXC/strings.xml b/packages/SettingsLib/res/values-en-rXC/strings.xml
index 41c20e0c915f..738dd2a2ba31 100644
--- a/packages/SettingsLib/res/values-en-rXC/strings.xml
+++ b/packages/SettingsLib/res/values-en-rXC/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‎‎‏‏‎‎‏‏‎‏‎‎‎‏‎‎‏‏‏‎‏‏‎‎‏‏‏‎‏‏‏‏‎‎‎‏‎‎‎‏‏‎‎‏‏‏‎‏‏‏‎‎‏‏‏‏‏‏‏‎‏‏‎Show Bluetooth devices without names‎‏‎‎‏‎"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‎‏‏‎‏‎‎‎‎‏‎‎‏‏‏‏‏‎‎‎‎‎‏‏‎‏‎‎‏‏‎‎‎‏‎‏‏‏‏‎‎‎‏‏‎‎‏‎‏‏‏‎‎‏‏‏‏‏‎‏‎‏‎‎Disable absolute volume‎‏‎‎‏‎"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‏‏‏‏‎‏‎‏‏‏‎‏‎‎‏‏‎‏‏‎‎‎‏‏‎‏‎‎‏‏‏‎‏‎‏‎‎‏‎‏‏‎‎‎‏‏‎‏‏‎‎‏‏‎‏‎‏‏‎‎‎‎Enable Gabeldorsche‎‏‎‎‏‎"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‎‎‎‏‏‏‏‏‎‏‏‏‏‏‎‎‎‏‎‏‏‎‎‏‏‎‎‏‎‎‏‏‎‎‏‏‏‎‎‎‎‎‏‎‎‎‎‏‏‎‎‏‏‏‏‏‏‎‏‎‎‎Enhanced Connectivity‎‏‎‎‏‎"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‎‏‏‎‏‏‏‏‎‏‏‏‏‎‏‎‎‏‎‏‎‏‏‏‏‎‏‎‎‎‏‎‎‎‎‎‎‏‏‏‎‎‎‎‎‎‏‏‏‏‎‎‎‎‎‏‏‏‏‎‏‏‏‎Bluetooth AVRCP Version‎‏‎‎‏‎"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‎‏‏‎‎‏‏‏‎‎‏‎‏‏‏‎‏‏‏‏‎‎‎‏‏‏‏‏‏‏‎‎‎‎‎‎‎‏‎‎‎‏‎‎‎‏‏‎‎‎‎‏‎‏‏‎‎‎‎‎‏‎Select Bluetooth AVRCP Version‎‏‎‎‏‎"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‎‏‏‏‏‏‎‏‎‎‏‏‎‏‏‏‎‏‎‎‏‎‎‏‏‏‏‎‎‎‎‎‏‏‎‎‏‏‏‎‎‎‎‎‎‎‎‏‎‏‏‏‏‎‎‏‎‏‏‏‏‏‎Bluetooth MAP Version‎‏‎‎‏‎"</string>
diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml
index 287a1aca2fbd..d1e4fb5607a8 100644
--- a/packages/SettingsLib/res/values-es-rUS/strings.xml
+++ b/packages/SettingsLib/res/values-es-rUS/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Mostrar dispositivos Bluetooth sin nombre"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Inhabilitar volumen absoluto"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Habilitar Gabeldorsche"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Conectividad mejorada"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Versión de AVRCP del Bluetooth"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Selecciona la versión de AVRCP del Bluetooth"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Versión de MAP de Bluetooth"</string>
diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml
index 9d3455766f6b..9ad71e2766a3 100644
--- a/packages/SettingsLib/res/values-es/strings.xml
+++ b/packages/SettingsLib/res/values-es/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Mostrar dispositivos Bluetooth sin nombre"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Inhabilitar volumen absoluto"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Habilitar Gabeldorsche"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Conectividad mejorada"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Versión AVRCP de Bluetooth"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Selecciona la versión AVRCP de Bluetooth"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Versión de MAP de Bluetooth"</string>
diff --git a/packages/SettingsLib/res/values-et/strings.xml b/packages/SettingsLib/res/values-et/strings.xml
index d003ef0b9c71..14d3b5782862 100644
--- a/packages/SettingsLib/res/values-et/strings.xml
+++ b/packages/SettingsLib/res/values-et/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Kuva ilma nimedeta Bluetoothi seadmed"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Keela absoluutne helitugevus"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Luba Gabeldorsche"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Täiustatud ühenduvus"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Bluetoothi AVRCP versioon"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Valige Bluetoothi AVRCP versioon"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Bluetoothi MAP-i versioon"</string>
diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml
index 0042321a3654..dcdadbdf3454 100644
--- a/packages/SettingsLib/res/values-eu/strings.xml
+++ b/packages/SettingsLib/res/values-eu/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Erakutsi Bluetooth bidezko gailuak izenik gabe"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Desgaitu bolumen absolutua"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Gaitu Gabeldorsche"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Konexio hobeak"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Bluetooth AVRCP bertsioa"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Hautatu Bluetooth AVRCP bertsioa"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Bluetooth MAParen bertsioa"</string>
diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml
index 1c0881531f89..f3b22d355b77 100644
--- a/packages/SettingsLib/res/values-fa/strings.xml
+++ b/packages/SettingsLib/res/values-fa/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"نمایش دستگاه‌های بلوتوث بدون نام"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"غیرفعال کردن میزان صدای مطلق"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"‏فعال کردن Gabeldorsche"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"اتصال بهبودیافته"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"‏نسخه AVRCP بلوتوث"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"‏انتخاب نسخه AVRCP بلوتوث"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"‏نسخه MAP بلوتوث"</string>
diff --git a/packages/SettingsLib/res/values-fi/strings.xml b/packages/SettingsLib/res/values-fi/strings.xml
index 3945e5542eb7..3d28f1d0a1f5 100644
--- a/packages/SettingsLib/res/values-fi/strings.xml
+++ b/packages/SettingsLib/res/values-fi/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Näytä nimettömät Bluetooth-laitteet"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Poista yleinen äänenvoimakkuuden säätö käytöstä"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Ota Gabeldorsche käyttöön"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Parannetut yhteydet"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Bluetoothin AVRCP-versio"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Valitse Bluetoothin AVRCP-versio"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Bluetoothin MAP-versio"</string>
diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml
index 140d4cee6ad7..87d3de16f216 100644
--- a/packages/SettingsLib/res/values-fr-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Afficher les appareils Bluetooth sans nom"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Désactiver le volume absolu"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Activer le Gabeldorsche"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Connectivité améliorée"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Version du profil Bluetooth AVRCP"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Sélectionner la version du profil Bluetooth AVRCP"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Version du profil Bluetooth MAP"</string>
diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml
index 1b1ae8ed55d4..ddf2bc0991a4 100644
--- a/packages/SettingsLib/res/values-fr/strings.xml
+++ b/packages/SettingsLib/res/values-fr/strings.xml
@@ -251,13 +251,12 @@
<string name="wifi_display_certification" msgid="1805579519992520381">"Certification affichage sans fil"</string>
<string name="wifi_verbose_logging" msgid="1785910450009679371">"Autoriser l\'enregistrement d\'infos Wi-Fi détaillées"</string>
<string name="wifi_scan_throttling" msgid="2985624788509913617">"Limiter la recherche Wi‑Fi"</string>
- <string name="wifi_enhanced_mac_randomization" msgid="5437378364995776979">"Chgt aléatoire d\'adresse MAC sur Wi-Fi"</string>
+ <string name="wifi_enhanced_mac_randomization" msgid="5437378364995776979">"Chgt aléatoire d\'adresse MAC en Wi-Fi"</string>
<string name="mobile_data_always_on" msgid="8275958101875563572">"Données mobiles toujours actives"</string>
<string name="tethering_hardware_offload" msgid="4116053719006939161">"Accélération matérielle pour le partage de connexion"</string>
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Afficher les appareils Bluetooth sans nom"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Désactiver le volume absolu"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Activer Gabeldorsche"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Connectivité améliorée"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Version Bluetooth AVRCP"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Sélectionner la version Bluetooth AVRCP"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Version Bluetooth MAP"</string>
@@ -284,7 +283,7 @@
<string name="wifi_display_certification_summary" msgid="8111151348106907513">"Afficher les options pour la certification de l\'affichage sans fil"</string>
<string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Détailler les infos Wi-Fi, afficher par RSSI de SSID dans l\'outil de sélection Wi-Fi"</string>
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Réduit la décharge de la batterie et améliore les performances du réseau"</string>
- <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Lorsque ce mode est activé, l\'adresse e-mail MAC de cet appareil peut changer lors de chaque connexion à un réseau pour lequel le changement aléatoire d\'adresse MAC est activé."</string>
+ <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Lorsque ce mode est activé, l\'adresse MAC de cet appareil peut changer lors de chaque connexion à un réseau Wi-Fi pour lequel le changement aléatoire d\'adresse MAC est activé"</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Facturé à l\'usage"</string>
<string name="wifi_unmetered_label" msgid="6174142840934095093">"Non facturé à l\'usage"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Tailles des tampons de l\'enregistreur"</string>
diff --git a/packages/SettingsLib/res/values-gl/strings.xml b/packages/SettingsLib/res/values-gl/strings.xml
index f9d57c453f69..af430991083d 100644
--- a/packages/SettingsLib/res/values-gl/strings.xml
+++ b/packages/SettingsLib/res/values-gl/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Mostrar dispositivos Bluetooth sen nomes"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Desactivar volume absoluto"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Activar Gabeldorsche"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Conectividade mellorada"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Versión de Bluetooth AVRCP"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Selecciona a versión de Bluetooth AVRCP"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Versión de MAP de Bluetooth"</string>
diff --git a/packages/SettingsLib/res/values-gu/strings.xml b/packages/SettingsLib/res/values-gu/strings.xml
index aa1f9605b07d..3261f69b1105 100644
--- a/packages/SettingsLib/res/values-gu/strings.xml
+++ b/packages/SettingsLib/res/values-gu/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"નામ વિનાના બ્લૂટૂથ ઉપકરણો બતાવો"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"ચોક્કસ વૉલ્યૂમને અક્ષમ કરો"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Gabeldorsche ચાલુ કરો"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"વિસ્તૃત કનેક્ટિવિટી"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"બ્લૂટૂથ AVRCP સંસ્કરણ"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"બ્લૂટૂથ AVRCP સંસ્કરણ પસંદ કરો"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"બ્લૂટૂથ MAP વર્ઝન"</string>
diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml
index 9b6a27ae8620..904a70e73958 100644
--- a/packages/SettingsLib/res/values-hi/strings.xml
+++ b/packages/SettingsLib/res/values-hi/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"बिना नाम वाले ब्लूटूथ डिवाइस दिखाएं"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"ब्लूटूथ से आवाज़ के नियंत्रण की सुविधा रोकें"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Gabeldorsche चालू करें"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"कनेक्टिविटी बेहतर बनाएं"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"ब्लूटूथ एवीआरसीपी वर्शन"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"ब्लूटूथ AVRCP वर्शन चुनें"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"ब्लूटूथ का MAP वर्शन"</string>
diff --git a/packages/SettingsLib/res/values-hr/strings.xml b/packages/SettingsLib/res/values-hr/strings.xml
index 14e3330a1670..3edc4527fb01 100644
--- a/packages/SettingsLib/res/values-hr/strings.xml
+++ b/packages/SettingsLib/res/values-hr/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Prikaži Bluetooth uređaje bez naziva"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Onemogući apsolutnu glasnoću"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Omogući Gabeldorsche"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Poboljšana povezivost"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Verzija AVRCP-a za Bluetooth"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Odaberite verziju AVRCP-a za Bluetooth"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Verzija MAP-a za Bluetooth"</string>
diff --git a/packages/SettingsLib/res/values-hu/strings.xml b/packages/SettingsLib/res/values-hu/strings.xml
index d16ff03b0903..fec2dd6d523f 100644
--- a/packages/SettingsLib/res/values-hu/strings.xml
+++ b/packages/SettingsLib/res/values-hu/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Név nélküli Bluetooth-eszközök megjelenítése"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Abszolút hangerő funkció letiltása"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"A Gabeldorsche engedélyezése"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Enhanced Connectivity"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"A Bluetooth AVRCP-verziója"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"A Bluetooth AVRCP-verziójának kiválasztása"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"A Bluetooth MAP-verziója"</string>
diff --git a/packages/SettingsLib/res/values-hy/strings.xml b/packages/SettingsLib/res/values-hy/strings.xml
index b010b504b00c..f219d248e641 100644
--- a/packages/SettingsLib/res/values-hy/strings.xml
+++ b/packages/SettingsLib/res/values-hy/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Ցուցադրել Bluetooth սարքերն առանց անունների"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Անջատել ձայնի բացարձակ ուժգնությունը"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Միացնել Gabeldorsche-ը"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Տվյալների լավացված փոխանակում"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Bluetooth AVRCP տարբերակը"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Ընտրել Bluetooth AVRCP տարբերակը"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Bluetooth MAP-ի տարբերակ"</string>
diff --git a/packages/SettingsLib/res/values-in/arrays.xml b/packages/SettingsLib/res/values-in/arrays.xml
index 37cf189f26c0..3ab50cc948eb 100644
--- a/packages/SettingsLib/res/values-in/arrays.xml
+++ b/packages/SettingsLib/res/values-in/arrays.xml
@@ -31,7 +31,7 @@
<item msgid="7852381437933824454">"Memutus sambungan..."</item>
<item msgid="5046795712175415059">"Sambungan terputus"</item>
<item msgid="2473654476624070462">"Gagal"</item>
- <item msgid="9146847076036105115">"Dicekal"</item>
+ <item msgid="9146847076036105115">"Diblokir"</item>
<item msgid="4543924085816294893">"Menghindari sambungan buruk untuk sementara"</item>
</string-array>
<string-array name="wifi_status_with_ssid">
diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml
index 42ccd5310913..a6f88465a673 100644
--- a/packages/SettingsLib/res/values-in/strings.xml
+++ b/packages/SettingsLib/res/values-in/strings.xml
@@ -180,8 +180,8 @@
<string name="tts_engine_settings_button" msgid="477155276199968948">"Luncurkan setelan mesin"</string>
<string name="tts_engine_preference_section_title" msgid="3861562305498624904">"Mesin yang dipilih"</string>
<string name="tts_general_section_title" msgid="8919671529502364567">"Umum"</string>
- <string name="tts_reset_speech_pitch_title" msgid="7149398585468413246">"Setel ulang tinggi nada ucapan"</string>
- <string name="tts_reset_speech_pitch_summary" msgid="6822904157021406449">"Setel ulang tinggi nada diucapkannya teks menjadi default."</string>
+ <string name="tts_reset_speech_pitch_title" msgid="7149398585468413246">"Reset tinggi nada ucapan"</string>
+ <string name="tts_reset_speech_pitch_summary" msgid="6822904157021406449">"Reset tinggi nada diucapkannya teks menjadi default."</string>
<string-array name="tts_rate_entries">
<item msgid="9004239613505400644">"Sangat lambat"</item>
<item msgid="1815382991399815061">"Lambat"</item>
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Tampilkan perangkat Bluetooth tanpa nama"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Nonaktifkan volume absolut"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Aktifkan Gabeldorsche"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Konektivitas Yang Disempurnakan"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Versi AVRCP Bluetooth"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Pilih Versi AVRCP Bluetooth"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Versi MAP Bluetooth"</string>
diff --git a/packages/SettingsLib/res/values-is/strings.xml b/packages/SettingsLib/res/values-is/strings.xml
index 0ebc341a9541..caf2323813ca 100644
--- a/packages/SettingsLib/res/values-is/strings.xml
+++ b/packages/SettingsLib/res/values-is/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Sýna Bluetooth-tæki án heita"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Slökkva á samstillingu hljóðstyrks"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Virkja Gabeldorsche"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Aukin tengigeta"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Bluetooth AVRCP-útgáfa"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Velja Bluetooth AVRCP-útgáfu"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Bluetooth MAP-útgáfa"</string>
diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml
index 50fdfc9a9136..8d18727e384c 100644
--- a/packages/SettingsLib/res/values-it/strings.xml
+++ b/packages/SettingsLib/res/values-it/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Mostra dispositivi Bluetooth senza nome"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Disattiva volume assoluto"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Attiva Gabeldorsche"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Connettività migliorata"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Versione Bluetooth AVRCP"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Seleziona versione Bluetooth AVRCP"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Versione Bluetooth MAP"</string>
diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml
index fb7d00f866b1..fff881c46433 100644
--- a/packages/SettingsLib/res/values-iw/strings.xml
+++ b/packages/SettingsLib/res/values-iw/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"‏הצגת מכשירי Bluetooth ללא שמות"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"השבת עוצמת קול מוחלטת"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"‏הפעלת Gabeldorsche"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"קישוריות משופרת"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"‏Bluetooth גרסה AVRCP"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"‏בחר Bluetooth גרסה AVRCP"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"‏גרסת Bluetooth MAP"</string>
diff --git a/packages/SettingsLib/res/values-ja/strings.xml b/packages/SettingsLib/res/values-ja/strings.xml
index 3537ceaf8204..5e579b758f09 100644
--- a/packages/SettingsLib/res/values-ja/strings.xml
+++ b/packages/SettingsLib/res/values-ja/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Bluetooth デバイスを名前なしで表示"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"絶対音量を無効にする"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Gabeldorsche を有効にする"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"接続強化"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Bluetooth AVRCP バージョン"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Bluetooth AVRCP バージョンを選択する"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Bluetooth MAP バージョン"</string>
diff --git a/packages/SettingsLib/res/values-ka/strings.xml b/packages/SettingsLib/res/values-ka/strings.xml
index 9b671a864e15..1b5fae9781b9 100644
--- a/packages/SettingsLib/res/values-ka/strings.xml
+++ b/packages/SettingsLib/res/values-ka/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Bluetooth-მოწყობილობების ჩვენება სახელების გარეშე"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"ხმის აბსოლუტური სიძლიერის გათიშვა"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Gabeldorsche-ის ჩართვა"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"კავშირის გაძლიერებული შესაძლებლობა"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Bluetooth-ის AVRCP-ის ვერსია"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"აირჩიეთ Bluetooth-ის AVRCP-ის ვერსია"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Bluetooth MAP-ის ვერსია"</string>
diff --git a/packages/SettingsLib/res/values-kk/strings.xml b/packages/SettingsLib/res/values-kk/strings.xml
index 279aca0731f7..9c290e90dd8d 100644
--- a/packages/SettingsLib/res/values-kk/strings.xml
+++ b/packages/SettingsLib/res/values-kk/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Bluetooth құрылғыларын атаусыз көрсету"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Абсолютті дыбыс деңгейін өшіру"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Gabeldorsche функциясын іске қосу"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Жетілдірілген байланыс"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Bluetooth AVRCP нұсқасы"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Bluetooth AVRCP нұсқасын таңдау"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Bluetooth MAP нұсқасы"</string>
diff --git a/packages/SettingsLib/res/values-km/strings.xml b/packages/SettingsLib/res/values-km/strings.xml
index 03065e896da2..2878db192d18 100644
--- a/packages/SettingsLib/res/values-km/strings.xml
+++ b/packages/SettingsLib/res/values-km/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"បង្ហាញ​ឧបករណ៍​ប្ល៊ូធូស​គ្មានឈ្មោះ"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"បិទកម្រិតសំឡេងលឺខ្លាំង"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"បើក Gabeldorsche"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"ការតភ្ជាប់​ដែលបានធ្វើឱ្យប្រសើរឡើង"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"កំណែប្ល៊ូធូស AVRCP"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"ជ្រើសរើសកំណែប្ល៊ូធូស AVRCP"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"កំណែ​ប៊្លូធូស MAP"</string>
diff --git a/packages/SettingsLib/res/values-kn/strings.xml b/packages/SettingsLib/res/values-kn/strings.xml
index 71c5e491d927..7b010564effa 100644
--- a/packages/SettingsLib/res/values-kn/strings.xml
+++ b/packages/SettingsLib/res/values-kn/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"ಹೆಸರುಗಳಿಲ್ಲದ ಬ್ಲೂಟೂತ್ ಸಾಧನಗಳನ್ನು ತೋರಿಸಿ"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"ಸಂಪೂರ್ಣ ವಾಲ್ಯೂಮ್‌ ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಿ"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Gabeldorsche ಅನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿ"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"ವರ್ಧಿತ ಸಂಪರ್ಕ"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"ಬ್ಲೂಟೂತ್ AVRCP ಆವೃತ್ತಿ"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"ಬ್ಲೂಟೂತ್ AVRCP ಆವೃತ್ತಿಯನ್ನು ಆಯ್ಕೆ ಮಾಡಿ"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"ಬ್ಲೂಟೂತ್ MAP ಆವೃತ್ತಿ"</string>
diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml
index 5d82eae2fcba..696ed2955daa 100644
--- a/packages/SettingsLib/res/values-ko/strings.xml
+++ b/packages/SettingsLib/res/values-ko/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"이름이 없는 블루투스 기기 표시"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"절대 볼륨 사용 안함"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Gabeldorsche 사용 설정"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"향상된 연결"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"블루투스 AVRCP 버전"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"블루투스 AVRCP 버전 선택"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"블루투스 MAP 버전"</string>
diff --git a/packages/SettingsLib/res/values-ky/strings.xml b/packages/SettingsLib/res/values-ky/strings.xml
index 2702392c108f..c4b5f7e7477f 100644
--- a/packages/SettingsLib/res/values-ky/strings.xml
+++ b/packages/SettingsLib/res/values-ky/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Аталышсыз Bluetooth түзмөктөрү көрсөтүлсүн"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Үндүн абсолюттук деңгээли өчүрүлсүн"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Gabeldorsche функциясын иштетүү"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Жакшыртылган туташуу"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Bluetooth AVRCP версиясы"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Bluetooth AVRCP версиясын тандоо"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Bluetooth MAP версиясы"</string>
diff --git a/packages/SettingsLib/res/values-lo/strings.xml b/packages/SettingsLib/res/values-lo/strings.xml
index 7a2c338ef008..a72861ee6aac 100644
--- a/packages/SettingsLib/res/values-lo/strings.xml
+++ b/packages/SettingsLib/res/values-lo/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"ສະແດງອຸປະກອນ Bluetooth ທີ່ບໍ່ມີຊື່"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"ປິດໃຊ້ລະດັບສຽງສົມບູນ"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"ເປີດໃຊ້ Gabeldorsche"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"ການເຊື່ອມຕໍ່ທີ່ເສີມແຕ່ງແລ້ວ"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"ເວີຊັນ Bluetooth AVRCP"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"ເລືອກເວີຊັນ Bluetooth AVRCP"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"ເວີຊັນ Bluetooth MAP"</string>
diff --git a/packages/SettingsLib/res/values-lt/strings.xml b/packages/SettingsLib/res/values-lt/strings.xml
index b73aa66ae54b..c72bf21d8b29 100644
--- a/packages/SettingsLib/res/values-lt/strings.xml
+++ b/packages/SettingsLib/res/values-lt/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Rodyti „Bluetooth“ įrenginius be pavadinimų"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Išjungti didžiausią garsą"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Įgalinti „Gabeldorsche“"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Patobulintas ryšys"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"„Bluetooth“ AVRCP versija"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Pasirinkite „Bluetooth“ AVRCP versiją"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"„Bluetooth“ MRK versija"</string>
diff --git a/packages/SettingsLib/res/values-lv/strings.xml b/packages/SettingsLib/res/values-lv/strings.xml
index 8e5d24cfa81a..d95e57df320e 100644
--- a/packages/SettingsLib/res/values-lv/strings.xml
+++ b/packages/SettingsLib/res/values-lv/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Rādīt Bluetooth ierīces bez nosaukumiem"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Atspējot absolūto skaļumu"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Iespējot Gabeldorsche"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Uzlabota savienojamība"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Bluetooth AVRCP versija"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Atlasiet Bluetooth AVRCP versiju"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Bluetooth MAP versija"</string>
diff --git a/packages/SettingsLib/res/values-mk/strings.xml b/packages/SettingsLib/res/values-mk/strings.xml
index 34299d801946..fb7b63410a5f 100644
--- a/packages/SettingsLib/res/values-mk/strings.xml
+++ b/packages/SettingsLib/res/values-mk/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Прикажувај уреди со Bluetooth без имиња"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Оневозможете апсолутна јачина на звук"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Овозможи Gabeldorsche"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Подобрена поврзливост"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Верзија Bluetooth AVRCP"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Изберете верзија Bluetooth AVRCP"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Верзија на Bluetooth MAP"</string>
diff --git a/packages/SettingsLib/res/values-ml/strings.xml b/packages/SettingsLib/res/values-ml/strings.xml
index c95f8bf2fe39..3c281c8d972f 100644
--- a/packages/SettingsLib/res/values-ml/strings.xml
+++ b/packages/SettingsLib/res/values-ml/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"പേരില്ലാത്ത Bluetooth ഉപകരണങ്ങൾ കാണിക്കുക"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"അബ്‌സൊല്യൂട്ട് വോളിയം പ്രവർത്തനരഹിതമാക്കുക"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Gabeldorsche പ്രവർത്തനക്ഷമമാക്കുക"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"മെച്ചപ്പെടുത്തിയ കണക്റ്റിവിറ്റി"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Bluetooth AVRCP പതിപ്പ്"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Bluetooth AVRCP പതിപ്പ് തിരഞ്ഞെടുക്കുക"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Bluetooth MAP പതിപ്പ്"</string>
diff --git a/packages/SettingsLib/res/values-mn/strings.xml b/packages/SettingsLib/res/values-mn/strings.xml
index 8407db6d3a08..37fc5b47619c 100644
--- a/packages/SettingsLib/res/values-mn/strings.xml
+++ b/packages/SettingsLib/res/values-mn/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Нэргүй Bluetooth төхөөрөмжийг харуулах"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Үнэмлэхүй дууны түвшинг идэвхгүй болгох"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Gabeldorsche-г идэвхжүүлэх"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Сайжруулсан холболт"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Bluetooth AVRCP хувилбар"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Bluetooth AVRCP хувилбарыг сонгох"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Bluetooth MAP хувилбар"</string>
diff --git a/packages/SettingsLib/res/values-mr/strings.xml b/packages/SettingsLib/res/values-mr/strings.xml
index c50f365f68e3..360f15897ebe 100644
--- a/packages/SettingsLib/res/values-mr/strings.xml
+++ b/packages/SettingsLib/res/values-mr/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"नावांशिवाय ब्‍लूटूथ डिव्‍हाइस दाखवा"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"संपूर्ण आवाज बंद करा"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"गाबलडॉर्ष सुरू करा"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"वर्धित कनेक्टिव्हिटी"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"ब्लूटूथ AVRCP आवृत्ती"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"ब्लूटूथ AVRCP आवृत्ती निवडा"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"ब्लूटूथ MAP आवृत्ती"</string>
diff --git a/packages/SettingsLib/res/values-ms/strings.xml b/packages/SettingsLib/res/values-ms/strings.xml
index a0a434f05959..68356df25ef9 100644
--- a/packages/SettingsLib/res/values-ms/strings.xml
+++ b/packages/SettingsLib/res/values-ms/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Tunjukkan peranti Bluetooth tanpa nama"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Lumpuhkan kelantangan mutlak"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Dayakan Gabeldorsche"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Kesambungan Dipertingkat"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Versi AVRCP Bluetooth"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Pilih Versi AVRCP Bluetooth"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Versi MAP Bluetooth"</string>
diff --git a/packages/SettingsLib/res/values-my/strings.xml b/packages/SettingsLib/res/values-my/strings.xml
index fa499293ceab..3729a8352abd 100644
--- a/packages/SettingsLib/res/values-my/strings.xml
+++ b/packages/SettingsLib/res/values-my/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"အမည်မရှိသော ဘလူးတုသ်စက်ပစ္စည်းများကို ပြသရန်"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"ပကတိ အသံနှုန်း သတ်မှတ်ချက် ပိတ်ရန်"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Gabeldorsche ကို ဖွင့်ရန်"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"အရည်အသွေးမြှင့်တင်ထားသော ချိတ်ဆက်နိုင်မှု"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"ဘလူးတုသ် AVRCP ဗားရှင်း"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"ဘလူးတုသ် AVRCP ဗားရှင်းကို ရွေးပါ"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"ဘလူးတုသ် MAP ဗားရှင်း"</string>
diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml
index aeaba31691f9..0e0e7617b06d 100644
--- a/packages/SettingsLib/res/values-nb/strings.xml
+++ b/packages/SettingsLib/res/values-nb/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Vis Bluetooth-enheter uten navn"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Slå av funksjonen for absolutt volum"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Aktiver Gabeldorsche"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Forbedret tilkobling"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Bluetooth AVRCP-versjon"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Velg Bluetooth AVRCP-versjon"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Bluetooth MAP-versjon"</string>
diff --git a/packages/SettingsLib/res/values-ne/strings.xml b/packages/SettingsLib/res/values-ne/strings.xml
index 4a2c1719aeb7..762d8304dd64 100644
--- a/packages/SettingsLib/res/values-ne/strings.xml
+++ b/packages/SettingsLib/res/values-ne/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"नामकरण नगरिएका ब्लुटुथ यन्त्रहरू देखाउनुहोस्"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"निरपेक्ष आवाज असक्षम गर्नुहोस्"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Gabeldorsche सक्षम पार्नुहोस्"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"परिष्कृत जडान"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"ब्लुटुथको AVRCP संस्करण"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"ब्लुटुथको AVRCP संस्करण चयन गर्नुहोस्"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"ब्लुटुथको MAP संस्करण"</string>
diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml
index 32cc39ec5b4f..83b72e925fe1 100644
--- a/packages/SettingsLib/res/values-nl/strings.xml
+++ b/packages/SettingsLib/res/values-nl/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Bluetooth-apparaten zonder namen weergeven"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Absoluut volume uitschakelen"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Gabeldorsche inschakelen"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Verbeterde connectiviteit"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Bluetooth-AVRCP-versie"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Bluetooth-AVRCP-versie selecteren"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"MAP-versie voor bluetooth"</string>
diff --git a/packages/SettingsLib/res/values-or/strings.xml b/packages/SettingsLib/res/values-or/strings.xml
index 8e5bf25a19ca..d200f502879e 100644
--- a/packages/SettingsLib/res/values-or/strings.xml
+++ b/packages/SettingsLib/res/values-or/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"ବ୍ଲୁଟୂଥ୍‍‌ ଡିଭାଇସ୍‌ଗୁଡ଼ିକୁ ନାମ ବିନା ଦେଖନ୍ତୁ"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"ପୂର୍ଣ୍ଣ ଭଲ୍ୟୁମ୍‌ ଅକ୍ଷମ କରନ୍ତୁ"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"ଗାବେଲ୍‌ଡୋର୍ସ ସକ୍ରିୟ କରନ୍ତୁ"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"ଏନହାନ୍ସଡ୍ କନେକ୍ଟିଭିଟି"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"ବ୍ଲୁଟୂଥ୍‌ AVRCP ଭର୍ସନ୍"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"ବ୍ଲୁଟୂଥ୍‍‌ AVRCP ଭର୍ସନ୍‌"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"ବ୍ଲୁଟୁଥ୍ MAP ସଂସ୍କରଣ"</string>
diff --git a/packages/SettingsLib/res/values-pa/strings.xml b/packages/SettingsLib/res/values-pa/strings.xml
index 15700130cf78..354ee126d9af 100644
--- a/packages/SettingsLib/res/values-pa/strings.xml
+++ b/packages/SettingsLib/res/values-pa/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"ਅਨਾਮ ਬਲੂਟੁੱਥ ਡੀਵਾਈਸਾਂ ਦਿਖਾਓ"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"ਪੂਰਨ ਅਵਾਜ਼ ਨੂੰ ਬੰਦ ਕਰੋ"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Gabeldorsche ਨੂੰ ਚਾਲੂ ਕਰੋ"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"ਵਿਸਤ੍ਰਿਤ ਕਨੈਕਟੀਵਿਟੀ"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"ਬਲੂਟੁੱਥ AVRCP ਵਰਜਨ"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"ਬਲੂਟੁੱਥ AVRCP ਵਰਜਨ ਚੁਣੋ"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Bluetooth MAP ਵਰਜਨ"</string>
diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml
index 1120c504717f..095412c94502 100644
--- a/packages/SettingsLib/res/values-pl/strings.xml
+++ b/packages/SettingsLib/res/values-pl/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Pokaż urządzenia Bluetooth bez nazw"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Wyłącz głośność bezwzględną"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Włącz Gabeldorsche"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Lepsza obsługa połączeń"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Wersja AVRCP Bluetooth"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Wybierz wersję AVRCP Bluetooth"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Wersja MAP Bluetooth"</string>
diff --git a/packages/SettingsLib/res/values-pt-rBR/strings.xml b/packages/SettingsLib/res/values-pt-rBR/strings.xml
index 4214a2720813..895a9872f4d4 100644
--- a/packages/SettingsLib/res/values-pt-rBR/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Mostrar dispositivos Bluetooth sem nomes"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Desativar volume absoluto"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Ativar Gabeldorsche"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Conectividade melhorada"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Versão do Bluetooth AVRCP"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Selecionar versão do Bluetooth AVRCP"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Versão MAP do Bluetooth"</string>
diff --git a/packages/SettingsLib/res/values-pt-rPT/strings.xml b/packages/SettingsLib/res/values-pt-rPT/strings.xml
index 508cbfccffe9..2d9f037297fb 100644
--- a/packages/SettingsLib/res/values-pt-rPT/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Mostrar dispositivos Bluetooth sem nomes"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Desativar volume absoluto"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Ativar o Gabeldorsche"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Conetividade melhorada"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Versão de Bluetooth AVRCP"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Selecionar versão de Bluetooth AVRCP"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Versão do MAP do Bluetooth"</string>
diff --git a/packages/SettingsLib/res/values-pt/strings.xml b/packages/SettingsLib/res/values-pt/strings.xml
index 4214a2720813..895a9872f4d4 100644
--- a/packages/SettingsLib/res/values-pt/strings.xml
+++ b/packages/SettingsLib/res/values-pt/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Mostrar dispositivos Bluetooth sem nomes"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Desativar volume absoluto"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Ativar Gabeldorsche"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Conectividade melhorada"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Versão do Bluetooth AVRCP"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Selecionar versão do Bluetooth AVRCP"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Versão MAP do Bluetooth"</string>
diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml
index 663d3f702ae5..728db174cd7b 100644
--- a/packages/SettingsLib/res/values-ro/strings.xml
+++ b/packages/SettingsLib/res/values-ro/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Afișați dispozitivele Bluetooth fără nume"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Dezactivați volumul absolut"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Activați Gabeldorsche"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Conectivitate îmbunătățită"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Versiunea AVRCP pentru Bluetooth"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Selectați versiunea AVRCP pentru Bluetooth"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Versiunea MAP pentru Bluetooth"</string>
diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml
index 9c0a2f5beb8b..ff2115ee3ff0 100644
--- a/packages/SettingsLib/res/values-ru/strings.xml
+++ b/packages/SettingsLib/res/values-ru/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Показывать Bluetooth-устройства без названий"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Отключить абсолютный уровень громкости"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Включить Gabeldorsche"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Улучшенный обмен данными"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Версия Bluetooth AVRCP"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Выберите версию Bluetooth AVRCP"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Версия Bluetooth MAP"</string>
diff --git a/packages/SettingsLib/res/values-si/strings.xml b/packages/SettingsLib/res/values-si/strings.xml
index 8d0e93e4b5f7..a883cc60d8e1 100644
--- a/packages/SettingsLib/res/values-si/strings.xml
+++ b/packages/SettingsLib/res/values-si/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"නම් නොමැති බ්ලූටූත් උපාංග පෙන්වන්න"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"නිරපේක්ෂ හඩ පරිමාව අබල කරන්න"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Gabeldorsche සබල කරන්න"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"වැඩිදියුණු කළ සබැඳුම් හැකියාව"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"බ්ලූටූත් AVRCP අනුවාදය"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"බ්ලූටූත් AVRCP අනුවාදය තෝරන්න"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Bluetooth MAP අනුවාදය"</string>
diff --git a/packages/SettingsLib/res/values-sk/strings.xml b/packages/SettingsLib/res/values-sk/strings.xml
index f39a741e3a4b..05c63795382b 100644
--- a/packages/SettingsLib/res/values-sk/strings.xml
+++ b/packages/SettingsLib/res/values-sk/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Zobrazovať zariadenia Bluetooth bez názvov"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Zakázať absolútnu hlasitosť"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Povoliť Gabeldorsche"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Zlepšené možnosti pripojenia"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Verzia rozhrania Bluetooth AVRCP"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Zvoľte verziu rozhrania Bluetooth AVRCP"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Verzia profilu Bluetooth MAP"</string>
diff --git a/packages/SettingsLib/res/values-sl/strings.xml b/packages/SettingsLib/res/values-sl/strings.xml
index 233c8e48635a..fd216e83d927 100644
--- a/packages/SettingsLib/res/values-sl/strings.xml
+++ b/packages/SettingsLib/res/values-sl/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Prikaži naprave Bluetooth brez imen"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Onemogočanje absolutne glasnosti"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Omogoči Gabeldorsche"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Izboljšana povezljivost"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Različica profila AVRCP za Bluetooth"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Izberite različico profila AVRCP za Bluetooth"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Različica profila MAP za Bluetooth"</string>
diff --git a/packages/SettingsLib/res/values-sq/strings.xml b/packages/SettingsLib/res/values-sq/strings.xml
index 6af1062a98f8..002c7fcda363 100644
--- a/packages/SettingsLib/res/values-sq/strings.xml
+++ b/packages/SettingsLib/res/values-sq/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Shfaq pajisjet me Bluetooth pa emra"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Çaktivizo volumin absolut"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Aktivizo Gabeldorsche"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Lidhshmëria e përmirësuar"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Versioni AVRCP i Bluetooth-it"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Zgjidh versionin AVRCP të Bluetooth-it"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Versioni MAP i Bluetooth-it"</string>
diff --git a/packages/SettingsLib/res/values-sr/strings.xml b/packages/SettingsLib/res/values-sr/strings.xml
index 74c2aec7c174..25a1beb7af68 100644
--- a/packages/SettingsLib/res/values-sr/strings.xml
+++ b/packages/SettingsLib/res/values-sr/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Прикажи Bluetooth уређаје без назива"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Онемогући главно подешавање јачине звука"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Омогући Gabeldorsche"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Побољшано повезивање"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Верзија Bluetooth AVRCP-а"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Изаберите верзију Bluetooth AVRCP-а"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Верзија Bluetooth MAP-а"</string>
diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml
index fe1b0a856802..352cb0ab7d19 100644
--- a/packages/SettingsLib/res/values-sv/strings.xml
+++ b/packages/SettingsLib/res/values-sv/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Visa namnlösa Bluetooth-enheter"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Inaktivera Absolute volume"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Aktivera Gabeldorsche"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Förbättrad anslutning"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"AVRCP-version för Bluetooth"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Välj AVRCP-version för Bluetooth"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"MAP-version för Bluetooth"</string>
diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml
index 5c80627003cd..d2891a06402a 100644
--- a/packages/SettingsLib/res/values-sw/strings.xml
+++ b/packages/SettingsLib/res/values-sw/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Onyesha vifaa vya Bluetooth visivyo na majina"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Zima sauti kamili"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Washa Gabeldorsche"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Muunganisho Ulioboreshwa"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Toleo la Bluetooth AVRCP"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Chagua Toleo la Bluetooth AVRCP"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Toleo la Ramani ya Bluetooth"</string>
diff --git a/packages/SettingsLib/res/values-ta/strings.xml b/packages/SettingsLib/res/values-ta/strings.xml
index 241644f631d3..7837dd8d46df 100644
--- a/packages/SettingsLib/res/values-ta/strings.xml
+++ b/packages/SettingsLib/res/values-ta/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"பெயர்கள் இல்லாத புளூடூத் சாதனங்களைக் காட்டு"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"அப்சல்யூட் ஒலியளவு அம்சத்தை முடக்கு"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Gabeldorscheவை இயக்கு"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"மேம்படுத்தப்பட்ட இணைப்புநிலை"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"புளூடூத் AVRCP பதிப்பு"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"புளூடூத் AVRCP பதிப்பைத் தேர்ந்தெடு"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"புளூடூத்தின் MAP பதிப்பு"</string>
diff --git a/packages/SettingsLib/res/values-te/strings.xml b/packages/SettingsLib/res/values-te/strings.xml
index a9ec2ea95ac5..60001a0b0ecd 100644
--- a/packages/SettingsLib/res/values-te/strings.xml
+++ b/packages/SettingsLib/res/values-te/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"పేర్లు లేని బ్లూటూత్ పరికరాలు చూపించు"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"సంపూర్ణ వాల్యూమ్‌‍ను నిలిపివేయి"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Gabeldorscheను ఎనేబుల్ చేయి"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"మెరుగైన కనెక్టివిటీ"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"బ్లూటూత్ AVRCP వెర్షన్"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"బ్లూటూత్ AVRCP సంస్కరణను ఎంచుకోండి"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"బ్లూటూత్ MAP వెర్షన్‌"</string>
diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml
index b8343c6a82e7..defc33ee9233 100644
--- a/packages/SettingsLib/res/values-th/strings.xml
+++ b/packages/SettingsLib/res/values-th/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"แสดงอุปกรณ์บลูทูธที่ไม่มีชื่อ"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"ปิดใช้การควบคุมระดับเสียงของอุปกรณ์อื่น"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"เปิดใช้ Gabeldorsche"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"การเชื่อมต่อที่ปรับปรุงแล้ว"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"เวอร์ชันของบลูทูธ AVRCP"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"เลือกเวอร์ชันของบลูทูธ AVRCP"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"เวอร์ชัน MAP ของบลูทูธ"</string>
diff --git a/packages/SettingsLib/res/values-tl/strings.xml b/packages/SettingsLib/res/values-tl/strings.xml
index 8aeb39256748..5d4e9752fd93 100644
--- a/packages/SettingsLib/res/values-tl/strings.xml
+++ b/packages/SettingsLib/res/values-tl/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Ipakita ang mga Bluetooth device na walang pangalan"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"I-disable ang absolute volume"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"I-enable ang Gabeldorsche"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Pinagandang Pagkakonekta"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Bersyon ng AVRCP ng Bluetooth"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Pumili ng Bersyon ng AVRCP ng Bluetooth"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Bersyon ng MAP ng Bluetooth"</string>
diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml
index e6d938047fcf..f01f3faed73e 100644
--- a/packages/SettingsLib/res/values-tr/strings.xml
+++ b/packages/SettingsLib/res/values-tr/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Adsız Bluetooth cihazlarını göster"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Mutlak sesi iptal et"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Gabeldorsche\'yi etkileştir"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Gelişmiş Bağlantı"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Bluetooth AVRCP Sürümü"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Bluetooth AVRCP Sürümünü seçin"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Bluetooth MAP Sürümü"</string>
diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml
index cf1fafd8f190..9ca2f062127a 100644
--- a/packages/SettingsLib/res/values-uk/strings.xml
+++ b/packages/SettingsLib/res/values-uk/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Показувати пристрої Bluetooth без назв"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Вимкнути абсолютну гучність"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Увімкнути Gabeldorsche"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Покращене з\'єднання"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Версія Bluetooth AVRCP"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Виберіть версію Bluetooth AVRCP"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Версія Bluetooth MAP"</string>
diff --git a/packages/SettingsLib/res/values-ur/strings.xml b/packages/SettingsLib/res/values-ur/strings.xml
index b7fbe6fad392..8953f50078f1 100644
--- a/packages/SettingsLib/res/values-ur/strings.xml
+++ b/packages/SettingsLib/res/values-ur/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"بغیر نام والے بلوٹوتھ آلات دکھائیں"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"مطلق والیوم کو غیر فعال کریں"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"‏Gabeldorsche فعال کریں"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"بہتر کردہ کنیکٹوٹی"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"‏بلوٹوتھ AVRCP ورژن"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"‏بلوٹوتھ AVRCP ورژن منتخب کریں"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"‏بلوٹوتھ MAP ورژن"</string>
diff --git a/packages/SettingsLib/res/values-uz/strings.xml b/packages/SettingsLib/res/values-uz/strings.xml
index f81731ab2723..f25b3ac3c37f 100644
--- a/packages/SettingsLib/res/values-uz/strings.xml
+++ b/packages/SettingsLib/res/values-uz/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Bluetooth qurilmalarini nomlarisiz ko‘rsatish"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Tovush balandligining mutlaq darajasini faolsizlantirish"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Gabeldorsche funksiyasini yoqish"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Kuchaytirilgan aloqa"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Bluetooth AVRCP versiyasi"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Bluetooth AVRCP versiyasini tanlang"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Bluetooth MAP versiyasi"</string>
diff --git a/packages/SettingsLib/res/values-vi/strings.xml b/packages/SettingsLib/res/values-vi/strings.xml
index b7ccf8d85677..b5798f31d0f9 100644
--- a/packages/SettingsLib/res/values-vi/strings.xml
+++ b/packages/SettingsLib/res/values-vi/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Hiển thị các thiết bị Bluetooth không có tên"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Vô hiệu hóa âm lượng tuyệt đối"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Bật tính năng Gabeldorsche"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Kết nối nâng cao"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Phiên bản Bluetooth AVRCP"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Chọn phiên bản Bluetooth AVRCP"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Phiên bản Bluetooth MAP"</string>
diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml
index 75c1333c37c1..c4dcfff1b579 100644
--- a/packages/SettingsLib/res/values-zh-rCN/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"显示没有名称的蓝牙设备"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"停用绝对音量功能"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"启用“Gabeldorsche”"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"增强连接性"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"蓝牙 AVRCP 版本"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"选择蓝牙 AVRCP 版本"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"蓝牙 MAP 版本"</string>
diff --git a/packages/SettingsLib/res/values-zh-rHK/strings.xml b/packages/SettingsLib/res/values-zh-rHK/strings.xml
index 26ddfb13717b..e04651cac5f6 100644
--- a/packages/SettingsLib/res/values-zh-rHK/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rHK/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"顯示沒有名稱的藍牙裝置"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"停用絕對音量功能"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"啟用 Gabeldorsche"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"強化連線功能"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"藍牙 AVRCP 版本"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"選擇藍牙 AVRCP 版本"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"藍牙 MAP 版本"</string>
diff --git a/packages/SettingsLib/res/values-zh-rTW/strings.xml b/packages/SettingsLib/res/values-zh-rTW/strings.xml
index 72ea0439b1f6..a1ae6b6c27a1 100644
--- a/packages/SettingsLib/res/values-zh-rTW/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rTW/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"顯示沒有名稱的藍牙裝置"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"停用絕對音量功能"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"啟用 Gabeldorsche"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"加強型連線"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"藍牙 AVRCP 版本"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"選取藍牙 AVRCP 版本"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"藍牙 MAP 版本"</string>
diff --git a/packages/SettingsLib/res/values-zu/strings.xml b/packages/SettingsLib/res/values-zu/strings.xml
index 6b8739fd017a..2dafad8114d8 100644
--- a/packages/SettingsLib/res/values-zu/strings.xml
+++ b/packages/SettingsLib/res/values-zu/strings.xml
@@ -257,7 +257,6 @@
<string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Bonisa amadivayisi e-Bluetooth ngaphandle kwamagama"</string>
<string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Khubaza ivolumu ngokuphelele"</string>
<string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Nika amandla i-Gabeldorsche"</string>
- <string name="enhanced_connectivity" msgid="7201127377781666804">"Ukuxhumeka Okuthuthukisiwe"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="1710571610177659127">"Inguqulo ye-Bluetooth ye-AVRCP"</string>
<string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Khetha inguqulo ye-Bluetooth AVRCP"</string>
<string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Inguqulo ye-Bluetooth MAP"</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/development/DeveloperOptionsPreferenceController.java b/packages/SettingsLib/src/com/android/settingslib/development/DeveloperOptionsPreferenceController.java
index f757aa4e4dab..b29595eab5c7 100644
--- a/packages/SettingsLib/src/com/android/settingslib/development/DeveloperOptionsPreferenceController.java
+++ b/packages/SettingsLib/src/com/android/settingslib/development/DeveloperOptionsPreferenceController.java
@@ -24,7 +24,7 @@ import androidx.preference.PreferenceScreen;
import com.android.settingslib.core.AbstractPreferenceController;
/**
- * This controller is used handle changes for the master switch in the developer options page.
+ * This controller is used handle changes for the primary switch in the developer options page.
*
* All Preference Controllers that are a part of the developer options page should inherit this
* class.
diff --git a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/PowerWhitelistBackend.java b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/PowerAllowlistBackend.java
index 3c647a7ec465..c501b3aab4d4 100644
--- a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/PowerWhitelistBackend.java
+++ b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/PowerAllowlistBackend.java
@@ -34,44 +34,50 @@ import com.android.internal.telephony.SmsApplication;
import com.android.internal.util.ArrayUtils;
/**
- * Handles getting/changing the whitelist for the exceptions to battery saving features.
+ * Handles getting/changing the allowlist for the exceptions to battery saving features.
*/
-public class PowerWhitelistBackend {
+public class PowerAllowlistBackend {
- private static final String TAG = "PowerWhitelistBackend";
+ private static final String TAG = "PowerAllowlistBackend";
private static final String DEVICE_IDLE_SERVICE = "deviceidle";
- private static PowerWhitelistBackend sInstance;
+ private static PowerAllowlistBackend sInstance;
private final Context mAppContext;
private final IDeviceIdleController mDeviceIdleService;
- private final ArraySet<String> mWhitelistedApps = new ArraySet<>();
- private final ArraySet<String> mSysWhitelistedApps = new ArraySet<>();
+ private final ArraySet<String> mAllowlistedApps = new ArraySet<>();
+ private final ArraySet<String> mSysAllowlistedApps = new ArraySet<>();
private final ArraySet<String> mDefaultActiveApps = new ArraySet<>();
- public PowerWhitelistBackend(Context context) {
+ public PowerAllowlistBackend(Context context) {
this(context, IDeviceIdleController.Stub.asInterface(
ServiceManager.getService(DEVICE_IDLE_SERVICE)));
}
@VisibleForTesting
- PowerWhitelistBackend(Context context, IDeviceIdleController deviceIdleService) {
+ PowerAllowlistBackend(Context context, IDeviceIdleController deviceIdleService) {
mAppContext = context.getApplicationContext();
mDeviceIdleService = deviceIdleService;
refreshList();
}
- public int getWhitelistSize() {
- return mWhitelistedApps.size();
+ public int getAllowlistSize() {
+ return mAllowlistedApps.size();
}
- public boolean isSysWhitelisted(String pkg) {
- return mSysWhitelistedApps.contains(pkg);
+ /**
+ * Check if target package is in System allow list
+ */
+ public boolean isSysAllowlisted(String pkg) {
+ return mSysAllowlistedApps.contains(pkg);
}
- public boolean isWhitelisted(String pkg) {
- if (mWhitelistedApps.contains(pkg)) {
+ /**
+ * Check if target package is in allow list
+ */
+ public boolean isAllowlisted(String pkg) {
+ if (mAllowlistedApps.contains(pkg)) {
return true;
}
@@ -87,7 +93,7 @@ public class PowerWhitelistBackend {
*/
public boolean isDefaultActiveApp(String pkg) {
// Additionally, check if pkg is default dialer/sms. They are considered essential apps and
- // should be automatically whitelisted (otherwise user may be able to set restriction on
+ // should be automatically allowlisted (otherwise user may be able to set restriction on
// them, leading to bad device behavior.)
if (mDefaultActiveApps.contains(pkg)) {
@@ -103,12 +109,17 @@ public class PowerWhitelistBackend {
return false;
}
- public boolean isWhitelisted(String[] pkgs) {
+ /**
+ *
+ * @param pkgs a list of packageName
+ * @return true when one of package is in allow list
+ */
+ public boolean isAllowlisted(String[] pkgs) {
if (ArrayUtils.isEmpty(pkgs)) {
return false;
}
for (String pkg : pkgs) {
- if (isWhitelisted(pkg)) {
+ if (isAllowlisted(pkg)) {
return true;
}
}
@@ -116,40 +127,51 @@ public class PowerWhitelistBackend {
return false;
}
+ /**
+ * Add app into power save allow list.
+ * @param pkg packageName
+ */
public void addApp(String pkg) {
try {
mDeviceIdleService.addPowerSaveWhitelistApp(pkg);
- mWhitelistedApps.add(pkg);
+ mAllowlistedApps.add(pkg);
} catch (RemoteException e) {
Log.w(TAG, "Unable to reach IDeviceIdleController", e);
}
}
+ /**
+ * Remove package from power save allow list.
+ * @param pkg
+ */
public void removeApp(String pkg) {
try {
mDeviceIdleService.removePowerSaveWhitelistApp(pkg);
- mWhitelistedApps.remove(pkg);
+ mAllowlistedApps.remove(pkg);
} catch (RemoteException e) {
Log.w(TAG, "Unable to reach IDeviceIdleController", e);
}
}
+ /**
+ * Refresh all of lists
+ */
@VisibleForTesting
public void refreshList() {
- mSysWhitelistedApps.clear();
- mWhitelistedApps.clear();
+ mSysAllowlistedApps.clear();
+ mAllowlistedApps.clear();
mDefaultActiveApps.clear();
if (mDeviceIdleService == null) {
return;
}
try {
- final String[] whitelistedApps = mDeviceIdleService.getFullPowerWhitelist();
- for (String app : whitelistedApps) {
- mWhitelistedApps.add(app);
+ final String[] allowlistedApps = mDeviceIdleService.getFullPowerWhitelist();
+ for (String app : allowlistedApps) {
+ mAllowlistedApps.add(app);
}
- final String[] sysWhitelistedApps = mDeviceIdleService.getSystemPowerWhitelist();
- for (String app : sysWhitelistedApps) {
- mSysWhitelistedApps.add(app);
+ final String[] sysAllowlistedApps = mDeviceIdleService.getSystemPowerWhitelist();
+ for (String app : sysAllowlistedApps) {
+ mSysAllowlistedApps.add(app);
}
final boolean hasTelephony = mAppContext.getPackageManager().hasSystemFeature(
PackageManager.FEATURE_TELEPHONY);
@@ -171,9 +193,13 @@ public class PowerWhitelistBackend {
}
}
- public static PowerWhitelistBackend getInstance(Context context) {
+ /**
+ * @param context
+ * @return a PowerAllowlistBackend object
+ */
+ public static PowerAllowlistBackend getInstance(Context context) {
if (sInstance == null) {
- sInstance = new PowerWhitelistBackend(context);
+ sInstance = new PowerAllowlistBackend(context);
}
return sInstance;
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/users/AppRestrictionsHelper.java b/packages/SettingsLib/src/com/android/settingslib/users/AppRestrictionsHelper.java
index 4941f7e42bf6..8ac434957cd9 100644
--- a/packages/SettingsLib/src/com/android/settingslib/users/AppRestrictionsHelper.java
+++ b/packages/SettingsLib/src/com/android/settingslib/users/AppRestrictionsHelper.java
@@ -135,7 +135,7 @@ public class AppRestrictionsHelper {
// Ignore
}
} else {
- // Blacklist all other apps, system or downloaded
+ // Denylist all other apps, system or downloaded
try {
ApplicationInfo info = mIPm.getApplicationInfo(packageName, 0, userId);
if (info != null) {
@@ -258,11 +258,11 @@ public class AppRestrictionsHelper {
}
}
- // Establish master/slave relationship for entries that share a package name
+ // Establish primary/secondary relationship for entries that share a package name
HashMap<String,SelectableAppInfo> packageMap = new HashMap<String,SelectableAppInfo>();
for (SelectableAppInfo info : mVisibleApps) {
if (packageMap.containsKey(info.packageName)) {
- info.masterEntry = packageMap.get(info.packageName);
+ info.primaryEntry = packageMap.get(info.packageName);
} else {
packageMap.put(info.packageName, info);
}
@@ -366,12 +366,12 @@ public class AppRestrictionsHelper {
public CharSequence appName;
public CharSequence activityName;
public Drawable icon;
- public SelectableAppInfo masterEntry;
+ public SelectableAppInfo primaryEntry;
@Override
public String toString() {
return packageName + ": appName=" + appName + "; activityName=" + activityName
- + "; icon=" + icon + "; masterEntry=" + masterEntry;
+ + "; icon=" + icon + "; primaryEntry=" + primaryEntry;
}
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedLockUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedLockUtilsTest.java
index 11c799ea9df5..94e28f2b5e22 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedLockUtilsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedLockUtilsTest.java
@@ -290,12 +290,12 @@ public class RestrictedLockUtilsTest {
@Test
public void sendShowAdminSupportDetailsIntent_extraRestrictionProvided() {
EnforcedAdmin enforcedAdmin = new EnforcedAdmin();
- enforcedAdmin.enforcedRestriction = "Dummy";
+ enforcedAdmin.enforcedRestriction = "Fake";
RestrictedLockUtils.sendShowAdminSupportDetailsIntent(mContext, enforcedAdmin);
ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
verify(mContext).startActivityAsUser(intentCaptor.capture(), any());
- assertThat(intentCaptor.getValue().getExtra(EXTRA_RESTRICTION)).isEqualTo("Dummy");
+ assertThat(intentCaptor.getValue().getExtra(EXTRA_RESTRICTION)).isEqualTo("Fake");
}
@Test
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/MasterSwitchControllerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/PrimarySwitchControllerTest.java
index 69d0f2e71c17..9e4cde866ef2 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/MasterSwitchControllerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/PrimarySwitchControllerTest.java
@@ -23,16 +23,16 @@ import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
@RunWith(RobolectricTestRunner.class)
-public class MasterSwitchControllerTest {
+public class PrimarySwitchControllerTest {
@Rule
public final ExpectedException thrown = ExpectedException.none();
- private MasterSwitchController mController;
+ private PrimarySwitchController mController;
@Before
public void setUp() {
- mController = new TestMasterSwitchController("123");
+ mController = new TestPrimarySwitchController("123");
}
@Test
@@ -49,11 +49,11 @@ public class MasterSwitchControllerTest {
mController.getBundle();
}
- static class TestMasterSwitchController extends MasterSwitchController {
+ static class TestPrimarySwitchController extends PrimarySwitchController {
private String mKey;
- TestMasterSwitchController(String key) {
+ TestPrimarySwitchController(String key) {
mKey = key;
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/SwitchesProviderTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/SwitchesProviderTest.java
index a740e683642a..bd0100b67a94 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/SwitchesProviderTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/SwitchesProviderTest.java
@@ -35,7 +35,7 @@ import android.content.Context;
import android.content.pm.ProviderInfo;
import android.os.Bundle;
-import com.android.settingslib.drawer.MasterSwitchControllerTest.TestMasterSwitchController;
+import com.android.settingslib.drawer.PrimarySwitchControllerTest.TestPrimarySwitchController;
import com.android.settingslib.drawer.SwitchController.MetaData;
import org.junit.Before;
@@ -124,8 +124,8 @@ public class SwitchesProviderTest {
}
@Test
- public void getSwitchData_shouldNotReturnMasterSwitchData() {
- final SwitchController controller = new TestMasterSwitchController("123");
+ public void getSwitchData_shouldNotReturnPrimarySwitchData() {
+ final SwitchController controller = new TestPrimarySwitchController("123");
mSwitchesProvider.addSwitchController(controller);
mSwitchesProvider.attachInfo(mContext, mProviderInfo);
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/PowerWhitelistBackendTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/PowerAllowlistBackendTest.java
index 20908925feff..4f11fb1f782f 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/PowerWhitelistBackendTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/PowerAllowlistBackendTest.java
@@ -47,7 +47,7 @@ import org.robolectric.shadows.ShadowPackageManager;
@RunWith(RobolectricTestRunner.class)
@Config(shadows = {ShadowDefaultDialerManager.class, ShadowSmsApplication.class})
-public class PowerWhitelistBackendTest {
+public class PowerAllowlistBackendTest {
private static final String PACKAGE_ONE = "com.example.packageone";
private static final String PACKAGE_TWO = "com.example.packagetwo";
@@ -56,7 +56,7 @@ public class PowerWhitelistBackendTest {
private IDeviceIdleController mDeviceIdleService;
@Mock
private DevicePolicyManager mDevicePolicyManager;
- private PowerWhitelistBackend mPowerWhitelistBackend;
+ private PowerAllowlistBackend mPowerAllowlistBackend;
private ShadowPackageManager mPackageManager;
private Context mContext;
@@ -74,81 +74,81 @@ public class PowerWhitelistBackendTest {
mPackageManager.setSystemFeature(PackageManager.FEATURE_TELEPHONY, true);
doReturn(mDevicePolicyManager).when(mContext).getSystemService(DevicePolicyManager.class);
- mPowerWhitelistBackend = new PowerWhitelistBackend(mContext, mDeviceIdleService);
+ mPowerAllowlistBackend = new PowerAllowlistBackend(mContext, mDeviceIdleService);
}
@Test
- public void testIsWhitelisted() throws Exception {
+ public void testIsAllowlisted() throws Exception {
doReturn(new String[] {PACKAGE_ONE}).when(mDeviceIdleService).getFullPowerWhitelist();
- mPowerWhitelistBackend.refreshList();
+ mPowerAllowlistBackend.refreshList();
- assertThat(mPowerWhitelistBackend.isWhitelisted(PACKAGE_ONE)).isTrue();
- assertThat(mPowerWhitelistBackend.isWhitelisted(PACKAGE_TWO)).isFalse();
- assertThat(mPowerWhitelistBackend.isWhitelisted(new String[] {PACKAGE_ONE})).isTrue();
- assertThat(mPowerWhitelistBackend.isWhitelisted(new String[] {PACKAGE_TWO})).isFalse();
+ assertThat(mPowerAllowlistBackend.isAllowlisted(PACKAGE_ONE)).isTrue();
+ assertThat(mPowerAllowlistBackend.isAllowlisted(PACKAGE_TWO)).isFalse();
+ assertThat(mPowerAllowlistBackend.isAllowlisted(new String[] {PACKAGE_ONE})).isTrue();
+ assertThat(mPowerAllowlistBackend.isAllowlisted(new String[] {PACKAGE_TWO})).isFalse();
- mPowerWhitelistBackend.addApp(PACKAGE_TWO);
+ mPowerAllowlistBackend.addApp(PACKAGE_TWO);
verify(mDeviceIdleService, atLeastOnce()).addPowerSaveWhitelistApp(PACKAGE_TWO);
- assertThat(mPowerWhitelistBackend.isWhitelisted(PACKAGE_ONE)).isTrue();
- assertThat(mPowerWhitelistBackend.isWhitelisted(PACKAGE_TWO)).isTrue();
- assertThat(mPowerWhitelistBackend.isWhitelisted(
+ assertThat(mPowerAllowlistBackend.isAllowlisted(PACKAGE_ONE)).isTrue();
+ assertThat(mPowerAllowlistBackend.isAllowlisted(PACKAGE_TWO)).isTrue();
+ assertThat(mPowerAllowlistBackend.isAllowlisted(
new String[] {PACKAGE_ONE, PACKAGE_TWO})).isTrue();
- mPowerWhitelistBackend.removeApp(PACKAGE_TWO);
+ mPowerAllowlistBackend.removeApp(PACKAGE_TWO);
verify(mDeviceIdleService, atLeastOnce()).removePowerSaveWhitelistApp(PACKAGE_TWO);
- assertThat(mPowerWhitelistBackend.isWhitelisted(PACKAGE_ONE)).isTrue();
- assertThat(mPowerWhitelistBackend.isWhitelisted(PACKAGE_TWO)).isFalse();
- assertThat(mPowerWhitelistBackend.isWhitelisted(new String[] {PACKAGE_ONE})).isTrue();
- assertThat(mPowerWhitelistBackend.isWhitelisted(new String[] {PACKAGE_TWO})).isFalse();
+ assertThat(mPowerAllowlistBackend.isAllowlisted(PACKAGE_ONE)).isTrue();
+ assertThat(mPowerAllowlistBackend.isAllowlisted(PACKAGE_TWO)).isFalse();
+ assertThat(mPowerAllowlistBackend.isAllowlisted(new String[] {PACKAGE_ONE})).isTrue();
+ assertThat(mPowerAllowlistBackend.isAllowlisted(new String[] {PACKAGE_TWO})).isFalse();
- mPowerWhitelistBackend.removeApp(PACKAGE_ONE);
+ mPowerAllowlistBackend.removeApp(PACKAGE_ONE);
verify(mDeviceIdleService, atLeastOnce()).removePowerSaveWhitelistApp(PACKAGE_ONE);
- assertThat(mPowerWhitelistBackend.isWhitelisted(PACKAGE_ONE)).isFalse();
- assertThat(mPowerWhitelistBackend.isWhitelisted(PACKAGE_TWO)).isFalse();
- assertThat(mPowerWhitelistBackend.isWhitelisted(
+ assertThat(mPowerAllowlistBackend.isAllowlisted(PACKAGE_ONE)).isFalse();
+ assertThat(mPowerAllowlistBackend.isAllowlisted(PACKAGE_TWO)).isFalse();
+ assertThat(mPowerAllowlistBackend.isAllowlisted(
new String[] {PACKAGE_ONE, PACKAGE_TWO})).isFalse();
}
@Test
- public void isWhitelisted_shouldWhitelistDefaultSms() {
+ public void isAllowlisted_shouldAllowlistDefaultSms() {
final String testSms = "com.android.test.defaultsms";
ShadowSmsApplication.setDefaultSmsApplication(new ComponentName(testSms, "receiver"));
- mPowerWhitelistBackend.refreshList();
+ mPowerAllowlistBackend.refreshList();
- assertThat(mPowerWhitelistBackend.isWhitelisted(testSms)).isTrue();
- assertThat(mPowerWhitelistBackend.isDefaultActiveApp(testSms)).isTrue();
+ assertThat(mPowerAllowlistBackend.isAllowlisted(testSms)).isTrue();
+ assertThat(mPowerAllowlistBackend.isDefaultActiveApp(testSms)).isTrue();
}
@Test
- public void isWhitelisted_shouldWhitelistDefaultDialer() {
+ public void isAllowlisted_shouldAllowlistDefaultDialer() {
final String testDialer = "com.android.test.defaultdialer";
ShadowDefaultDialerManager.setDefaultDialerApplication(testDialer);
- mPowerWhitelistBackend.refreshList();
+ mPowerAllowlistBackend.refreshList();
- assertThat(mPowerWhitelistBackend.isWhitelisted(testDialer)).isTrue();
- assertThat(mPowerWhitelistBackend.isDefaultActiveApp(testDialer)).isTrue();
+ assertThat(mPowerAllowlistBackend.isAllowlisted(testDialer)).isTrue();
+ assertThat(mPowerAllowlistBackend.isDefaultActiveApp(testDialer)).isTrue();
}
@Test
- public void isWhitelisted_shouldWhitelistActiveDeviceAdminApp() {
+ public void isAllowlisted_shouldAllowlistActiveDeviceAdminApp() {
doReturn(true).when(mDevicePolicyManager).packageHasActiveAdmins(PACKAGE_ONE);
- assertThat(mPowerWhitelistBackend.isWhitelisted(PACKAGE_ONE)).isTrue();
- assertThat(mPowerWhitelistBackend.isDefaultActiveApp(PACKAGE_ONE)).isTrue();
+ assertThat(mPowerAllowlistBackend.isAllowlisted(PACKAGE_ONE)).isTrue();
+ assertThat(mPowerAllowlistBackend.isDefaultActiveApp(PACKAGE_ONE)).isTrue();
}
@Test
- public void testIsSystemWhitelisted() throws Exception {
+ public void testIsSystemAllowlisted() throws Exception {
doReturn(new String[] {PACKAGE_ONE}).when(mDeviceIdleService).getSystemPowerWhitelist();
- mPowerWhitelistBackend.refreshList();
+ mPowerAllowlistBackend.refreshList();
- assertThat(mPowerWhitelistBackend.isSysWhitelisted(PACKAGE_ONE)).isTrue();
- assertThat(mPowerWhitelistBackend.isSysWhitelisted(PACKAGE_TWO)).isFalse();
- assertThat(mPowerWhitelistBackend.isWhitelisted(PACKAGE_ONE)).isFalse();
+ assertThat(mPowerAllowlistBackend.isSysAllowlisted(PACKAGE_ONE)).isTrue();
+ assertThat(mPowerAllowlistBackend.isSysAllowlisted(PACKAGE_TWO)).isFalse();
+ assertThat(mPowerAllowlistBackend.isAllowlisted(PACKAGE_ONE)).isFalse();
}
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/inputmethod/InputMethodAndSubtypeUtilCompatTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/inputmethod/InputMethodAndSubtypeUtilCompatTest.java
index b930aa6ee1bd..84d722ad16df 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/inputmethod/InputMethodAndSubtypeUtilCompatTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/inputmethod/InputMethodAndSubtypeUtilCompatTest.java
@@ -197,61 +197,61 @@ public class InputMethodAndSubtypeUtilCompatTest {
public void isValidSystemNonAuxAsciiCapableIme() {
// System IME w/ no subtype
assertThat(InputMethodAndSubtypeUtilCompat.isValidSystemNonAuxAsciiCapableIme(
- createDummyIme(true, false)))
+ createFakeIme(true, false)))
.isFalse();
// System IME w/ non-Aux and non-ASCII-capable "keyboard" subtype
assertThat(InputMethodAndSubtypeUtilCompat.isValidSystemNonAuxAsciiCapableIme(
- createDummyIme(true, false, createDummySubtype("keyboard", false, false))))
+ createFakeIme(true, false, createFakeSubtype("keyboard", false, false))))
.isFalse();
// System IME w/ non-Aux and ASCII-capable "keyboard" subtype
assertThat(InputMethodAndSubtypeUtilCompat.isValidSystemNonAuxAsciiCapableIme(
- createDummyIme(true, false, createDummySubtype("keyboard", false, true))))
+ createFakeIme(true, false, createFakeSubtype("keyboard", false, true))))
.isTrue();
// System IME w/ Aux and ASCII-capable "keyboard" subtype
assertThat(InputMethodAndSubtypeUtilCompat.isValidSystemNonAuxAsciiCapableIme(
- createDummyIme(true, true, createDummySubtype("keyboard", true, true))))
+ createFakeIme(true, true, createFakeSubtype("keyboard", true, true))))
.isFalse();
// System IME w/ non-Aux and ASCII-capable "voice" subtype
assertThat(InputMethodAndSubtypeUtilCompat.isValidSystemNonAuxAsciiCapableIme(
- createDummyIme(true, false, createDummySubtype("voice", false, true))))
+ createFakeIme(true, false, createFakeSubtype("voice", false, true))))
.isFalse();
// System IME w/ non-Aux and non-ASCII-capable subtype + Non-Aux and ASCII-capable subtype
assertThat(InputMethodAndSubtypeUtilCompat.isValidSystemNonAuxAsciiCapableIme(
- createDummyIme(true, false,
- createDummySubtype("keyboard", false, true),
- createDummySubtype("keyboard", false, false))))
+ createFakeIme(true, false,
+ createFakeSubtype("keyboard", false, true),
+ createFakeSubtype("keyboard", false, false))))
.isTrue();
// Non-system IME w/ non-Aux and ASCII-capable "keyboard" subtype
assertThat(InputMethodAndSubtypeUtilCompat.isValidSystemNonAuxAsciiCapableIme(
- createDummyIme(false, false, createDummySubtype("keyboard", false, true))))
+ createFakeIme(false, false, createFakeSubtype("keyboard", false, true))))
.isFalse();
}
- private static InputMethodInfo createDummyIme(boolean isSystem, boolean isAuxIme,
+ private static InputMethodInfo createFakeIme(boolean isSystem, boolean isAuxIme,
InputMethodSubtype... subtypes) {
final ResolveInfo ri = new ResolveInfo();
final ServiceInfo si = new ServiceInfo();
final ApplicationInfo ai = new ApplicationInfo();
- ai.packageName = "com.example.android.dummyime";
+ ai.packageName = "com.example.android.fakeime";
ai.enabled = true;
ai.flags |= (isSystem ? ApplicationInfo.FLAG_SYSTEM : 0);
si.applicationInfo = ai;
si.enabled = true;
- si.packageName = "com.example.android.dummyime";
- si.name = "Dummy IME";
+ si.packageName = "com.example.android.fakeime";
+ si.name = "Fake IME";
si.exported = true;
- si.nonLocalizedLabel = "Dummy IME";
+ si.nonLocalizedLabel = "Fake IME";
ri.serviceInfo = si;
return new InputMethodInfo(ri, isAuxIme, "", Arrays.asList(subtypes), 1, false);
}
- private static InputMethodSubtype createDummySubtype(
+ private static InputMethodSubtype createFakeSubtype(
String mode, boolean isAuxiliary, boolean isAsciiCapable) {
return new InputMethodSubtypeBuilder()
.setSubtypeNameResId(0)
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/inputmethod/InputMethodAndSubtypeUtilTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/inputmethod/InputMethodAndSubtypeUtilTest.java
index 5171dda9bff7..97d87051402e 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/inputmethod/InputMethodAndSubtypeUtilTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/inputmethod/InputMethodAndSubtypeUtilTest.java
@@ -195,55 +195,55 @@ public class InputMethodAndSubtypeUtilTest {
public void isValidNonAuxAsciiCapableIme() {
// IME w/ no subtype
assertThat(InputMethodAndSubtypeUtil.isValidNonAuxAsciiCapableIme(
- createDummyIme(false)))
+ createFakeIme(false)))
.isFalse();
// IME w/ non-Aux and non-ASCII-capable "keyboard" subtype
assertThat(InputMethodAndSubtypeUtil.isValidNonAuxAsciiCapableIme(
- createDummyIme(false, createDummySubtype("keyboard", false, false))))
+ createFakeIme(false, createFakeSubtype("keyboard", false, false))))
.isFalse();
// IME w/ non-Aux and ASCII-capable "keyboard" subtype
assertThat(InputMethodAndSubtypeUtil.isValidNonAuxAsciiCapableIme(
- createDummyIme(false, createDummySubtype("keyboard", false, true))))
+ createFakeIme(false, createFakeSubtype("keyboard", false, true))))
.isTrue();
// IME w/ Aux and ASCII-capable "keyboard" subtype
assertThat(InputMethodAndSubtypeUtil.isValidNonAuxAsciiCapableIme(
- createDummyIme(true, createDummySubtype("keyboard", true, true))))
+ createFakeIme(true, createFakeSubtype("keyboard", true, true))))
.isFalse();
// IME w/ non-Aux and ASCII-capable "voice" subtype
assertThat(InputMethodAndSubtypeUtil.isValidNonAuxAsciiCapableIme(
- createDummyIme(false, createDummySubtype("voice", false, true))))
+ createFakeIme(false, createFakeSubtype("voice", false, true))))
.isFalse();
// IME w/ non-Aux and non-ASCII-capable subtype + Non-Aux and ASCII-capable subtype
assertThat(InputMethodAndSubtypeUtil.isValidNonAuxAsciiCapableIme(
- createDummyIme(false,
- createDummySubtype("keyboard", false, true),
- createDummySubtype("keyboard", false, false))))
+ createFakeIme(false,
+ createFakeSubtype("keyboard", false, true),
+ createFakeSubtype("keyboard", false, false))))
.isTrue();
}
- private static InputMethodInfo createDummyIme(boolean isAuxIme,
+ private static InputMethodInfo createFakeIme(boolean isAuxIme,
InputMethodSubtype... subtypes) {
final ResolveInfo ri = new ResolveInfo();
final ServiceInfo si = new ServiceInfo();
final ApplicationInfo ai = new ApplicationInfo();
- ai.packageName = "com.example.android.dummyime";
+ ai.packageName = "com.example.android.fakeime";
ai.enabled = true;
si.applicationInfo = ai;
si.enabled = true;
- si.packageName = "com.example.android.dummyime";
- si.name = "Dummy IME";
+ si.packageName = "com.example.android.fakeime";
+ si.name = "Fake IME";
si.exported = true;
- si.nonLocalizedLabel = "Dummy IME";
+ si.nonLocalizedLabel = "Fake IME";
ri.serviceInfo = si;
return new InputMethodInfo(ri, isAuxIme, "", Arrays.asList(subtypes), 1, false);
}
- private static InputMethodSubtype createDummySubtype(
+ private static InputMethodSubtype createFakeSubtype(
String mode, boolean isAuxiliary, boolean isAsciiCapable) {
return new InputMethodSubtypeBuilder()
.setSubtypeNameResId(0)
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
index c1543fd91060..bfd5b1ccbc25 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
@@ -81,6 +81,7 @@ public class SettingsHelper {
sBroadcastOnRestore.add(Settings.Secure.DARK_THEME_CUSTOM_START_TIME);
sBroadcastOnRestore.add(Settings.Secure.DARK_THEME_CUSTOM_END_TIME);
sBroadcastOnRestore.add(Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED);
+ sBroadcastOnRestore.add(Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS);
}
private interface SettingsLookup {
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index aa960875ec6f..319b44ce216f 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -320,19 +320,6 @@
<!-- Permissions required for CTS test - AdbManagerTest -->
<uses-permission android:name="android.permission.MANAGE_DEBUGGING" />
- <!-- Permissions required for ATS tests - AtsCarHostTestCases, AtsCarDeviceApp -->
- <uses-permission android:name="android.car.permission.CAR_DRIVING_STATE" />
- <!-- Permissions required for ATS tests - AtsDeviceInfo, AtsAudioDeviceTestCases -->
- <uses-permission android:name="android.car.permission.CAR_CONTROL_AUDIO_VOLUME" />
- <!-- Permissions required for ATS tests - AtsDeviceInfo -->
- <uses-permission android:name="android.car.permission.CAR_DIAGNOSTICS" />
- <!-- Permissions required for ATS tests - AtsDeviceInfo -->
- <uses-permission android:name="android.car.permission.CLEAR_CAR_DIAGNOSTICS" />
- <!-- Permissions required for ATS tests - AtsCarHostTestCases -->
- <uses-permission android:name="android.car.permission.CONTROL_APP_BLOCKING" />
- <!-- Permissions required for ATS tests - AtsCarHostTestCases -->
- <uses-permission android:name="android.car.permission.CAR_UX_RESTRICTIONS_CONFIGURATION" />
-
<application android:label="@string/app_label"
android:theme="@android:style/Theme.DeviceDefault.DayNight"
android:defaultToDeviceProtectedStorage="true"
diff --git a/packages/SimAppDialog/Android.bp b/packages/SimAppDialog/Android.bp
index 176035f73b65..1c680bb9d25e 100644
--- a/packages/SimAppDialog/Android.bp
+++ b/packages/SimAppDialog/Android.bp
@@ -7,7 +7,8 @@ android_app {
static_libs: [
"androidx.legacy_legacy-support-v4",
- "setup-wizard-lib",
+ "setupcompat",
+ "setupdesign",
],
resource_dirs: ["res"],
diff --git a/packages/SimAppDialog/AndroidManifest.xml b/packages/SimAppDialog/AndroidManifest.xml
index 873f6c5bac54..e7368f35ed5a 100644
--- a/packages/SimAppDialog/AndroidManifest.xml
+++ b/packages/SimAppDialog/AndroidManifest.xml
@@ -23,7 +23,7 @@
android:name=".InstallCarrierAppActivity"
android:exported="true"
android:permission="android.permission.NETWORK_SETTINGS"
- android:theme="@style/SuwThemeGlif.Light">
+ android:theme="@style/SudThemeGlif.Light">
</activity>
</application>
</manifest>
diff --git a/packages/SimAppDialog/res/layout/install_carrier_app_activity.xml b/packages/SimAppDialog/res/layout/install_carrier_app_activity.xml
index 12f9bb6b13ea..68113dbf5df0 100644
--- a/packages/SimAppDialog/res/layout/install_carrier_app_activity.xml
+++ b/packages/SimAppDialog/res/layout/install_carrier_app_activity.xml
@@ -14,18 +14,17 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<com.android.setupwizardlib.GlifLayout
+<com.google.android.setupdesign.GlifLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/setup_wizard_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:icon="@drawable/ic_signal_cellular_alt_rounded"
- app:suwHeaderText="@string/install_carrier_app_title"
- app:suwFooter="@layout/install_carrier_app_footer">
+ app:sucHeaderText="@string/install_carrier_app_title">
<LinearLayout
- style="@style/SuwContentFrame"
+ style="@style/SudContentFrame"
android:id="@+id/content_frame"
android:layout_width="match_parent"
android:layout_height="wrap_content"
@@ -33,12 +32,12 @@
<TextView
android:id="@+id/install_carrier_app_description"
- style="@style/SuwDescription.Glif"
+ style="@style/SudDescription.Glif"
android:text="@string/install_carrier_app_description_default"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
- <com.android.setupwizardlib.view.FillContentLayout
+ <com.google.android.setupdesign.view.FillContentLayout
android:id="@+id/illo_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
@@ -47,12 +46,12 @@
<ImageView
android:src="@drawable/illo_sim_app_dialog"
- style="@style/SuwContentIllustration"
+ style="@style/SudContentIllustration"
android:contentDescription="@string/install_carrier_app_image_content_description"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
- </com.android.setupwizardlib.view.FillContentLayout>
-</LinearLayout>
+ </com.google.android.setupdesign.view.FillContentLayout>
+ </LinearLayout>
-</com.android.setupwizardlib.GlifLayout>
+</com.google.android.setupdesign.GlifLayout>
diff --git a/packages/SimAppDialog/res/layout/install_carrier_app_footer.xml b/packages/SimAppDialog/res/layout/install_carrier_app_footer.xml
deleted file mode 100644
index 10dcb77a6584..000000000000
--- a/packages/SimAppDialog/res/layout/install_carrier_app_footer.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2018 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<com.android.setupwizardlib.view.ButtonBarLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/footer"
- style="@style/SuwGlifButtonBar.Stackable"
- android:layout_width="match_parent"
- android:layout_height="wrap_content">
-
- <Button
- android:id="@+id/skip_button"
- style="@style/SuwGlifButton.Secondary"
- android:text="@string/install_carrier_app_defer_action"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"/>
-
- <Space
- android:layout_width="0dp"
- android:layout_height="0dp"
- android:layout_weight="1"/>
-
- <Button
- android:id="@+id/download_button"
- style="@style/SuwGlifButton.Primary"
- android:text="@string/install_carrier_app_download_action"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"/>
-</com.android.setupwizardlib.view.ButtonBarLayout>
diff --git a/packages/SimAppDialog/res/values/styles.xml b/packages/SimAppDialog/res/values/styles.xml
new file mode 100644
index 000000000000..824e3802aca1
--- /dev/null
+++ b/packages/SimAppDialog/res/values/styles.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<resources>
+
+ <style name="SetupWizardPartnerResource">
+ <!-- Disable to use partner overlay theme for outside setupwizard flow. -->
+ <item name="sucUsePartnerResource">false</item>
+ <!-- Enable heavy theme style inside setupwizard flow. -->
+ <item name="sudUsePartnerHeavyTheme">true</item>
+ </style>
+
+</resources>
diff --git a/packages/SimAppDialog/src/com/android/simappdialog/InstallCarrierAppActivity.java b/packages/SimAppDialog/src/com/android/simappdialog/InstallCarrierAppActivity.java
index abe82a885a94..0b6f9bb4f9e0 100644
--- a/packages/SimAppDialog/src/com/android/simappdialog/InstallCarrierAppActivity.java
+++ b/packages/SimAppDialog/src/com/android/simappdialog/InstallCarrierAppActivity.java
@@ -17,14 +17,17 @@ package com.android.simappdialog;
import android.app.Activity;
import android.content.Intent;
+import android.content.res.Resources;
import android.os.Bundle;
import android.sysprop.SetupWizardProperties;
import android.text.TextUtils;
import android.view.View;
-import android.widget.Button;
import android.widget.TextView;
-import com.android.setupwizardlib.util.WizardManagerHelper;
+import com.google.android.setupcompat.template.FooterBarMixin;
+import com.google.android.setupcompat.template.FooterButton;
+import com.google.android.setupdesign.GlifLayout;
+import com.google.android.setupdesign.util.ThemeResolver;
/**
* Activity that gives a user the choice to download the SIM app or defer until a later time
@@ -35,7 +38,7 @@ import com.android.setupwizardlib.util.WizardManagerHelper;
* Can display the carrier app name if its passed into the intent with key
* {@link #BUNDLE_KEY_CARRIER_NAME}
*/
-public class InstallCarrierAppActivity extends Activity implements View.OnClickListener {
+public class InstallCarrierAppActivity extends Activity {
/**
* Key for the carrier app name that will be displayed as the app to download. If unset, a
* default description will be used
@@ -50,20 +53,33 @@ public class InstallCarrierAppActivity extends Activity implements View.OnClickL
protected void onCreate(Bundle icicle) {
// Setup theme for aosp/pixel
setTheme(
- WizardManagerHelper.getThemeRes(
- SetupWizardProperties.theme().orElse(""),
- R.style.SuwThemeGlif_Light
- )
- );
+ new ThemeResolver.Builder()
+ .setDefaultTheme(R.style.SudThemeGlifV3_Light)
+ .build()
+ .resolve(SetupWizardProperties.theme().orElse(""),
+ /* suppressDayNight= */ false));
super.onCreate(icicle);
setContentView(R.layout.install_carrier_app_activity);
- Button notNowButton = findViewById(R.id.skip_button);
- notNowButton.setOnClickListener(this);
+ GlifLayout layout = findViewById(R.id.setup_wizard_layout);
+ FooterBarMixin mixin = layout.getMixin(FooterBarMixin.class);
+ mixin.setSecondaryButton(
+ new FooterButton.Builder(this)
+ .setText(R.string.install_carrier_app_defer_action)
+ .setListener(this::onSkipButtonClick)
+ .setButtonType(FooterButton.ButtonType.SKIP)
+ .setTheme(R.style.SudGlifButton_Secondary)
+ .build());
+
+ mixin.setPrimaryButton(
+ new FooterButton.Builder(this)
+ .setText(R.string.install_carrier_app_download_action)
+ .setListener(this::onDownloadButtonClick)
+ .setButtonType(FooterButton.ButtonType.OTHER)
+ .setTheme(R.style.SudGlifButton_Primary)
+ .build());
- Button downloadButton = findViewById(R.id.download_button);
- downloadButton.setOnClickListener(this);
// Show/hide illo depending on whether one was provided in a resource overlay
boolean showIllo = getResources().getBoolean(R.bool.show_sim_app_dialog_illo);
@@ -82,15 +98,17 @@ public class InstallCarrierAppActivity extends Activity implements View.OnClickL
}
@Override
- public void onClick(View v) {
- switch (v.getId()) {
- case R.id.skip_button:
- finish(DEFER_RESULT);
- break;
- case R.id.download_button:
- finish(DOWNLOAD_RESULT);
- break;
- }
+ protected void onApplyThemeResource(Resources.Theme theme, int resid, boolean first) {
+ theme.applyStyle(R.style.SetupWizardPartnerResource, true);
+ super.onApplyThemeResource(theme, resid, first);
+ }
+
+ protected void onSkipButtonClick(View view) {
+ finish(DEFER_RESULT);
+ }
+
+ protected void onDownloadButtonClick(View view) {
+ finish(DOWNLOAD_RESULT);
}
private void finish(int resultCode) {
diff --git a/packages/SystemUI/res/layout/media_view.xml b/packages/SystemUI/res/layout/media_view.xml
index 3c641afea0d6..ed870f8bb2ef 100644
--- a/packages/SystemUI/res/layout/media_view.xml
+++ b/packages/SystemUI/res/layout/media_view.xml
@@ -210,8 +210,98 @@
android:layout_width="@dimen/qs_media_icon_size"
android:layout_height="@dimen/qs_media_icon_size" />
- <!-- Buttons to remove this view when no longer needed -->
- <include
- layout="@layout/qs_media_panel_options"
- android:visibility="gone" />
+ <!-- Constraints are set here as they are the same regardless of host -->
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/qs_media_panel_outer_padding"
+ android:layout_marginStart="@dimen/qs_media_panel_outer_padding"
+ android:layout_marginEnd="@dimen/qs_media_panel_outer_padding"
+ android:id="@+id/media_text"
+ android:fontFamily="@*android:string/config_headlineFontFamilyMedium"
+ android:textColor="@color/media_primary_text"
+ android:text="@string/controls_media_title"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintBottom_toTopOf="@id/remove_text"
+ app:layout_constraintVertical_chainStyle="spread_inside"/>
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/qs_media_panel_outer_padding"
+ android:layout_marginEnd="@dimen/qs_media_panel_outer_padding"
+ android:id="@+id/remove_text"
+ android:fontFamily="@*android:string/config_headlineFontFamily"
+ android:singleLine="true"
+ android:textColor="@color/media_primary_text"
+ android:text="@string/controls_media_close_session"
+ app:layout_constraintTop_toBottomOf="@id/media_text"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintBottom_toTopOf="@id/settings"/>
+
+ <FrameLayout
+ android:id="@+id/settings"
+ android:background="@drawable/qs_media_light_source"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/qs_media_panel_outer_padding"
+ android:paddingBottom="@dimen/qs_media_panel_outer_padding"
+ android:minWidth="48dp"
+ android:minHeight="48dp"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/remove_text">
+
+ <TextView
+ android:layout_gravity="bottom"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:fontFamily="@*android:string/config_headlineFontFamilyMedium"
+ android:textColor="@android:color/white"
+ android:text="@string/controls_media_settings_button" />
+ </FrameLayout>
+
+ <FrameLayout
+ android:id="@+id/cancel"
+ android:background="@drawable/qs_media_light_source"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginEnd="@dimen/qs_media_panel_outer_padding"
+ android:paddingBottom="@dimen/qs_media_panel_outer_padding"
+ android:minWidth="48dp"
+ android:minHeight="48dp"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toStartOf="@id/dismiss" >
+
+ <TextView
+ android:layout_gravity="bottom"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:fontFamily="@*android:string/config_headlineFontFamilyMedium"
+ android:textColor="@android:color/white"
+ android:text="@string/cancel" />
+ </FrameLayout>
+
+ <FrameLayout
+ android:id="@+id/dismiss"
+ android:background="@drawable/qs_media_light_source"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginEnd="@dimen/qs_media_panel_outer_padding"
+ android:paddingBottom="@dimen/qs_media_panel_outer_padding"
+ android:minWidth="48dp"
+ android:minHeight="48dp"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toEndOf="parent">
+
+ <TextView
+ android:layout_gravity="bottom"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:fontFamily="@*android:string/config_headlineFontFamilyMedium"
+ android:textColor="@android:color/white"
+ android:text="@string/controls_media_dismiss_button"
+ />
+ </FrameLayout>
</com.android.systemui.util.animation.TransitionLayout>
diff --git a/packages/SystemUI/res/layout/qs_media_panel_options.xml b/packages/SystemUI/res/layout/qs_media_panel_options.xml
deleted file mode 100644
index e72c0e85fb26..000000000000
--- a/packages/SystemUI/res/layout/qs_media_panel_options.xml
+++ /dev/null
@@ -1,61 +0,0 @@
-<?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
- -->
-<LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/qs_media_controls_options"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:gravity="center"
- android:padding="16dp"
- android:orientation="vertical">
- <LinearLayout
- android:layout_width="wrap_content"
- android:layout_height="48dp"
- android:layout_weight="1"
- android:minWidth="48dp"
- android:layout_gravity="start|bottom"
- android:gravity="bottom"
- android:id="@+id/remove"
- android:orientation="horizontal">
- <ImageView
- android:layout_width="18dp"
- android:layout_height="18dp"
- android:id="@+id/remove_icon"
- android:layout_marginEnd="16dp"
- android:tint="@color/media_primary_text"
- android:src="@drawable/ic_clear"/>
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:id="@+id/remove_text"
- android:fontFamily="@*android:string/config_headlineFontFamilyMedium"
- android:singleLine="true"
- android:textColor="@color/media_primary_text"
- android:text="@string/controls_media_close_session" />
- </LinearLayout>
- <TextView
- android:id="@+id/cancel"
- android:layout_width="wrap_content"
- android:layout_height="48dp"
- android:layout_weight="1"
- android:minWidth="48dp"
- android:layout_gravity="end|bottom"
- android:gravity="bottom"
- android:fontFamily="@*android:string/config_headlineFontFamilyMedium"
- android:textColor="@android:color/white"
- android:text="@string/cancel" />
-</LinearLayout>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index fa620df12b87..fba43a628387 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -515,13 +515,11 @@
<!-- Whether or not to add a "people" notifications section -->
<bool name="config_usePeopleFiltering">false</bool>
- <!-- Defines the blacklist for system icons. That is to say, the icons in the status bar that
- are part of the blacklist are never displayed. Each item in the blacklist must be a string
- defined in core/res/res/config.xml to properly blacklist the icon.
-
- TODO: See if we can rename this config variable.
+ <!-- Defines system icons to be excluded from the display. That is to say, the icons in the
+ status bar that are part of this list are never displayed. Each item in the list must be a
+ string defined in core/res/res/config.xml to properly exclude the icon.
-->
- <string-array name="config_statusBarIconBlackList" translatable="false">
+ <string-array name="config_statusBarIconsToExclude" translatable="false">
<item>@*android:string/status_bar_rotate</item>
<item>@*android:string/status_bar_headset</item>
</string-array>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 77d3f4513957..823c1ff2fdd0 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -2799,7 +2799,7 @@
<!-- Explanation for closing controls associated with a specific media session [CHAR_LIMIT=NONE] -->
<string name="controls_media_close_session">Hide the current session.</string>
<!-- Label for a button that will hide media controls [CHAR_LIMIT=30] -->
- <string name="controls_media_dismiss_button">Hide</string>
+ <string name="controls_media_dismiss_button">Dismiss</string>
<!-- Label for button to resume media playback [CHAR_LIMIT=NONE] -->
<string name="controls_media_resume">Resume</string>
<!-- Label for button to go to media control settings screen [CHAR_LIMIT=30] -->
diff --git a/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java b/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java
index 4df66602bb7e..6512624f5064 100644
--- a/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java
@@ -281,9 +281,11 @@ public class AppOpsControllerImpl implements AppOpsController,
* @return {@code true} iff the app-op for should be shown to the user
*/
private boolean isUserVisible(int appOpCode, int uid, String packageName) {
- // currently OP_SYSTEM_ALERT_WINDOW does not correspond to a platform permission
- // which may be user senstive, so for now always show it to the user.
- if (appOpCode == AppOpsManager.OP_SYSTEM_ALERT_WINDOW) {
+ // currently OP_SYSTEM_ALERT_WINDOW and OP_MONITOR_HIGH_POWER_LOCATION
+ // does not correspond to a platform permission
+ // which may be user sensitive, so for now always show it to the user.
+ if (appOpCode == AppOpsManager.OP_SYSTEM_ALERT_WINDOW
+ || appOpCode == AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION) {
return true;
}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
index bb572191fe3c..c5639ea6fcde 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
@@ -84,6 +84,7 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.statusbar.NotificationVisibility;
import com.android.systemui.Dumpable;
+import com.android.systemui.bubbles.animation.StackAnimationController;
import com.android.systemui.bubbles.dagger.BubbleModule;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.model.SysUiState;
@@ -173,6 +174,12 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
@Nullable private BubbleStackView mStackView;
private BubbleIconFactory mBubbleIconFactory;
+ /**
+ * The relative position of the stack when we removed it and nulled it out. If the stack is
+ * re-created, it will re-appear at this position.
+ */
+ @Nullable private BubbleStackView.RelativeStackPosition mPositionFromRemovedStack;
+
// Tracks the id of the current (foreground) user.
private int mCurrentUserId;
// Saves notification keys of active bubbles when users are switched.
@@ -736,6 +743,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
mContext, mBubbleData, mSurfaceSynchronizer, mFloatingContentCoordinator,
mSysUiState, this::onAllBubblesAnimatedOut, this::onImeVisibilityChanged,
this::hideCurrentInputMethod);
+ mStackView.setStackStartPosition(mPositionFromRemovedStack);
mStackView.addView(mBubbleScrim);
if (mExpandListener != null) {
mStackView.setExpandListener(mExpandListener);
@@ -806,6 +814,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
try {
mAddedToWindowManager = false;
if (mStackView != null) {
+ mPositionFromRemovedStack = mStackView.getRelativeStackPosition();
mWindowManager.removeView(mStackView);
mStackView.removeView(mBubbleScrim);
mStackView = null;
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
index d0f61817d1cc..fa0d2ba84b4e 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
@@ -310,7 +310,6 @@ public class BubbleExpandedView extends LinearLayout {
// Set ActivityView's alpha value as zero, since there is no view content to be shown.
setContentVisibility(false);
- mActivityViewContainer.setBackgroundColor(Color.WHITE);
mActivityViewContainer.setOutlineProvider(new ViewOutlineProvider() {
@Override
public void getOutline(View view, Outline outline) {
@@ -439,9 +438,11 @@ public class BubbleExpandedView extends LinearLayout {
}
void applyThemeAttrs() {
- final TypedArray ta = mContext.obtainStyledAttributes(
- new int[] {android.R.attr.dialogCornerRadius});
+ final TypedArray ta = mContext.obtainStyledAttributes(new int[] {
+ android.R.attr.dialogCornerRadius,
+ android.R.attr.colorBackgroundFloating});
mCornerRadius = ta.getDimensionPixelSize(0, 0);
+ mActivityViewContainer.setBackgroundColor(ta.getColor(1, Color.WHITE));
ta.recycle();
if (mActivityView != null && ScreenDecorationsUtils.supportsRoundedCornersOnWindows(
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
index b3fbfd6a0f30..ec9644af7013 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
@@ -253,13 +253,8 @@ public class BubbleStackView extends FrameLayout
/** Layout change listener that moves the stack to the nearest valid position on rotation. */
private OnLayoutChangeListener mOrientationChangedListener;
- /** Whether the stack was on the left side of the screen prior to rotation. */
- private boolean mWasOnLeftBeforeRotation = false;
- /**
- * How far down the screen the stack was before rotation, in terms of percentage of the way down
- * the allowable region. Defaults to -1 if not set.
- */
- private float mVerticalPosPercentBeforeRotation = -1;
+
+ @Nullable private RelativeStackPosition mRelativeStackPositionBeforeRotation;
private int mMaxBubbles;
private int mBubbleSize;
@@ -940,9 +935,10 @@ public class BubbleStackView extends FrameLayout
mExpandedViewContainer.setTranslationY(getExpandedViewY());
mExpandedViewContainer.setAlpha(1f);
}
- if (mVerticalPosPercentBeforeRotation >= 0) {
- mStackAnimationController.moveStackToSimilarPositionAfterRotation(
- mWasOnLeftBeforeRotation, mVerticalPosPercentBeforeRotation);
+ if (mRelativeStackPositionBeforeRotation != null) {
+ mStackAnimationController.setStackPosition(
+ mRelativeStackPositionBeforeRotation);
+ mRelativeStackPositionBeforeRotation = null;
}
removeOnLayoutChangeListener(mOrientationChangedListener);
};
@@ -1189,13 +1185,7 @@ public class BubbleStackView extends FrameLayout
com.android.internal.R.dimen.status_bar_height);
mBubblePaddingTop = res.getDimensionPixelSize(R.dimen.bubble_padding_top);
- final RectF allowablePos = mStackAnimationController.getAllowableStackPositionRegion();
- mWasOnLeftBeforeRotation = mStackAnimationController.isStackOnLeftSide();
- mVerticalPosPercentBeforeRotation =
- (mStackAnimationController.getStackPosition().y - allowablePos.top)
- / (allowablePos.bottom - allowablePos.top);
- mVerticalPosPercentBeforeRotation =
- Math.max(0f, Math.min(1f, mVerticalPosPercentBeforeRotation));
+ mRelativeStackPositionBeforeRotation = mStackAnimationController.getRelativeStackPosition();
addOnLayoutChangeListener(mOrientationChangedListener);
hideFlyoutImmediate();
@@ -1459,7 +1449,7 @@ public class BubbleStackView extends FrameLayout
if (getBubbleCount() == 0 && mShouldShowUserEducation) {
// Override the default stack position if we're showing user education.
mStackAnimationController.setStackPosition(
- mStackAnimationController.getDefaultStartPosition());
+ mStackAnimationController.getStartPosition());
}
if (getBubbleCount() == 0) {
@@ -1674,7 +1664,7 @@ public class BubbleStackView extends FrameLayout
// Post so we have height of mUserEducationView
mUserEducationView.post(() -> {
final int viewHeight = mUserEducationView.getHeight();
- PointF stackPosition = mStackAnimationController.getDefaultStartPosition();
+ PointF stackPosition = mStackAnimationController.getStartPosition();
final float translationY = stackPosition.y + (mBubbleSize / 2) - (viewHeight / 2);
mUserEducationView.setTranslationY(translationY);
mUserEducationView.animate()
@@ -2740,10 +2730,18 @@ public class BubbleStackView extends FrameLayout
.floatValue();
}
+ public void setStackStartPosition(RelativeStackPosition position) {
+ mStackAnimationController.setStackStartPosition(position);
+ }
+
public PointF getStackPosition() {
return mStackAnimationController.getStackPosition();
}
+ public RelativeStackPosition getRelativeStackPosition() {
+ return mStackAnimationController.getRelativeStackPosition();
+ }
+
/**
* Logs the bubble UI event.
*
@@ -2797,4 +2795,47 @@ public class BubbleStackView extends FrameLayout
}
return bubbles;
}
+
+ /**
+ * Representation of stack position that uses relative properties rather than absolute
+ * coordinates. This is used to maintain similar stack positions across configuration changes.
+ */
+ public static class RelativeStackPosition {
+ /** Whether to place the stack at the leftmost allowed position. */
+ private boolean mOnLeft;
+
+ /**
+ * How far down the vertically allowed region to place the stack. For example, if the stack
+ * allowed region is between y = 100 and y = 1100 and this is 0.2f, we'll place the stack at
+ * 100 + (0.2f * 1000) = 300.
+ */
+ private float mVerticalOffsetPercent;
+
+ public RelativeStackPosition(boolean onLeft, float verticalOffsetPercent) {
+ mOnLeft = onLeft;
+ mVerticalOffsetPercent = clampVerticalOffsetPercent(verticalOffsetPercent);
+ }
+
+ /** Constructs a relative position given a region and a point in that region. */
+ public RelativeStackPosition(PointF position, RectF region) {
+ mOnLeft = position.x < region.width() / 2;
+ mVerticalOffsetPercent =
+ clampVerticalOffsetPercent((position.y - region.top) / region.height());
+ }
+
+ /** Ensures that the offset percent is between 0f and 1f. */
+ private float clampVerticalOffsetPercent(float offsetPercent) {
+ return Math.max(0f, Math.min(1f, offsetPercent));
+ }
+
+ /**
+ * Given an allowable stack position region, returns the point within that region
+ * represented by this relative position.
+ */
+ public PointF getAbsolutePositionInRegion(RectF region) {
+ return new PointF(
+ mOnLeft ? region.left : region.right,
+ region.top + mVerticalOffsetPercent * region.height());
+ }
+ }
}
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 b378469c4c98..e835ea206e59 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java
@@ -35,6 +35,7 @@ import androidx.dynamicanimation.animation.SpringAnimation;
import androidx.dynamicanimation.animation.SpringForce;
import com.android.systemui.R;
+import com.android.systemui.bubbles.BubbleStackView;
import com.android.systemui.util.FloatingContentCoordinator;
import com.android.systemui.util.animation.PhysicsAnimator;
import com.android.systemui.util.magnetictarget.MagnetizedObject;
@@ -125,6 +126,9 @@ public class StackAnimationController extends
*/
private Rect mAnimatingToBounds = new Rect();
+ /** Initial starting location for the stack. */
+ @Nullable private BubbleStackView.RelativeStackPosition mStackStartPosition;
+
/** Whether or not the stack's start position has been set. */
private boolean mStackMovedToStartPosition = false;
@@ -431,21 +435,6 @@ public class StackAnimationController extends
return stackPos;
}
- /**
- * Moves the stack in response to rotation. We keep it in the most similar position by keeping
- * it on the same side, and positioning it the same percentage of the way down the screen
- * (taking status bar/nav bar into account by using the allowable region's height).
- */
- public void moveStackToSimilarPositionAfterRotation(boolean wasOnLeft, float verticalPercent) {
- final RectF allowablePos = getAllowableStackPositionRegion();
- final float allowableRegionHeight = allowablePos.bottom - allowablePos.top;
-
- final float x = wasOnLeft ? allowablePos.left : allowablePos.right;
- final float y = (allowableRegionHeight * verticalPercent) + allowablePos.top;
-
- setStackPosition(new PointF(x, y));
- }
-
/** Description of current animation controller state. */
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
pw.println("StackAnimationController state:");
@@ -815,7 +804,7 @@ public class StackAnimationController extends
} else {
// When all children are removed ensure stack position is sane
setStackPosition(mRestingStackPosition == null
- ? getDefaultStartPosition()
+ ? getStartPosition()
: mRestingStackPosition);
// Remove the stack from the coordinator since we don't have any bubbles and aren't
@@ -868,7 +857,7 @@ public class StackAnimationController extends
mLayout.setVisibility(View.INVISIBLE);
mLayout.post(() -> {
setStackPosition(mRestingStackPosition == null
- ? getDefaultStartPosition()
+ ? getStartPosition()
: mRestingStackPosition);
mStackMovedToStartPosition = true;
mLayout.setVisibility(View.VISIBLE);
@@ -938,15 +927,47 @@ public class StackAnimationController extends
}
}
- /** Returns the default stack position, which is on the top left. */
- public PointF getDefaultStartPosition() {
- boolean isRtl = mLayout != null
- && mLayout.getResources().getConfiguration().getLayoutDirection()
- == View.LAYOUT_DIRECTION_RTL;
- return new PointF(isRtl
- ? getAllowableStackPositionRegion().right
- : getAllowableStackPositionRegion().left,
- getAllowableStackPositionRegion().top + mStackStartingVerticalOffset);
+ public void setStackPosition(BubbleStackView.RelativeStackPosition position) {
+ setStackPosition(position.getAbsolutePositionInRegion(getAllowableStackPositionRegion()));
+ }
+
+ public BubbleStackView.RelativeStackPosition getRelativeStackPosition() {
+ return new BubbleStackView.RelativeStackPosition(
+ mStackPosition, getAllowableStackPositionRegion());
+ }
+
+ /**
+ * Sets the starting position for the stack, where it will be located when the first bubble is
+ * added.
+ */
+ public void setStackStartPosition(BubbleStackView.RelativeStackPosition position) {
+ mStackStartPosition = position;
+ }
+
+ /**
+ * Returns the starting stack position. If {@link #setStackStartPosition} was called, this will
+ * return that position - otherwise, a reasonable default will be returned.
+ */
+ @Nullable public PointF getStartPosition() {
+ if (mLayout == null) {
+ return null;
+ }
+
+ if (mStackStartPosition == null) {
+ // Start on the left if we're in LTR, right otherwise.
+ final boolean startOnLeft =
+ mLayout.getResources().getConfiguration().getLayoutDirection()
+ != View.LAYOUT_DIRECTION_RTL;
+
+ final float startingVerticalOffset = mLayout.getResources().getDimensionPixelOffset(
+ R.dimen.bubble_stack_starting_offset_y);
+
+ mStackStartPosition = new BubbleStackView.RelativeStackPosition(
+ startOnLeft,
+ startingVerticalOffset / getAllowableStackPositionRegion().height());
+ }
+
+ return mStackStartPosition.getAbsolutePositionInRegion(getAllowableStackPositionRegion());
}
private boolean isStackPositionSet() {
diff --git a/packages/SystemUI/src/com/android/systemui/controls/CustomIconCache.kt b/packages/SystemUI/src/com/android/systemui/controls/CustomIconCache.kt
new file mode 100644
index 000000000000..cca0f1653757
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/controls/CustomIconCache.kt
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.controls
+
+import android.content.ComponentName
+import android.graphics.drawable.Icon
+import androidx.annotation.GuardedBy
+import javax.inject.Inject
+import javax.inject.Singleton
+
+/**
+ * Icon cache for custom icons sent with controls.
+ *
+ * It assumes that only one component can be current at the time, to minimize the number of icons
+ * stored at a given time.
+ */
+@Singleton
+class CustomIconCache @Inject constructor() {
+
+ private var currentComponent: ComponentName? = null
+ @GuardedBy("cache")
+ private val cache: MutableMap<String, Icon> = LinkedHashMap()
+
+ /**
+ * Store an icon in the cache.
+ *
+ * If the icons currently stored do not correspond to the component to be stored, the cache is
+ * cleared first.
+ */
+ fun store(component: ComponentName, controlId: String, icon: Icon?) {
+ if (component != currentComponent) {
+ clear()
+ currentComponent = component
+ }
+ synchronized(cache) {
+ if (icon != null) {
+ cache.put(controlId, icon)
+ } else {
+ cache.remove(controlId)
+ }
+ }
+ }
+
+ /**
+ * Retrieves a custom icon stored in the cache.
+ *
+ * It will return null if the component requested is not the one whose icons are stored, or if
+ * there is no icon cached for that id.
+ */
+ fun retrieve(component: ComponentName, controlId: String): Icon? {
+ if (component != currentComponent) return null
+ return synchronized(cache) {
+ cache.get(controlId)
+ }
+ }
+
+ private fun clear() {
+ synchronized(cache) {
+ cache.clear()
+ }
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsEditingActivity.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsEditingActivity.kt
index ff40a8a883ae..f68388d5db3f 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsEditingActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsEditingActivity.kt
@@ -29,6 +29,7 @@ import androidx.recyclerview.widget.ItemTouchHelper
import androidx.recyclerview.widget.RecyclerView
import com.android.systemui.R
import com.android.systemui.broadcast.BroadcastDispatcher
+import com.android.systemui.controls.CustomIconCache
import com.android.systemui.controls.controller.ControlsControllerImpl
import com.android.systemui.controls.controller.StructureInfo
import com.android.systemui.globalactions.GlobalActionsComponent
@@ -42,7 +43,8 @@ import javax.inject.Inject
class ControlsEditingActivity @Inject constructor(
private val controller: ControlsControllerImpl,
broadcastDispatcher: BroadcastDispatcher,
- private val globalActionsComponent: GlobalActionsComponent
+ private val globalActionsComponent: GlobalActionsComponent,
+ private val customIconCache: CustomIconCache
) : LifecycleActivity() {
companion object {
@@ -170,7 +172,7 @@ class ControlsEditingActivity @Inject constructor(
private fun setUpList() {
val controls = controller.getFavoritesForStructure(component, structure)
- model = FavoritesModel(component, controls, favoritesModelCallback)
+ model = FavoritesModel(customIconCache, component, controls, favoritesModelCallback)
val elevation = resources.getFloat(R.dimen.control_card_elevation)
val recyclerView = requireViewById<RecyclerView>(R.id.list)
recyclerView.alpha = 0.0f
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsModel.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsModel.kt
index 4ef64a5cddbf..ad0e7a541f98 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsModel.kt
@@ -114,11 +114,27 @@ data class ControlStatusWrapper(
val controlStatus: ControlStatus
) : ElementWrapper(), ControlInterface by controlStatus
+private fun nullIconGetter(_a: ComponentName, _b: String): Icon? = null
+
data class ControlInfoWrapper(
override val component: ComponentName,
val controlInfo: ControlInfo,
override var favorite: Boolean
) : ElementWrapper(), ControlInterface {
+
+ var customIconGetter: (ComponentName, String) -> Icon? = ::nullIconGetter
+ private set
+
+ // Separate constructor so the getter is not used in auto-generated methods
+ constructor(
+ component: ComponentName,
+ controlInfo: ControlInfo,
+ favorite: Boolean,
+ customIconGetter: (ComponentName, String) -> Icon?
+ ): this(component, controlInfo, favorite) {
+ this.customIconGetter = customIconGetter
+ }
+
override val controlId: String
get() = controlInfo.controlId
override val title: CharSequence
@@ -128,8 +144,7 @@ data class ControlInfoWrapper(
override val deviceType: Int
get() = controlInfo.deviceType
override val customIcon: Icon?
- // Will need to address to support for edit activity
- get() = null
+ get() = customIconGetter(component, controlId)
}
data class DividerWrapper(
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/FavoritesModel.kt b/packages/SystemUI/src/com/android/systemui/controls/management/FavoritesModel.kt
index 524250134e9b..f9ce6362f4f8 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/FavoritesModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/FavoritesModel.kt
@@ -21,6 +21,7 @@ import android.util.Log
import androidx.recyclerview.widget.ItemTouchHelper
import androidx.recyclerview.widget.RecyclerView
import com.android.systemui.controls.ControlInterface
+import com.android.systemui.controls.CustomIconCache
import com.android.systemui.controls.controller.ControlInfo
import java.util.Collections
@@ -35,6 +36,7 @@ import java.util.Collections
* @property favoritesModelCallback callback to notify on first change and empty favorites
*/
class FavoritesModel(
+ private val customIconCache: CustomIconCache,
private val componentName: ComponentName,
favorites: List<ControlInfo>,
private val favoritesModelCallback: FavoritesModelCallback
@@ -83,7 +85,7 @@ class FavoritesModel(
}
override val elements: List<ElementWrapper> = favorites.map {
- ControlInfoWrapper(componentName, it, true)
+ ControlInfoWrapper(componentName, it, true, customIconCache::retrieve)
} + DividerWrapper()
/**
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt
index 22d6b6bb75c3..e15380b42a78 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt
@@ -92,7 +92,7 @@ class ControlActionCoordinatorImpl @Inject constructor(
override fun setValue(cvh: ControlViewHolder, templateId: String, newValue: Float) {
bouncerOrRun(Action(cvh.cws.ci.controlId, {
cvh.action(FloatAction(templateId, newValue))
- }, true /* blockable */))
+ }, false /* blockable */))
}
override fun longPress(cvh: ControlViewHolder) {
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
index 1eb7e2168a6a..5f75c96be128 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
@@ -44,6 +44,7 @@ import android.widget.Space
import android.widget.TextView
import com.android.systemui.R
import com.android.systemui.controls.ControlsServiceInfo
+import com.android.systemui.controls.CustomIconCache
import com.android.systemui.controls.controller.ControlInfo
import com.android.systemui.controls.controller.ControlsController
import com.android.systemui.controls.controller.StructureInfo
@@ -75,7 +76,8 @@ class ControlsUiControllerImpl @Inject constructor (
@Main val sharedPreferences: SharedPreferences,
val controlActionCoordinator: ControlActionCoordinator,
private val activityStarter: ActivityStarter,
- private val shadeController: ShadeController
+ private val shadeController: ShadeController,
+ private val iconCache: CustomIconCache
) : ControlsUiController {
companion object {
@@ -502,6 +504,7 @@ class ControlsUiControllerImpl @Inject constructor (
controls.forEach { c ->
controlsById.get(ControlKey(componentName, c.getControlId()))?.let {
Log.d(ControlsUiController.TAG, "onRefreshState() for id: " + c.getControlId())
+ iconCache.store(componentName, c.controlId, c.customIcon)
val cws = ControlWithState(componentName, it.ci, c)
val key = ControlKey(componentName, c.getControlId())
controlsById.put(key, cws)
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
index de5316885b94..7f610d1a8467 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
@@ -3,7 +3,6 @@ package com.android.systemui.media
import android.content.Context
import android.content.Intent
import android.content.res.Configuration
-import android.graphics.Color
import android.provider.Settings.ACTION_MEDIA_CONTROLS_SETTINGS
import android.util.Log
import android.util.MathUtils
@@ -151,7 +150,7 @@ class MediaCarouselController @Inject constructor(
pageIndicator = mediaFrame.requireViewById(R.id.media_page_indicator)
mediaCarouselScrollHandler = MediaCarouselScrollHandler(mediaCarousel, pageIndicator,
executor, mediaManager::onSwipeToDismiss, this::updatePageIndicatorLocation,
- falsingManager)
+ this::closeGuts, falsingManager)
isRtl = context.resources.configuration.layoutDirection == View.LAYOUT_DIRECTION_RTL
inflateSettingsButton()
mediaContent = mediaCarousel.requireViewById(R.id.media_carousel)
@@ -470,6 +469,12 @@ class MediaCarouselController @Inject constructor(
}
}
+ fun closeGuts() {
+ mediaPlayers.values.forEach {
+ it.closeGuts(true)
+ }
+ }
+
/**
* Update the size of the carousel, remeasuring it if necessary.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselScrollHandler.kt b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselScrollHandler.kt
index 3096908aca21..77cac5023db3 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselScrollHandler.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselScrollHandler.kt
@@ -56,6 +56,7 @@ class MediaCarouselScrollHandler(
private val mainExecutor: DelayableExecutor,
private val dismissCallback: () -> Unit,
private var translationChangedListener: () -> Unit,
+ private val closeGuts: () -> Unit,
private val falsingManager: FalsingManager
) {
/**
@@ -452,6 +453,7 @@ class MediaCarouselScrollHandler(
val nowScrolledIn = scrollIntoCurrentMedia != 0
if (newIndex != activeMediaIndex || wasScrolledIn != nowScrolledIn) {
activeMediaIndex = newIndex
+ closeGuts()
updatePlayerVisibilities()
}
val relativeLocation = activeMediaIndex.toFloat() + if (playerWidthPlusPadding > 0)
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
index 3fc162ead6d1..e55678dc986b 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
@@ -16,6 +16,8 @@
package com.android.systemui.media;
+import static android.provider.Settings.ACTION_MEDIA_CONTROLS_SETTINGS;
+
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
@@ -45,6 +47,7 @@ import com.android.settingslib.widget.AdaptiveIcon;
import com.android.systemui.R;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.statusbar.phone.KeyguardDismissUtil;
import com.android.systemui.util.animation.TransitionLayout;
import java.util.List;
@@ -52,6 +55,8 @@ import java.util.concurrent.Executor;
import javax.inject.Inject;
+import dagger.Lazy;
+
/**
* A view controller used for Media Playback.
*/
@@ -59,6 +64,8 @@ public class MediaControlPanel {
private static final String TAG = "MediaControlPanel";
private static final float DISABLED_ALPHA = 0.38f;
+ private static final Intent SETTINGS_INTENT = new Intent(ACTION_MEDIA_CONTROLS_SETTINGS);
+
// Button IDs for QS controls
static final int[] ACTION_IDS = {
R.id.action0,
@@ -78,6 +85,8 @@ public class MediaControlPanel {
private MediaViewController mMediaViewController;
private MediaSession.Token mToken;
private MediaController mController;
+ private KeyguardDismissUtil mKeyguardDismissUtil;
+ private Lazy<MediaDataManager> mMediaDataManagerLazy;
private int mBackgroundColor;
private int mAlbumArtSize;
private int mAlbumArtRadius;
@@ -93,12 +102,15 @@ public class MediaControlPanel {
@Inject
public MediaControlPanel(Context context, @Background Executor backgroundExecutor,
ActivityStarter activityStarter, MediaViewController mediaViewController,
- SeekBarViewModel seekBarViewModel) {
+ SeekBarViewModel seekBarViewModel, Lazy<MediaDataManager> lazyMediaDataManager,
+ KeyguardDismissUtil keyguardDismissUtil) {
mContext = context;
mBackgroundExecutor = backgroundExecutor;
mActivityStarter = activityStarter;
mSeekBarViewModel = seekBarViewModel;
mMediaViewController = mediaViewController;
+ mMediaDataManagerLazy = lazyMediaDataManager;
+ mKeyguardDismissUtil = keyguardDismissUtil;
loadDimens();
mViewOutlineProvider = new ViewOutlineProvider() {
@@ -174,6 +186,21 @@ public class MediaControlPanel {
mSeekBarViewModel.getProgress().observeForever(mSeekBarObserver);
mSeekBarViewModel.attachTouchHandlers(vh.getSeekBar());
mMediaViewController.attach(player);
+
+ mViewHolder.getPlayer().setOnLongClickListener(v -> {
+ if (!mMediaViewController.isGutsVisible()) {
+ mMediaViewController.openGuts();
+ return true;
+ } else {
+ return false;
+ }
+ });
+ mViewHolder.getCancel().setOnClickListener(v -> {
+ closeGuts();
+ });
+ mViewHolder.getSettings().setOnClickListener(v -> {
+ mActivityStarter.startActivity(SETTINGS_INTENT, true /* dismissShade */);
+ });
}
/**
@@ -205,6 +232,7 @@ public class MediaControlPanel {
PendingIntent clickIntent = data.getClickIntent();
if (clickIntent != null) {
mViewHolder.getPlayer().setOnClickListener(v -> {
+ if (mMediaViewController.isGutsVisible()) return;
mActivityStarter.postStartActivityDismissingKeyguard(clickIntent);
});
}
@@ -329,14 +357,38 @@ public class MediaControlPanel {
final MediaController controller = getController();
mBackgroundExecutor.execute(() -> mSeekBarViewModel.updateController(controller));
- // Set up long press menu
- // TODO: b/156036025 bring back media guts
+ // Dismiss
+ mViewHolder.getDismiss().setOnClickListener(v -> {
+ if (data.getNotificationKey() != null) {
+ closeGuts();
+ mKeyguardDismissUtil.executeWhenUnlocked(() -> {
+ mMediaDataManagerLazy.get().dismissMediaData(data.getNotificationKey(),
+ MediaViewController.GUTS_ANIMATION_DURATION + 100);
+ return true;
+ }, /* requiresShadeOpen */ true);
+ } else {
+ Log.w(TAG, "Dismiss media with null notification. Token uid="
+ + data.getToken().getUid());
+ }
+ });
// TODO: We don't need to refresh this state constantly, only if the state actually changed
// to something which might impact the measurement
mMediaViewController.refreshState();
}
+ /**
+ * Close the guts for this player.
+ * @param immediate {@code true} if it should be closed without animation
+ */
+ public void closeGuts(boolean immediate) {
+ mMediaViewController.closeGuts(immediate);
+ }
+
+ private void closeGuts() {
+ closeGuts(false);
+ }
+
@UiThread
private Drawable scaleDrawable(Icon icon) {
if (icon == null) {
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
index d82150f2346b..8a51c8515852 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
@@ -48,6 +48,7 @@ import com.android.systemui.statusbar.notification.MediaNotificationProcessor
import com.android.systemui.statusbar.notification.row.HybridGroupManager
import com.android.systemui.util.Assert
import com.android.systemui.util.Utils
+import com.android.systemui.util.concurrency.DelayableExecutor
import java.io.FileDescriptor
import java.io.IOException
import java.io.PrintWriter
@@ -90,7 +91,7 @@ fun isMediaNotification(sbn: StatusBarNotification): Boolean {
class MediaDataManager(
private val context: Context,
@Background private val backgroundExecutor: Executor,
- @Main private val foregroundExecutor: Executor,
+ @Main private val foregroundExecutor: DelayableExecutor,
private val mediaControllerFactory: MediaControllerFactory,
private val broadcastDispatcher: BroadcastDispatcher,
dumpManager: DumpManager,
@@ -107,7 +108,7 @@ class MediaDataManager(
constructor(
context: Context,
@Background backgroundExecutor: Executor,
- @Main foregroundExecutor: Executor,
+ @Main foregroundExecutor: DelayableExecutor,
mediaControllerFactory: MediaControllerFactory,
dumpManager: DumpManager,
broadcastDispatcher: BroadcastDispatcher,
@@ -183,10 +184,7 @@ class MediaDataManager(
val listenersCopy = listeners.toSet()
val toRemove = mediaEntries.filter { it.value.packageName == packageName }
toRemove.forEach {
- mediaEntries.remove(it.key)
- listenersCopy.forEach { listener ->
- listener.onMediaDataRemoved(it.key)
- }
+ removeEntry(it.key, listenersCopy)
}
}
@@ -269,6 +267,18 @@ class MediaDataManager(
}
}
+ private fun removeEntry(key: String, listenersCopy: Set<Listener>) {
+ mediaEntries.remove(key)
+ listenersCopy.forEach {
+ it.onMediaDataRemoved(key)
+ }
+ }
+
+ fun dismissMediaData(key: String, delay: Long) {
+ val listenersCopy = listeners.toSet()
+ foregroundExecutor.executeDelayed({ removeEntry(key, listenersCopy) }, delay)
+ }
+
private fun loadMediaDataInBgForResumption(
userId: Int,
desc: MediaDescription,
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt
index fc33391a9ad1..70f01d576a9c 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt
@@ -293,6 +293,13 @@ class MediaHierarchyManager @Inject constructor(
return viewHost
}
+ /**
+ * Close the guts in all players in [MediaCarouselController].
+ */
+ fun closeGuts() {
+ mediaCarouselController.closeGuts()
+ }
+
private fun createUniqueObjectHost(): UniqueObjectHostView {
val viewHost = UniqueObjectHostView(context)
viewHost.addOnAttachStateChangeListener(object : View.OnAttachStateChangeListener {
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaViewController.kt b/packages/SystemUI/src/com/android/systemui/media/MediaViewController.kt
index 38817d7b579e..92eeed46388d 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaViewController.kt
@@ -37,6 +37,11 @@ class MediaViewController @Inject constructor(
private val mediaHostStatesManager: MediaHostStatesManager
) {
+ companion object {
+ @JvmField
+ val GUTS_ANIMATION_DURATION = 500L
+ }
+
/**
* A listener when the current dimensions of the player change
*/
@@ -169,6 +174,12 @@ class MediaViewController @Inject constructor(
*/
val expandedLayout = ConstraintSet()
+ /**
+ * Whether the guts are visible for the associated player.
+ */
+ var isGutsVisible = false
+ private set
+
init {
collapsedLayout.load(context, R.xml.media_collapsed)
expandedLayout.load(context, R.xml.media_expanded)
@@ -189,6 +200,37 @@ class MediaViewController @Inject constructor(
configurationController.removeCallback(configurationListener)
}
+ /**
+ * Show guts with an animated transition.
+ */
+ fun openGuts() {
+ if (isGutsVisible) return
+ isGutsVisible = true
+ animatePendingStateChange(GUTS_ANIMATION_DURATION, 0L)
+ setCurrentState(currentStartLocation,
+ currentEndLocation,
+ currentTransitionProgress,
+ applyImmediately = false)
+ }
+
+ /**
+ * Close the guts for the associated player.
+ *
+ * @param immediate if `false`, it will animate the transition.
+ */
+ @JvmOverloads
+ fun closeGuts(immediate: Boolean = false) {
+ if (!isGutsVisible) return
+ isGutsVisible = false
+ if (!immediate) {
+ animatePendingStateChange(GUTS_ANIMATION_DURATION, 0L)
+ }
+ setCurrentState(currentStartLocation,
+ currentEndLocation,
+ currentTransitionProgress,
+ applyImmediately = immediate)
+ }
+
private fun ensureAllMeasurements() {
val mediaStates = mediaHostStatesManager.mediaHostStates
for (entry in mediaStates) {
@@ -203,6 +245,24 @@ class MediaViewController @Inject constructor(
if (expansion > 0) expandedLayout else collapsedLayout
/**
+ * Set the views to be showing/hidden based on the [isGutsVisible] for a given
+ * [TransitionViewState].
+ */
+ private fun setGutsViewState(viewState: TransitionViewState) {
+ PlayerViewHolder.controlsIds.forEach { id ->
+ viewState.widgetStates.get(id)?.let { state ->
+ // Make sure to use the unmodified state if guts are not visible
+ state.alpha = if (isGutsVisible) 0f else state.alpha
+ state.gone = if (isGutsVisible) true else state.gone
+ }
+ }
+ PlayerViewHolder.gutsIds.forEach { id ->
+ viewState.widgetStates.get(id)?.alpha = if (isGutsVisible) 1f else 0f
+ viewState.widgetStates.get(id)?.gone = !isGutsVisible
+ }
+ }
+
+ /**
* Obtain a new viewState for a given media state. This usually returns a cached state, but if
* it's not available, it will recreate one by measuring, which may be expensive.
*/
@@ -211,7 +271,7 @@ class MediaViewController @Inject constructor(
return null
}
// Only a subset of the state is relevant to get a valid viewState. Let's get the cachekey
- var cacheKey = getKey(state, tmpKey)
+ var cacheKey = getKey(state, isGutsVisible, tmpKey)
val viewState = viewStates[cacheKey]
if (viewState != null) {
// we already have cached this measurement, let's continue
@@ -228,6 +288,7 @@ class MediaViewController @Inject constructor(
constraintSetForExpansion(state.expansion),
TransitionViewState())
+ setGutsViewState(result)
// We don't want to cache interpolated or null states as this could quickly fill up
// our cache. We only cache the start and the end states since the interpolation
// is cheap
@@ -252,11 +313,12 @@ class MediaViewController @Inject constructor(
return result
}
- private fun getKey(state: MediaHostState, result: CacheKey): CacheKey {
+ private fun getKey(state: MediaHostState, guts: Boolean, result: CacheKey): CacheKey {
result.apply {
heightMeasureSpec = state.measurementInput?.heightMeasureSpec ?: 0
widthMeasureSpec = state.measurementInput?.widthMeasureSpec ?: 0
expansion = state.expansion
+ gutsVisible = guts
}
return result
}
@@ -432,5 +494,6 @@ class MediaViewController @Inject constructor(
private data class CacheKey(
var widthMeasureSpec: Int = -1,
var heightMeasureSpec: Int = -1,
- var expansion: Float = 0.0f
+ var expansion: Float = 0.0f,
+ var gutsVisible: Boolean = false
)
diff --git a/packages/SystemUI/src/com/android/systemui/media/PlayerViewHolder.kt b/packages/SystemUI/src/com/android/systemui/media/PlayerViewHolder.kt
index 600fdc27ef89..11551aca80f2 100644
--- a/packages/SystemUI/src/com/android/systemui/media/PlayerViewHolder.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/PlayerViewHolder.kt
@@ -23,6 +23,7 @@ import android.widget.ImageButton
import android.widget.ImageView
import android.widget.SeekBar
import android.widget.TextView
+import androidx.constraintlayout.widget.ConstraintSet
import com.android.systemui.R
import com.android.systemui.util.animation.TransitionLayout
@@ -59,6 +60,11 @@ class PlayerViewHolder private constructor(itemView: View) {
val action3 = itemView.requireViewById<ImageButton>(R.id.action3)
val action4 = itemView.requireViewById<ImageButton>(R.id.action4)
+ // Settings screen
+ val cancel = itemView.requireViewById<View>(R.id.cancel)
+ val dismiss = itemView.requireViewById<View>(R.id.dismiss)
+ val settings = itemView.requireViewById<View>(R.id.settings)
+
init {
(player.background as IlluminationDrawable).let {
it.registerLightSource(seamless)
@@ -67,6 +73,9 @@ class PlayerViewHolder private constructor(itemView: View) {
it.registerLightSource(action2)
it.registerLightSource(action3)
it.registerLightSource(action4)
+ it.registerLightSource(cancel)
+ it.registerLightSource(dismiss)
+ it.registerLightSource(settings)
}
}
@@ -83,9 +92,6 @@ class PlayerViewHolder private constructor(itemView: View) {
}
}
- // Settings screen
- val options = itemView.requireViewById<View>(R.id.qs_media_controls_options)
-
companion object {
/**
* Creates a PlayerViewHolder.
@@ -105,5 +111,29 @@ class PlayerViewHolder private constructor(itemView: View) {
progressTimes.layoutDirection = View.LAYOUT_DIRECTION_LTR
}
}
+
+ val controlsIds = setOf(
+ R.id.icon,
+ R.id.app_name,
+ R.id.album_art,
+ R.id.header_title,
+ R.id.header_artist,
+ R.id.media_seamless,
+ R.id.notification_media_progress_time,
+ R.id.media_progress_bar,
+ R.id.action0,
+ R.id.action1,
+ R.id.action2,
+ R.id.action3,
+ R.id.action4,
+ R.id.icon
+ )
+ val gutsIds = setOf(
+ R.id.media_text,
+ R.id.remove_text,
+ R.id.cancel,
+ R.id.dismiss,
+ R.id.settings
+ )
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedTutorialHandler.java b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedTutorialHandler.java
index 8a67da53e6a2..b28730d004f6 100644
--- a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedTutorialHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedTutorialHandler.java
@@ -16,11 +16,13 @@
package com.android.systemui.onehanded;
+import android.content.ContentResolver;
import android.content.Context;
import android.graphics.PixelFormat;
import android.graphics.Point;
import android.graphics.Rect;
import android.os.Handler;
+import android.provider.Settings;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
@@ -48,12 +50,15 @@ import javax.inject.Singleton;
@Singleton
public class OneHandedTutorialHandler implements OneHandedTransitionCallback, Dumpable {
private static final String TAG = "OneHandedTutorialHandler";
+ private static final int MAX_TUTORIAL_SHOW_COUNT = 2;
private final Rect mLastUpdatedBounds = new Rect();
private final WindowManager mWindowManager;
private View mTutorialView;
private Point mDisplaySize = new Point();
private Handler mUpdateHandler;
+ private ContentResolver mContentResolver;
+ private boolean mCanShowTutorial;
/**
* Container of the tutorial panel showing at outside region when one handed starting
@@ -71,6 +76,7 @@ public class OneHandedTutorialHandler implements OneHandedTransitionCallback, Du
@Inject
public OneHandedTutorialHandler(Context context) {
context.getDisplay().getRealSize(mDisplaySize);
+ mContentResolver = context.getContentResolver();
mUpdateHandler = new Handler();
mWindowManager = context.getSystemService(WindowManager.class);
mTargetViewContainer = new FrameLayout(context);
@@ -79,12 +85,20 @@ public class OneHandedTutorialHandler implements OneHandedTransitionCallback, Du
R.fraction.config_one_handed_offset, 1, 1));
mTutorialView = LayoutInflater.from(context).inflate(R.xml.one_handed_tutorial, null);
mTargetViewContainer.addView(mTutorialView);
- createOrUpdateTutorialTarget();
+ mCanShowTutorial = (Settings.Secure.getInt(mContentResolver,
+ Settings.Secure.ONE_HANDED_TUTORIAL_SHOW_COUNT, 0) >= MAX_TUTORIAL_SHOW_COUNT)
+ ? false : true;
+ if (mCanShowTutorial) {
+ createOrUpdateTutorialTarget();
+ }
}
@Override
public void onStartFinished(Rect bounds) {
- mUpdateHandler.post(() -> updateFinished(View.VISIBLE, 0f));
+ mUpdateHandler.post(() -> {
+ updateFinished(View.VISIBLE, 0f);
+ updateTutorialCount();
+ });
}
@Override
@@ -94,10 +108,23 @@ public class OneHandedTutorialHandler implements OneHandedTransitionCallback, Du
}
private void updateFinished(int visible, float finalPosition) {
+ if (!canShowTutorial()) {
+ return;
+ }
+
mTargetViewContainer.setVisibility(visible);
mTargetViewContainer.setTranslationY(finalPosition);
}
+ private void updateTutorialCount() {
+ int showCount = Settings.Secure.getInt(mContentResolver,
+ Settings.Secure.ONE_HANDED_TUTORIAL_SHOW_COUNT, 0);
+ showCount = Math.min(MAX_TUTORIAL_SHOW_COUNT, showCount + 1);
+ mCanShowTutorial = showCount < MAX_TUTORIAL_SHOW_COUNT;
+ Settings.Secure.putInt(mContentResolver,
+ Settings.Secure.ONE_HANDED_TUTORIAL_SHOW_COUNT, showCount);
+ }
+
/**
* Adds the tutorial target view to the WindowManager and update its layout, so it's ready
* to be animated in.
@@ -153,7 +180,19 @@ public class OneHandedTutorialHandler implements OneHandedTransitionCallback, Du
pw.println(mLastUpdatedBounds);
}
+ private boolean canShowTutorial() {
+ if (!mCanShowTutorial) {
+ mTargetViewContainer.setVisibility(View.GONE);
+ return false;
+ }
+
+ return true;
+ }
+
private void onAnimationUpdate(float value) {
+ if (!canShowTutorial()) {
+ return;
+ }
mTargetViewContainer.setVisibility(View.VISIBLE);
mTargetViewContainer.setTransitionGroup(true);
mTargetViewContainer.setTranslationY(value - mTargetViewContainer.getHeight());
diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java b/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java
index 7c3743bd8bcf..025341cf4fba 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java
@@ -99,6 +99,7 @@ public class PipTaskOrganizer extends TaskOrganizer implements
private final Handler mUpdateHandler;
private final PipBoundsHandler mPipBoundsHandler;
private final PipAnimationController mPipAnimationController;
+ private final PipUiEventLogger mPipUiEventLoggerLogger;
private final List<PipTransitionCallback> mPipTransitionCallbacks = new ArrayList<>();
private final Rect mLastReportedBounds = new Rect();
private final int mEnterExitAnimationDuration;
@@ -209,7 +210,8 @@ public class PipTaskOrganizer extends TaskOrganizer implements
@NonNull PipSurfaceTransactionHelper surfaceTransactionHelper,
@Nullable Divider divider,
@NonNull DisplayController displayController,
- @NonNull PipAnimationController pipAnimationController) {
+ @NonNull PipAnimationController pipAnimationController,
+ @NonNull PipUiEventLogger pipUiEventLogger) {
mMainHandler = new Handler(Looper.getMainLooper());
mUpdateHandler = new Handler(PipUpdateThread.get().getLooper(), mUpdateCallbacks);
mPipBoundsHandler = boundsHandler;
@@ -217,6 +219,7 @@ public class PipTaskOrganizer extends TaskOrganizer implements
.getInteger(R.integer.config_pipResizeAnimationDuration);
mSurfaceTransactionHelper = surfaceTransactionHelper;
mPipAnimationController = pipAnimationController;
+ mPipUiEventLoggerLogger = pipUiEventLogger;
mSurfaceControlTransactionFactory = SurfaceControl.Transaction::new;
mSplitDivider = divider;
displayController.addDisplayWindowListener(this);
@@ -279,6 +282,8 @@ public class PipTaskOrganizer extends TaskOrganizer implements
return;
}
+ mPipUiEventLoggerLogger.log(
+ PipUiEventLogger.PipUiEventEnum.PICTURE_IN_PICTURE_EXPAND_TO_FULLSCREEN);
final Configuration initialConfig = mInitialState.remove(mToken.asBinder());
final boolean orientationDiffers = initialConfig.windowConfiguration.getRotation()
!= mPipBoundsHandler.getDisplayRotation();
@@ -381,6 +386,9 @@ public class PipTaskOrganizer extends TaskOrganizer implements
mInitialState.put(mToken.asBinder(), new Configuration(mTaskInfo.configuration));
mPictureInPictureParams = mTaskInfo.pictureInPictureParams;
+ mPipUiEventLoggerLogger.setTaskInfo(mTaskInfo);
+ mPipUiEventLoggerLogger.log(PipUiEventLogger.PipUiEventEnum.PICTURE_IN_PICTURE_ENTER);
+
if (mShouldDeferEnteringPip) {
if (DEBUG) Log.d(TAG, "Defer entering PiP animation, fixed rotation is ongoing");
// if deferred, hide the surface till fixed rotation is completed
@@ -454,10 +462,11 @@ public class PipTaskOrganizer extends TaskOrganizer implements
private void sendOnPipTransitionStarted(
@PipAnimationController.TransitionDirection int direction) {
+ final Rect pipBounds = new Rect(mLastReportedBounds);
runOnMainHandler(() -> {
for (int i = mPipTransitionCallbacks.size() - 1; i >= 0; i--) {
final PipTransitionCallback callback = mPipTransitionCallbacks.get(i);
- callback.onPipTransitionStarted(mTaskInfo.baseActivity, direction);
+ callback.onPipTransitionStarted(mTaskInfo.baseActivity, direction, pipBounds);
}
});
}
@@ -513,6 +522,7 @@ public class PipTaskOrganizer extends TaskOrganizer implements
mPictureInPictureParams = null;
mInPip = false;
mExitingPip = false;
+ mPipUiEventLoggerLogger.setTaskInfo(null);
}
@Override
@@ -628,7 +638,7 @@ public class PipTaskOrganizer extends TaskOrganizer implements
* {@link PictureInPictureParams} would affect the bounds.
*/
private boolean applyPictureInPictureParams(@NonNull PictureInPictureParams params) {
- final boolean changed = (mPictureInPictureParams == null) ? true : !Objects.equals(
+ final boolean changed = (mPictureInPictureParams == null) || !Objects.equals(
mPictureInPictureParams.getAspectRatioRational(), params.getAspectRatioRational());
if (changed) {
mPictureInPictureParams = params;
@@ -973,7 +983,7 @@ public class PipTaskOrganizer extends TaskOrganizer implements
/**
* Callback when the pip transition is started.
*/
- void onPipTransitionStarted(ComponentName activity, int direction);
+ void onPipTransitionStarted(ComponentName activity, int direction, Rect pipBounds);
/**
* Callback when the pip transition is finished.
diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipUiEventLogger.java b/packages/SystemUI/src/com/android/systemui/pip/PipUiEventLogger.java
new file mode 100644
index 000000000000..5e2cd9c111b2
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/pip/PipUiEventLogger.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.pip;
+
+import android.app.TaskInfo;
+
+import com.android.internal.logging.UiEvent;
+import com.android.internal.logging.UiEventLogger;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+
+/**
+ * Helper class that ends PiP log to UiEvent, see also go/uievent
+ */
+@Singleton
+public class PipUiEventLogger {
+
+ private final UiEventLogger mUiEventLogger;
+
+ private TaskInfo mTaskInfo;
+
+ @Inject
+ public PipUiEventLogger(UiEventLogger uiEventLogger) {
+ mUiEventLogger = uiEventLogger;
+ }
+
+ public void setTaskInfo(TaskInfo taskInfo) {
+ mTaskInfo = taskInfo;
+ }
+
+ /**
+ * Sends log via UiEvent, reference go/uievent for how to debug locally
+ */
+ public void log(PipUiEventEnum event) {
+ if (mTaskInfo == null) {
+ return;
+ }
+ mUiEventLogger.log(event, mTaskInfo.userId, mTaskInfo.topActivity.getPackageName());
+ }
+
+ /**
+ * Enums for logging the PiP events to UiEvent
+ */
+ public enum PipUiEventEnum implements UiEventLogger.UiEventEnum {
+ @UiEvent(doc = "Activity enters picture-in-picture mode")
+ PICTURE_IN_PICTURE_ENTER(603),
+
+ @UiEvent(doc = "Expands from picture-in-picture to fullscreen")
+ PICTURE_IN_PICTURE_EXPAND_TO_FULLSCREEN(604),
+
+ @UiEvent(doc = "Removes picture-in-picture by tap close button")
+ PICTURE_IN_PICTURE_TAP_TO_REMOVE(605),
+
+ @UiEvent(doc = "Removes picture-in-picture by drag to dismiss area")
+ PICTURE_IN_PICTURE_DRAG_TO_REMOVE(606),
+
+ @UiEvent(doc = "Shows picture-in-picture menu")
+ PICTURE_IN_PICTURE_SHOW_MENU(607),
+
+ @UiEvent(doc = "Hides picture-in-picture menu")
+ PICTURE_IN_PICTURE_HIDE_MENU(608),
+
+ @UiEvent(doc = "Changes the aspect ratio of picture-in-picture window. This is inherited"
+ + " from previous Tron-based logging and currently not in use.")
+ PICTURE_IN_PICTURE_CHANGE_ASPECT_RATIO(609),
+
+ @UiEvent(doc = "User resize of the picture-in-picture window")
+ PICTURE_IN_PICTURE_RESIZE(610);
+
+ private final int mId;
+
+ PipUiEventEnum(int id) {
+ mId = id;
+ }
+
+ @Override
+ public int getId() {
+ return mId;
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
index 6e75253d8604..9dfa864e2ee7 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
@@ -47,6 +47,7 @@ import com.android.systemui.pip.BasePipManager;
import com.android.systemui.pip.PipBoundsHandler;
import com.android.systemui.pip.PipSnapAlgorithm;
import com.android.systemui.pip.PipTaskOrganizer;
+import com.android.systemui.pip.PipUiEventLogger;
import com.android.systemui.pip.phone.dagger.PipMenuActivityClass;
import com.android.systemui.shared.recents.IPinnedStackAnimationListener;
import com.android.systemui.shared.system.ActivityManagerWrapper;
@@ -259,7 +260,8 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio
PipSnapAlgorithm pipSnapAlgorithm,
PipTaskOrganizer pipTaskOrganizer,
SysUiState sysUiState,
- ConfigurationController configController) {
+ ConfigurationController configController,
+ PipUiEventLogger pipUiEventLogger) {
mContext = context;
mActivityManager = ActivityManager.getService();
@@ -280,7 +282,8 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio
mMediaController, mInputConsumerController);
mTouchHandler = new PipTouchHandler(context, mActivityManager,
mMenuController, mInputConsumerController, mPipBoundsHandler, mPipTaskOrganizer,
- floatingContentCoordinator, deviceConfig, pipSnapAlgorithm, sysUiState);
+ floatingContentCoordinator, deviceConfig, pipSnapAlgorithm, sysUiState,
+ pipUiEventLogger);
mAppOpsListener = new PipAppOpsListener(context, mActivityManager,
mTouchHandler.getMotionHelper());
displayController.addDisplayChangingController(mRotationController);
@@ -373,10 +376,10 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio
}
@Override
- public void onPipTransitionStarted(ComponentName activity, int direction) {
+ public void onPipTransitionStarted(ComponentName activity, int direction, Rect pipBounds) {
if (isOutPipDirection(direction)) {
// Exiting PIP, save the reentry bounds to restore to when re-entering.
- updateReentryBounds();
+ updateReentryBounds(pipBounds);
mPipBoundsHandler.onSaveReentryBounds(activity, mReentryBounds);
}
// Disable touches while the animation is running
@@ -393,15 +396,8 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio
/**
* Update the bounds used to save the re-entry size and snap fraction when exiting PIP.
*/
- public void updateReentryBounds() {
- // On phones, the expansion animation that happens on pip tap before restoring
- // to fullscreen makes it so that the last reported bounds are the expanded
- // bounds. We want to restore to the unexpanded bounds when re-entering pip,
- // so we use the bounds before expansion (normal) instead of the reported
- // bounds.
- Rect reentryBounds = mTouchHandler.getNormalBounds();
- // Apply the snap fraction of the current bounds to the normal bounds.
- final Rect bounds = mPipTaskOrganizer.getLastReportedBounds();
+ public void updateReentryBounds(Rect bounds) {
+ final Rect reentryBounds = mTouchHandler.getUserResizeBounds();
float snapFraction = mPipBoundsHandler.getSnapFraction(bounds);
mPipBoundsHandler.applySnapFraction(reentryBounds, snapFraction);
mReentryBounds.set(reentryBounds);
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
index ee8f295e0c30..19138fdba788 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
@@ -154,7 +154,7 @@ public class PipMotionHelper implements PipAppOpsListener.Callback,
private final PipTaskOrganizer.PipTransitionCallback mPipTransitionCallback =
new PipTaskOrganizer.PipTransitionCallback() {
@Override
- public void onPipTransitionStarted(ComponentName activity, int direction) {}
+ public void onPipTransitionStarted(ComponentName activity, int direction, Rect pipBounds) {}
@Override
public void onPipTransitionFinished(ComponentName activity, int direction) {
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java
index d884fa956edc..9c42f8bff378 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java
@@ -52,6 +52,7 @@ import com.android.internal.policy.TaskResizingAlgorithm;
import com.android.systemui.model.SysUiState;
import com.android.systemui.pip.PipBoundsHandler;
import com.android.systemui.pip.PipTaskOrganizer;
+import com.android.systemui.pip.PipUiEventLogger;
import com.android.systemui.util.DeviceConfigProxy;
import com.android.wm.shell.R;
@@ -88,6 +89,7 @@ public class PipResizeGestureHandler {
private final Point mMaxSize = new Point();
private final Point mMinSize = new Point();
private final Rect mLastResizeBounds = new Rect();
+ private final Rect mUserResizeBounds = new Rect();
private final Rect mLastDownBounds = new Rect();
private final Rect mDragCornerSize = new Rect();
private final Rect mTmpTopLeftCorner = new Rect();
@@ -109,13 +111,15 @@ public class PipResizeGestureHandler {
private InputMonitor mInputMonitor;
private InputEventReceiver mInputEventReceiver;
private PipTaskOrganizer mPipTaskOrganizer;
+ private PipUiEventLogger mPipUiEventLogger;
private int mCtrlType;
public PipResizeGestureHandler(Context context, PipBoundsHandler pipBoundsHandler,
PipMotionHelper motionHelper, DeviceConfigProxy deviceConfig,
PipTaskOrganizer pipTaskOrganizer, Function<Rect, Rect> movementBoundsSupplier,
- Runnable updateMovementBoundsRunnable, SysUiState sysUiState) {
+ Runnable updateMovementBoundsRunnable, SysUiState sysUiState,
+ PipUiEventLogger pipUiEventLogger) {
mContext = context;
mDisplayId = context.getDisplayId();
mMainExecutor = context.getMainExecutor();
@@ -125,6 +129,7 @@ public class PipResizeGestureHandler {
mMovementBoundsSupplier = movementBoundsSupplier;
mUpdateMovementBoundsRunnable = updateMovementBoundsRunnable;
mSysUiState = sysUiState;
+ mPipUiEventLogger = pipUiEventLogger;
context.getDisplay().getRealSize(mMaxSize);
reloadResources();
@@ -181,6 +186,7 @@ public class PipResizeGestureHandler {
void onActivityUnpinned() {
mIsAttached = false;
+ mUserResizeBounds.setEmpty();
updateIsEnabled();
}
@@ -329,6 +335,7 @@ public class PipResizeGestureHandler {
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
if (!mLastResizeBounds.isEmpty()) {
+ mUserResizeBounds.set(mLastResizeBounds);
mPipTaskOrganizer.scheduleFinishResizePip(mLastResizeBounds,
(Rect bounds) -> {
new Handler(Looper.getMainLooper()).post(() -> {
@@ -337,6 +344,8 @@ public class PipResizeGestureHandler {
resetState();
});
});
+ mPipUiEventLogger.log(
+ PipUiEventLogger.PipUiEventEnum.PICTURE_IN_PICTURE_RESIZE);
} else {
resetState();
}
@@ -351,6 +360,14 @@ public class PipResizeGestureHandler {
mThresholdCrossed = false;
}
+ void setUserResizeBounds(Rect bounds) {
+ mUserResizeBounds.set(bounds);
+ }
+
+ Rect getUserResizeBounds() {
+ return mUserResizeBounds;
+ }
+
void updateMaxSize(int maxX, int maxY) {
mMaxSize.set(maxX, maxY);
}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
index 7fc2823fc248..b20ea4e5c836 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
@@ -34,7 +34,6 @@ import android.graphics.drawable.TransitionDrawable;
import android.os.Handler;
import android.os.RemoteException;
import android.util.Log;
-import android.util.Pair;
import android.util.Size;
import android.view.Gravity;
import android.view.IPinnedStackController;
@@ -55,13 +54,13 @@ import androidx.dynamicanimation.animation.DynamicAnimation;
import androidx.dynamicanimation.animation.SpringForce;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.os.logging.MetricsLoggerWrapper;
import com.android.systemui.R;
import com.android.systemui.model.SysUiState;
import com.android.systemui.pip.PipAnimationController;
import com.android.systemui.pip.PipBoundsHandler;
import com.android.systemui.pip.PipSnapAlgorithm;
import com.android.systemui.pip.PipTaskOrganizer;
+import com.android.systemui.pip.PipUiEventLogger;
import com.android.systemui.shared.system.InputConsumerController;
import com.android.systemui.util.DeviceConfigProxy;
import com.android.systemui.util.DismissCircleView;
@@ -94,6 +93,8 @@ public class PipTouchHandler {
private final WindowManager mWindowManager;
private final IActivityManager mActivityManager;
private final PipBoundsHandler mPipBoundsHandler;
+ private final PipUiEventLogger mPipUiEventLogger;
+
private PipResizeGestureHandler mPipResizeGestureHandler;
private IPinnedStackController mPinnedStackController;
@@ -132,9 +133,6 @@ public class PipTouchHandler {
// The current movement bounds
private Rect mMovementBounds = new Rect();
- // The current resized bounds, changed by user resize.
- // This is used during expand/un-expand to save/restore the user's resized size.
- @VisibleForTesting Rect mResizedBounds = new Rect();
// The reference inset bounds, used to determine the dismiss fraction
private Rect mInsetBounds = new Rect();
@@ -198,11 +196,7 @@ public class PipTouchHandler {
@Override
public void onPipDismiss() {
- Pair<ComponentName, Integer> topPipActivity = PipUtils.getTopPipActivity(mContext,
- mActivityManager);
- if (topPipActivity.first != null) {
- MetricsLoggerWrapper.logPictureInPictureDismissByTap(mContext, topPipActivity);
- }
+ mPipUiEventLogger.log(PipUiEventLogger.PipUiEventEnum.PICTURE_IN_PICTURE_TAP_TO_REMOVE);
mTouchState.removeDoubleTapTimeoutCallback();
mMotionHelper.dismissPip();
}
@@ -223,7 +217,8 @@ public class PipTouchHandler {
FloatingContentCoordinator floatingContentCoordinator,
DeviceConfigProxy deviceConfig,
PipSnapAlgorithm pipSnapAlgorithm,
- SysUiState sysUiState) {
+ SysUiState sysUiState,
+ PipUiEventLogger pipUiEventLogger) {
// Initialize the Pip input consumer
mContext = context;
mActivityManager = activityManager;
@@ -238,7 +233,7 @@ public class PipTouchHandler {
mPipResizeGestureHandler =
new PipResizeGestureHandler(context, pipBoundsHandler, mMotionHelper,
deviceConfig, pipTaskOrganizer, this::getMovementBounds,
- this::updateMovementBounds, sysUiState);
+ this::updateMovementBounds, sysUiState, pipUiEventLogger);
mTouchState = new PipTouchState(ViewConfiguration.get(context), mHandler,
() -> mMenuController.showMenuWithDelay(MENU_STATE_FULL, mMotionHelper.getBounds(),
true /* allowMenuTimeout */, willResizeMenu(), shouldShowResizeHandle()),
@@ -259,6 +254,8 @@ public class PipTouchHandler {
pipTaskOrganizer, pipSnapAlgorithm, this::onAccessibilityShowMenu,
this::updateMovementBounds, mHandler);
+ mPipUiEventLogger = pipUiEventLogger;
+
mTargetView = new DismissCircleView(context);
mTargetViewContainer = new FrameLayout(context);
mTargetViewContainer.setBackgroundDrawable(
@@ -307,11 +304,8 @@ public class PipTouchHandler {
hideDismissTarget();
});
- Pair<ComponentName, Integer> topPipActivity = PipUtils.getTopPipActivity(mContext,
- mActivityManager);
- if (topPipActivity.first != null) {
- MetricsLoggerWrapper.logPictureInPictureDismissByDrag(mContext, topPipActivity);
- }
+ mPipUiEventLogger.log(
+ PipUiEventLogger.PipUiEventEnum.PICTURE_IN_PICTURE_DRAG_TO_REMOVE);
}
});
@@ -383,7 +377,6 @@ public class PipTouchHandler {
mFloatingContentCoordinator.onContentRemoved(mMotionHelper);
}
- mResizedBounds.setEmpty();
mPipResizeGestureHandler.onActivityUnpinned();
}
@@ -393,9 +386,8 @@ public class PipTouchHandler {
mMotionHelper.synchronizePinnedStackBounds();
updateMovementBounds();
if (direction == TRANSITION_DIRECTION_TO_PIP) {
- // updates mResizedBounds only if it's an entering PiP animation
- // mResized should be otherwise updated in setMenuState.
- mResizedBounds.set(mMotionHelper.getBounds());
+ // Set the initial bounds as the user resize bounds.
+ mPipResizeGestureHandler.setUserResizeBounds(mMotionHelper.getBounds());
}
if (mShowPipMenuOnAnimationEnd) {
@@ -808,9 +800,7 @@ public class PipTouchHandler {
// Save the current snap fraction and if we do not drag or move the PiP, then
// we store back to this snap fraction. Otherwise, we'll reset the snap
// fraction and snap to the closest edge.
- // Also save the current resized bounds so when the menu disappears, we can restore it.
if (resize) {
- mResizedBounds.set(mMotionHelper.getBounds());
Rect expandedBounds = new Rect(mExpandedBounds);
mSavedSnapFraction = mMotionHelper.animateToExpandedState(expandedBounds,
mMovementBounds, mExpandedMovementBounds, callback);
@@ -839,7 +829,7 @@ public class PipTouchHandler {
}
if (mDeferResizeToNormalBoundsUntilRotation == -1) {
- Rect restoreBounds = new Rect(mResizedBounds);
+ Rect restoreBounds = new Rect(getUserResizeBounds());
Rect restoredMovementBounds = new Rect();
mSnapAlgorithm.getMovementBounds(restoreBounds, mInsetBounds,
restoredMovementBounds, mIsImeShowing ? mImeHeight : 0);
@@ -856,8 +846,10 @@ public class PipTouchHandler {
// If pip menu has dismissed, we should register the A11y ActionReplacingConnection for pip
// as well, or it can't handle a11y focus and pip menu can't perform any action.
onRegistrationChanged(menuState == MENU_STATE_NONE);
- if (menuState != MENU_STATE_CLOSE) {
- MetricsLoggerWrapper.logPictureInPictureMenuVisible(mContext, menuState == MENU_STATE_FULL);
+ if (menuState == MENU_STATE_NONE) {
+ mPipUiEventLogger.log(PipUiEventLogger.PipUiEventEnum.PICTURE_IN_PICTURE_HIDE_MENU);
+ } else if (menuState == MENU_STATE_FULL) {
+ mPipUiEventLogger.log(PipUiEventLogger.PipUiEventEnum.PICTURE_IN_PICTURE_SHOW_MENU);
}
}
@@ -890,6 +882,10 @@ public class PipTouchHandler {
return mNormalBounds;
}
+ Rect getUserResizeBounds() {
+ return mPipResizeGestureHandler.getUserResizeBounds();
+ }
+
/**
* Gesture controlling normal movement of the PIP.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
index 2138f092b790..01670285c0f4 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
@@ -663,7 +663,7 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio
};
@Override
- public void onPipTransitionStarted(ComponentName activity, int direction) { }
+ public void onPipTransitionStarted(ComponentName activity, int direction, Rect pipBounds) { }
@Override
public void onPipTransitionFinished(ComponentName activity, int direction) {
diff --git a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt
index d5a14f7bef2f..affc5ee1fdf0 100644
--- a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt
+++ b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt
@@ -45,7 +45,6 @@ import javax.inject.Singleton
@Singleton
class PrivacyItemController @Inject constructor(
- context: Context,
private val appOpsController: AppOpsController,
@Main uiExecutor: DelayableExecutor,
@Background private val bgExecutor: Executor,
@@ -57,16 +56,21 @@ class PrivacyItemController @Inject constructor(
@VisibleForTesting
internal companion object {
- val OPS = intArrayOf(AppOpsManager.OP_CAMERA,
- AppOpsManager.OP_RECORD_AUDIO,
+ val OPS_MIC_CAMERA = intArrayOf(AppOpsManager.OP_CAMERA,
+ AppOpsManager.OP_RECORD_AUDIO)
+ val OPS_LOCATION = intArrayOf(
AppOpsManager.OP_COARSE_LOCATION,
AppOpsManager.OP_FINE_LOCATION)
+ val OPS = OPS_MIC_CAMERA + OPS_LOCATION
val intentFilter = IntentFilter().apply {
addAction(Intent.ACTION_USER_SWITCHED)
addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABLE)
addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE)
}
const val TAG = "PrivacyItemController"
+ private const val ALL_INDICATORS =
+ SystemUiDeviceConfigFlags.PROPERTY_PERMISSIONS_HUB_ENABLED
+ private const val MIC_CAMERA = SystemUiDeviceConfigFlags.PROPERTY_MIC_CAMERA_ENABLED
}
@VisibleForTesting
@@ -74,9 +78,14 @@ class PrivacyItemController @Inject constructor(
@Synchronized get() = field.toList() // Returns a shallow copy of the list
@Synchronized set
- private fun isPermissionsHubEnabled(): Boolean {
+ private fun isAllIndicatorsEnabled(): Boolean {
return deviceConfigProxy.getBoolean(DeviceConfig.NAMESPACE_PRIVACY,
- SystemUiDeviceConfigFlags.PROPERTY_PERMISSIONS_HUB_ENABLED, false)
+ ALL_INDICATORS, false)
+ }
+
+ private fun isMicCameraEnabled(): Boolean {
+ return deviceConfigProxy.getBoolean(DeviceConfig.NAMESPACE_PRIVACY,
+ MIC_CAMERA, false)
}
private var currentUserIds = emptyList<Int>()
@@ -94,23 +103,28 @@ class PrivacyItemController @Inject constructor(
uiExecutor.execute(notifyChanges)
}
- var indicatorsAvailable = isPermissionsHubEnabled()
+ var allIndicatorsAvailable = isAllIndicatorsEnabled()
private set
- @VisibleForTesting
- internal val devicePropertiesChangedListener =
+ var micCameraAvailable = isMicCameraEnabled()
+ private set
+
+ private val devicePropertiesChangedListener =
object : DeviceConfig.OnPropertiesChangedListener {
override fun onPropertiesChanged(properties: DeviceConfig.Properties) {
if (DeviceConfig.NAMESPACE_PRIVACY.equals(properties.getNamespace()) &&
- properties.getKeyset().contains(
- SystemUiDeviceConfigFlags.PROPERTY_PERMISSIONS_HUB_ENABLED)) {
- val flag = properties.getBoolean(
- SystemUiDeviceConfigFlags.PROPERTY_PERMISSIONS_HUB_ENABLED, false)
- if (indicatorsAvailable != flag) {
- // This is happening already in the UI executor, so we can iterate in the
- indicatorsAvailable = flag
- callbacks.forEach { it.get()?.onFlagChanged(flag) }
+ (properties.keyset.contains(ALL_INDICATORS) ||
+ properties.keyset.contains(MIC_CAMERA))) {
+
+ // Running on the ui executor so can iterate on callbacks
+ if (properties.keyset.contains(ALL_INDICATORS)) {
+ allIndicatorsAvailable = properties.getBoolean(ALL_INDICATORS, false)
+ callbacks.forEach { it.get()?.onFlagAllChanged(allIndicatorsAvailable) }
}
+ if (properties.keyset.contains(MIC_CAMERA)) {
+ micCameraAvailable = properties.getBoolean(MIC_CAMERA, false)
+ callbacks.forEach { it.get()?.onFlagMicCameraChanged(micCameraAvailable) }
+ }
internalUiExecutor.updateListeningState()
}
}
@@ -123,6 +137,10 @@ class PrivacyItemController @Inject constructor(
packageName: String,
active: Boolean
) {
+ // Check if we care about this code right now
+ if (!allIndicatorsAvailable && code in OPS_LOCATION) {
+ return
+ }
val userId = UserHandle.getUserId(uid)
if (userId in currentUserIds) {
update(false)
@@ -166,13 +184,16 @@ class PrivacyItemController @Inject constructor(
}
/**
- * Updates listening status based on whether there are callbacks and the indicators are enabled
+ * Updates listening status based on whether there are callbacks and the indicators are enabled.
+ *
+ * Always listen to all OPS so we don't have to figure out what we should be listening to. We
+ * still have to filter anyway. Updates are filtered in the callback.
*
* This is only called from private (add/remove)Callback and from the config listener, all in
* main thread.
*/
private fun setListeningState() {
- val listen = !callbacks.isEmpty() and indicatorsAvailable
+ val listen = !callbacks.isEmpty() and (allIndicatorsAvailable || micCameraAvailable)
if (listening == listen) return
listening = listen
if (listening) {
@@ -233,14 +254,19 @@ class PrivacyItemController @Inject constructor(
AppOpsManager.OP_RECORD_AUDIO -> PrivacyType.TYPE_MICROPHONE
else -> return null
}
+ if (type == PrivacyType.TYPE_LOCATION && !allIndicatorsAvailable) return null
val app = PrivacyApplication(appOpItem.packageName, appOpItem.uid)
return PrivacyItem(type, app)
}
interface Callback {
fun onPrivacyItemsChanged(privacyItems: List<PrivacyItem>)
+
+ @JvmDefault
+ fun onFlagAllChanged(flag: Boolean) {}
+
@JvmDefault
- fun onFlagChanged(flag: Boolean) {}
+ fun onFlagMicCameraChanged(flag: Boolean) {}
}
internal inner class Receiver : BroadcastReceiver() {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
index 560998b5d1d8..22c735d5fa11 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
@@ -185,7 +185,9 @@ public class PagedTileLayout extends ViewPager implements QSTileLayout {
fakeDragBy(getScrollX() - mScroller.getCurrX());
} else if (isFakeDragging()) {
endFakeDrag();
- mBounceAnimatorSet.start();
+ if (mBounceAnimatorSet != null) {
+ mBounceAnimatorSet.start();
+ }
setOffscreenPageLimit(1);
}
super.computeScroll();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
index 2dc82dd853d4..2e258d56ece0 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
@@ -151,7 +151,8 @@ public class QuickStatusBarHeader extends RelativeLayout implements
private Space mSpace;
private BatteryMeterView mBatteryRemainingIcon;
private RingerModeTracker mRingerModeTracker;
- private boolean mPermissionsHubEnabled;
+ private boolean mAllIndicatorsEnabled;
+ private boolean mMicCameraIndicatorsEnabled;
private PrivacyItemController mPrivacyItemController;
private final UiEventLogger mUiEventLogger;
@@ -178,13 +179,26 @@ public class QuickStatusBarHeader extends RelativeLayout implements
}
@Override
- public void onFlagChanged(boolean flag) {
- if (mPermissionsHubEnabled != flag) {
- StatusIconContainer iconContainer = requireViewById(R.id.statusIcons);
- iconContainer.setIgnoredSlots(getIgnoredIconSlots());
- setChipVisibility(!mPrivacyChip.getPrivacyList().isEmpty());
+ public void onFlagAllChanged(boolean flag) {
+ if (mAllIndicatorsEnabled != flag) {
+ mAllIndicatorsEnabled = flag;
+ update();
}
}
+
+ @Override
+ public void onFlagMicCameraChanged(boolean flag) {
+ if (mMicCameraIndicatorsEnabled != flag) {
+ mMicCameraIndicatorsEnabled = flag;
+ update();
+ }
+ }
+
+ private void update() {
+ StatusIconContainer iconContainer = requireViewById(R.id.statusIcons);
+ iconContainer.setIgnoredSlots(getIgnoredIconSlots());
+ setChipVisibility(!mPrivacyChip.getPrivacyList().isEmpty());
+ }
};
@Inject
@@ -267,7 +281,8 @@ public class QuickStatusBarHeader extends RelativeLayout implements
mRingerModeTextView.setSelected(true);
mNextAlarmTextView.setSelected(true);
- mPermissionsHubEnabled = mPrivacyItemController.getIndicatorsAvailable();
+ mAllIndicatorsEnabled = mPrivacyItemController.getAllIndicatorsAvailable();
+ mMicCameraIndicatorsEnabled = mPrivacyItemController.getMicCameraAvailable();
}
public QuickQSPanel getHeaderQsPanel() {
@@ -276,13 +291,15 @@ public class QuickStatusBarHeader extends RelativeLayout implements
private List<String> getIgnoredIconSlots() {
ArrayList<String> ignored = new ArrayList<>();
- ignored.add(mContext.getResources().getString(
- com.android.internal.R.string.status_bar_camera));
- ignored.add(mContext.getResources().getString(
- com.android.internal.R.string.status_bar_microphone));
- if (mPermissionsHubEnabled) {
+ if (getChipEnabled()) {
+ ignored.add(mContext.getResources().getString(
+ com.android.internal.R.string.status_bar_camera));
ignored.add(mContext.getResources().getString(
- com.android.internal.R.string.status_bar_location));
+ com.android.internal.R.string.status_bar_microphone));
+ if (mAllIndicatorsEnabled) {
+ ignored.add(mContext.getResources().getString(
+ com.android.internal.R.string.status_bar_location));
+ }
}
return ignored;
@@ -300,7 +317,7 @@ public class QuickStatusBarHeader extends RelativeLayout implements
}
private void setChipVisibility(boolean chipVisible) {
- if (chipVisible && mPermissionsHubEnabled) {
+ if (chipVisible && getChipEnabled()) {
mPrivacyChip.setVisibility(View.VISIBLE);
// Makes sure that the chip is logged as viewed at most once each time QS is opened
// mListening makes sure that the callback didn't return after the user closed QS
@@ -607,7 +624,8 @@ public class QuickStatusBarHeader extends RelativeLayout implements
mAlarmController.addCallback(this);
mLifecycle.setCurrentState(Lifecycle.State.RESUMED);
// Get the most up to date info
- mPermissionsHubEnabled = mPrivacyItemController.getIndicatorsAvailable();
+ mAllIndicatorsEnabled = mPrivacyItemController.getAllIndicatorsAvailable();
+ mMicCameraIndicatorsEnabled = mPrivacyItemController.getMicCameraAvailable();
mPrivacyItemController.addCallback(mPICCallback);
} else {
mZenController.removeCallback(this);
@@ -747,4 +765,8 @@ public class QuickStatusBarHeader extends RelativeLayout implements
updateHeaderTextContainerAlphaAnimator();
}
}
+
+ private boolean getChipEnabled() {
+ return mMicCameraIndicatorsEnabled || mAllIndicatorsEnabled;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
index 8c485a6a950f..d2aaaede3f4b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
@@ -451,15 +451,17 @@ public abstract class QSTileImpl<TState extends State> implements QSTile, Lifecy
if (listening) {
if (mListeners.add(listener) && mListeners.size() == 1) {
if (DEBUG) Log.d(TAG, "handleSetListening true");
- mLifecycle.setCurrentState(RESUMED);
handleSetListening(listening);
- refreshState(); // Ensure we get at least one refresh after listening.
+ mUiHandler.post(() -> {
+ mLifecycle.setCurrentState(RESUMED);
+ refreshState(); // Ensure we get at least one refresh after listening.
+ });
}
} else {
if (mListeners.remove(listener) && mListeners.size() == 0) {
if (DEBUG) Log.d(TAG, "handleSetListening false");
- mLifecycle.setCurrentState(STARTED);
handleSetListening(listening);
+ mUiHandler.post(() -> mLifecycle.setCurrentState(STARTED));
}
}
updateIsFullQs();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java
index eb794a8b4378..c64fc50b8237 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java
@@ -130,6 +130,7 @@ public class BatterySaverTile extends QSTileImpl<BooleanState> implements
: mPowerSave ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
state.icon = mIcon;
state.label = mContext.getString(R.string.battery_detail_switch_title);
+ state.secondaryLabel = "";
state.contentDescription = state.label;
state.value = mPowerSave;
state.expandedAccessibilityClassName = Switch.class.getName();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java
index 3264429a1723..d8548decc5f4 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java
@@ -67,7 +67,7 @@ public class NightDisplayTile extends QSTileImpl<BooleanState> implements
private static final String PATTERN_HOUR_MINUTE = "h:mm a";
private static final String PATTERN_HOUR_NINUTE_24 = "HH:mm";
- private final ColorDisplayManager mManager;
+ private ColorDisplayManager mManager;
private final LocationController mLocationController;
private final NightDisplayListenerModule.Builder mNightDisplayListenerBuilder;
private NightDisplayListener mListener;
@@ -126,6 +126,8 @@ public class NightDisplayTile extends QSTileImpl<BooleanState> implements
mListener.setCallback(null);
}
+ mManager = getHost().getUserContext().getSystemService(ColorDisplayManager.class);
+
// Make a new controller for the new user.
mListener = mNightDisplayListenerBuilder.setUser(newUserId).build();
if (mIsListening) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/UiModeNightTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/UiModeNightTile.java
index 07b841ffb6f7..78975a4798ce 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/UiModeNightTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UiModeNightTile.java
@@ -58,10 +58,9 @@ public class UiModeNightTile extends QSTileImpl<QSTile.BooleanState> implements
public static DateTimeFormatter formatter = DateTimeFormatter.ofPattern("hh:mm a");
private final Icon mIcon = ResourceIcon.get(
com.android.internal.R.drawable.ic_qs_ui_mode_night);
- private final UiModeManager mUiModeManager;
+ private UiModeManager mUiModeManager;
private final BatteryController mBatteryController;
private final LocationController mLocationController;
-
@Inject
public UiModeNightTile(
QSHost host,
@@ -78,7 +77,7 @@ public class UiModeNightTile extends QSTileImpl<QSTile.BooleanState> implements
super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController,
activityStarter, qsLogger);
mBatteryController = batteryController;
- mUiModeManager = mContext.getSystemService(UiModeManager.class);
+ mUiModeManager = host.getUserContext().getSystemService(UiModeManager.class);
mLocationController = locationController;
configurationController.observe(getLifecycle(), this);
batteryController.observe(getLifecycle(), this);
diff --git a/packages/SystemUI/src/com/android/systemui/settings/CurrentUserContentResolverProvider.kt b/packages/SystemUI/src/com/android/systemui/settings/CurrentUserContentResolverProvider.kt
new file mode 100644
index 000000000000..9d05843b42bf
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/settings/CurrentUserContentResolverProvider.kt
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.settings
+
+import android.content.ContentResolver
+
+interface CurrentUserContentResolverProvider {
+
+ val currentUserContentResolver: ContentResolver
+} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/settings/CurrentUserContextTracker.kt b/packages/SystemUI/src/com/android/systemui/settings/CurrentUserContextTracker.kt
index 825a7f3dbadb..d7c4caaa4f9d 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/CurrentUserContextTracker.kt
+++ b/packages/SystemUI/src/com/android/systemui/settings/CurrentUserContextTracker.kt
@@ -16,6 +16,7 @@
package com.android.systemui.settings
+import android.content.ContentResolver
import android.content.Context
import android.os.UserHandle
import androidx.annotation.VisibleForTesting
@@ -31,7 +32,7 @@ import java.lang.IllegalStateException
class CurrentUserContextTracker internal constructor(
private val sysuiContext: Context,
broadcastDispatcher: BroadcastDispatcher
-) {
+) : CurrentUserContentResolverProvider {
private val userTracker: CurrentUserTracker
private var initialized = false
@@ -44,6 +45,9 @@ class CurrentUserContextTracker internal constructor(
return _curUserContext!!
}
+ override val currentUserContentResolver: ContentResolver
+ get() = currentUserContext.contentResolver
+
init {
userTracker = object : CurrentUserTracker(broadcastDispatcher) {
override fun onUserSwitched(newUserId: Int) {
@@ -54,8 +58,8 @@ class CurrentUserContextTracker internal constructor(
fun initialize() {
initialized = true
- _curUserContext = makeUserContext(userTracker.currentUserId)
userTracker.startTracking()
+ _curUserContext = makeUserContext(userTracker.currentUserId)
}
@VisibleForTesting
diff --git a/packages/SystemUI/src/com/android/systemui/settings/dagger/SettingsModule.java b/packages/SystemUI/src/com/android/systemui/settings/dagger/SettingsModule.java
index 2c5c3ceb6e66..eb5bd5c01a78 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/dagger/SettingsModule.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/dagger/SettingsModule.java
@@ -19,10 +19,12 @@ package com.android.systemui.settings.dagger;
import android.content.Context;
import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.settings.CurrentUserContentResolverProvider;
import com.android.systemui.settings.CurrentUserContextTracker;
import javax.inject.Singleton;
+import dagger.Binds;
import dagger.Module;
import dagger.Provides;
@@ -30,7 +32,7 @@ import dagger.Provides;
* Dagger Module for classes found within the com.android.systemui.settings package.
*/
@Module
-public interface SettingsModule {
+public abstract class SettingsModule {
/**
* Provides and initializes a CurrentUserContextTracker
@@ -45,4 +47,9 @@ public interface SettingsModule {
tracker.initialize();
return tracker;
}
+
+ @Binds
+ @Singleton
+ abstract CurrentUserContentResolverProvider bindCurrentUserContentResolverTracker(
+ CurrentUserContextTracker tracker);
}
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
index 4007abb39903..d40b666860e9 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
@@ -78,6 +78,22 @@ public class Divider extends SystemUI {
onUndockingTask();
}
}
+
+ @Override
+ public void onActivityForcedResizable(String packageName, int taskId,
+ int reason) {
+ mDividerController.onActivityForcedResizable(packageName, taskId, reason);
+ }
+
+ @Override
+ public void onActivityDismissingDockedStack() {
+ mDividerController.onActivityDismissingSplitScreen();
+ }
+
+ @Override
+ public void onActivityLaunchOnSecondaryDisplayFailed() {
+ mDividerController.onActivityLaunchOnSecondaryDisplayFailed();
+ }
}
);
}
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerController.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerController.java
index 81649f608581..1ee8abb411b9 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerController.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerController.java
@@ -50,8 +50,7 @@ import java.util.function.Consumer;
/**
* Controls the docked stack divider.
*/
-public class DividerController implements DividerView.DividerCallbacks,
- DisplayController.OnDisplaysChangedListener {
+public class DividerController implements DisplayController.OnDisplaysChangedListener {
static final boolean DEBUG = false;
private static final String TAG = "Divider";
@@ -257,8 +256,8 @@ public class DividerController implements DividerView.DividerCallbacks,
mView = (DividerView)
LayoutInflater.from(dctx).inflate(R.layout.docked_stack_divider, null);
DisplayLayout displayLayout = mDisplayController.getDisplayLayout(mContext.getDisplayId());
- mView.injectDependencies(mWindowManager, mDividerState, this, mSplits, mSplitLayout,
- mImePositionProcessor, mWindowManagerProxy);
+ mView.injectDependencies(mWindowManager, mDividerState, mForcedResizableController, mSplits,
+ mSplitLayout, mImePositionProcessor, mWindowManagerProxy);
mView.setVisibility(mVisible ? View.VISIBLE : View.INVISIBLE);
mView.setMinimizedDockStack(mMinimized, mHomeStackResizable, null /* transaction */);
final int size = dctx.getResources().getDimensionPixelSize(
@@ -397,7 +396,22 @@ public class DividerController implements DividerView.DividerCallbacks,
}
}
- /** Called when there's a task undocking. */
+ /** Called when there's an activity forced resizable. */
+ public void onActivityForcedResizable(String packageName, int taskId, int reason) {
+ mForcedResizableController.activityForcedResizable(packageName, taskId, reason);
+ }
+
+ /** Called when there's an activity dismissing split screen. */
+ public void onActivityDismissingSplitScreen() {
+ mForcedResizableController.activityDismissingSplitScreen();
+ }
+
+ /** Called when there's an activity launch on secondary display failed. */
+ public void onActivityLaunchOnSecondaryDisplayFailed() {
+ mForcedResizableController.activityLaunchOnSecondaryDisplayFailed();
+ }
+
+ /** Called when there's a task undocking. */
public void onUndockingTask() {
if (mView != null) {
mView.onUndockingTask();
@@ -426,17 +440,7 @@ public class DividerController implements DividerView.DividerCallbacks,
mForcedResizableController.onAppTransitionFinished();
}
- @Override
- public void onDraggingStart() {
- mForcedResizableController.onDraggingStart();
- }
-
- @Override
- public void onDraggingEnd() {
- mForcedResizableController.onDraggingEnd();
- }
-
- /** Dumps current status of Divider.*/
+ /** Dumps current status of Split Screen. */
public void dump(PrintWriter pw) {
pw.print(" mVisible="); pw.println(mVisible);
pw.print(" mMinimized="); pw.println(mMinimized);
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivityController.java b/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivityController.java
index f412cc00981b..ff8bab07db05 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivityController.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivityController.java
@@ -28,15 +28,13 @@ import android.util.ArraySet;
import android.widget.Toast;
import com.android.systemui.R;
-import com.android.systemui.shared.system.ActivityManagerWrapper;
-import com.android.systemui.shared.system.TaskStackChangeListener;
import java.util.function.Consumer;
/**
* Controller that decides when to show the {@link ForcedResizableInfoActivity}.
*/
-public class ForcedResizableInfoActivityController {
+final class ForcedResizableInfoActivityController implements DividerView.DividerCallbacks {
private static final String SELF_PACKAGE_NAME = "com.android.systemui";
@@ -47,12 +45,7 @@ public class ForcedResizableInfoActivityController {
private final ArraySet<String> mPackagesShownInSession = new ArraySet<>();
private boolean mDividerDragging;
- private final Runnable mTimeoutRunnable = new Runnable() {
- @Override
- public void run() {
- showPending();
- }
- };
+ private final Runnable mTimeoutRunnable = this::showPending;
private final Consumer<Boolean> mDockedStackExistsListener = exists -> {
if (!exists) {
@@ -78,44 +71,28 @@ public class ForcedResizableInfoActivityController {
public ForcedResizableInfoActivityController(Context context,
DividerController dividerController) {
mContext = context;
- ActivityManagerWrapper.getInstance().registerTaskStackListener(
- new TaskStackChangeListener() {
- @Override
- public void onActivityForcedResizable(String packageName, int taskId,
- int reason) {
- activityForcedResizable(packageName, taskId, reason);
- }
-
- @Override
- public void onActivityDismissingDockedStack() {
- activityDismissingDockedStack();
- }
-
- @Override
- public void onActivityLaunchOnSecondaryDisplayFailed() {
- activityLaunchOnSecondaryDisplayFailed();
- }
- });
dividerController.registerInSplitScreenListener(mDockedStackExistsListener);
}
- public void onAppTransitionFinished() {
- if (!mDividerDragging) {
- showPending();
- }
- }
-
- void onDraggingStart() {
+ @Override
+ public void onDraggingStart() {
mDividerDragging = true;
mHandler.removeCallbacks(mTimeoutRunnable);
}
- void onDraggingEnd() {
+ @Override
+ public void onDraggingEnd() {
mDividerDragging = false;
showPending();
}
- private void activityForcedResizable(String packageName, int taskId, int reason) {
+ void onAppTransitionFinished() {
+ if (!mDividerDragging) {
+ showPending();
+ }
+ }
+
+ void activityForcedResizable(String packageName, int taskId, int reason) {
if (debounce(packageName)) {
return;
}
@@ -123,12 +100,12 @@ public class ForcedResizableInfoActivityController {
postTimeout();
}
- private void activityDismissingDockedStack() {
+ void activityDismissingSplitScreen() {
Toast.makeText(mContext, R.string.dock_non_resizeble_failed_to_dock_text,
Toast.LENGTH_SHORT).show();
}
- private void activityLaunchOnSecondaryDisplayFailed() {
+ void activityLaunchOnSecondaryDisplayFailed() {
Toast.makeText(mContext, R.string.activity_launch_on_secondary_display_failed_text,
Toast.LENGTH_SHORT).show();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
index 99cb4760a8d9..a87311a69ab5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -2620,6 +2620,7 @@ public class NotificationPanelViewController extends PanelViewController {
super.onClosingFinished();
resetHorizontalPanelPosition();
setClosingWithAlphaFadeout(false);
+ mMediaHierarchyManager.closeGuts();
}
private void setClosingWithAlphaFadeout(boolean closing) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
index b2cfceae2cf6..8cb54eef01b4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -662,16 +662,18 @@ public class PhoneStatusBarPolicy
mIconController.setIconVisibility(mSlotCamera, showCamera);
mIconController.setIconVisibility(mSlotMicrophone, showMicrophone);
- mIconController.setIconVisibility(mSlotLocation, showLocation);
+ if (mPrivacyItemController.getAllIndicatorsAvailable()) {
+ mIconController.setIconVisibility(mSlotLocation, showLocation);
+ }
}
@Override
public void onLocationActiveChanged(boolean active) {
- if (!mPrivacyItemController.getIndicatorsAvailable()) updateLocation();
+ if (!mPrivacyItemController.getAllIndicatorsAvailable()) updateLocationFromController();
}
// Updates the status view based on the current state of location requests.
- private void updateLocation() {
+ private void updateLocationFromController() {
if (mLocationController.isLocationActive()) {
mIconController.setIconVisibility(mSlotLocation, true);
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
index b89cb210dea1..8ff7a41cb22f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
@@ -86,7 +86,7 @@ public interface StatusBarIconController {
static ArraySet<String> getIconHideList(Context context, String hideListStr) {
ArraySet<String> ret = new ArraySet<>();
String[] hideList = hideListStr == null
- ? context.getResources().getStringArray(R.array.config_statusBarIconBlackList)
+ ? context.getResources().getStringArray(R.array.config_statusBarIconsToExclude)
: hideListStr.split(",");
for (String slot : hideList) {
if (!TextUtils.isEmpty(slot)) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java
index 673549ab589f..e5a46797d035 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java
@@ -79,6 +79,13 @@ public interface BatteryController extends DemoMode, Dumpable,
default void setReverseState(boolean isReverse) {}
/**
+ * Returns {@code true} if extreme battery saver is on.
+ */
+ default boolean isExtremeSaverOn() {
+ return false;
+ }
+
+ /**
* A listener that will be notified whenever a change in battery level or power save mode has
* occurred.
*/
@@ -92,6 +99,9 @@ public interface BatteryController extends DemoMode, Dumpable,
default void onReverseChanged(boolean isReverse, int level, String name) {
}
+
+ default void onExtremeBatterySaverChanged(boolean isExtreme) {
+ }
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/usb/UsbAccessoryUriActivity.java b/packages/SystemUI/src/com/android/systemui/usb/UsbAccessoryUriActivity.java
index b5f98ad47c09..89297fd83bb0 100644
--- a/packages/SystemUI/src/com/android/systemui/usb/UsbAccessoryUriActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/usb/UsbAccessoryUriActivity.java
@@ -54,7 +54,7 @@ public class UsbAccessoryUriActivity extends AlertActivity
String uriString = intent.getStringExtra("uri");
mUri = (uriString == null ? null : Uri.parse(uriString));
- // sanity check before displaying dialog
+ // Exception check before displaying dialog
if (mUri == null) {
Log.e(TAG, "could not parse Uri " + uriString);
finish();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/CustomIconCacheTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/CustomIconCacheTest.kt
new file mode 100644
index 000000000000..4d0f2ed47495
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/CustomIconCacheTest.kt
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.controls
+
+import android.content.ComponentName
+import android.graphics.drawable.Icon
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import org.junit.Assert.assertNull
+import org.junit.Assert.assertTrue
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class CustomIconCacheTest : SysuiTestCase() {
+
+ companion object {
+ private val TEST_COMPONENT1 = ComponentName.unflattenFromString("pkg/.cls1")!!
+ private val TEST_COMPONENT2 = ComponentName.unflattenFromString("pkg/.cls2")!!
+ private const val CONTROL_ID_1 = "TEST_CONTROL_1"
+ private const val CONTROL_ID_2 = "TEST_CONTROL_2"
+ }
+
+ @Mock(stubOnly = true)
+ private lateinit var icon1: Icon
+ @Mock(stubOnly = true)
+ private lateinit var icon2: Icon
+ private lateinit var customIconCache: CustomIconCache
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+
+ customIconCache = CustomIconCache()
+ }
+
+ @Test
+ fun testIconStoredCorrectly() {
+ customIconCache.store(TEST_COMPONENT1, CONTROL_ID_1, icon1)
+
+ assertTrue(icon1 === customIconCache.retrieve(TEST_COMPONENT1, CONTROL_ID_1))
+ }
+
+ @Test
+ fun testIconNotStoredReturnsNull() {
+ customIconCache.store(TEST_COMPONENT1, CONTROL_ID_1, icon1)
+
+ assertNull(customIconCache.retrieve(TEST_COMPONENT1, CONTROL_ID_2))
+ }
+
+ @Test
+ fun testWrongComponentReturnsNull() {
+ customIconCache.store(TEST_COMPONENT1, CONTROL_ID_1, icon1)
+
+ assertNull(customIconCache.retrieve(TEST_COMPONENT2, CONTROL_ID_1))
+ }
+
+ @Test
+ fun testChangeComponentOldComponentIsRemoved() {
+ customIconCache.store(TEST_COMPONENT1, CONTROL_ID_1, icon1)
+ customIconCache.store(TEST_COMPONENT2, CONTROL_ID_2, icon2)
+
+ assertNull(customIconCache.retrieve(TEST_COMPONENT1, CONTROL_ID_1))
+ assertNull(customIconCache.retrieve(TEST_COMPONENT1, CONTROL_ID_2))
+ }
+
+ @Test
+ fun testChangeComponentCorrectIconRetrieved() {
+ customIconCache.store(TEST_COMPONENT1, CONTROL_ID_1, icon1)
+ customIconCache.store(TEST_COMPONENT2, CONTROL_ID_1, icon2)
+
+ assertTrue(icon2 === customIconCache.retrieve(TEST_COMPONENT2, CONTROL_ID_1))
+ }
+
+ @Test
+ fun testStoreNull() {
+ customIconCache.store(TEST_COMPONENT1, CONTROL_ID_1, icon1)
+ customIconCache.store(TEST_COMPONENT1, CONTROL_ID_1, null)
+
+ assertNull(customIconCache.retrieve(TEST_COMPONENT1, CONTROL_ID_1))
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/management/FavoritesModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/management/FavoritesModelTest.kt
index ce33a8d49fac..f0003ed603ab 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/management/FavoritesModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/management/FavoritesModelTest.kt
@@ -22,6 +22,7 @@ import androidx.recyclerview.widget.RecyclerView
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.controls.ControlInterface
+import com.android.systemui.controls.CustomIconCache
import com.android.systemui.controls.controller.ControlInfo
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.eq
@@ -57,6 +58,8 @@ class FavoritesModelTest : SysuiTestCase() {
private lateinit var callback: FavoritesModel.FavoritesModelCallback
@Mock
private lateinit var adapter: RecyclerView.Adapter<*>
+ @Mock
+ private lateinit var customIconCache: CustomIconCache
private lateinit var model: FavoritesModel
private lateinit var dividerWrapper: DividerWrapper
@@ -64,7 +67,7 @@ class FavoritesModelTest : SysuiTestCase() {
fun setUp() {
MockitoAnnotations.initMocks(this)
- model = FavoritesModel(TEST_COMPONENT, INITIAL_FAVORITES, callback)
+ model = FavoritesModel(customIconCache, TEST_COMPONENT, INITIAL_FAVORITES, callback)
model.attachAdapter(adapter)
dividerWrapper = model.elements.first { it is DividerWrapper } as DividerWrapper
}
@@ -89,7 +92,7 @@ class FavoritesModelTest : SysuiTestCase() {
@Test
fun testInitialElements() {
val expected = INITIAL_FAVORITES.map {
- ControlInfoWrapper(TEST_COMPONENT, it, true)
+ ControlInfoWrapper(TEST_COMPONENT, it, true, customIconCache::retrieve)
} + DividerWrapper()
assertEquals(expected, model.elements)
}
@@ -287,5 +290,13 @@ class FavoritesModelTest : SysuiTestCase() {
verify(callback).onFirstChange()
}
+ @Test
+ fun testCacheCalledWhenGettingCustomIcon() {
+ val wrapper = model.elements[0] as ControlInfoWrapper
+ wrapper.customIcon
+
+ verify(customIconCache).retrieve(TEST_COMPONENT, wrapper.controlId)
+ }
+
private fun getDividerPosition(): Int = model.elements.indexOf(dividerWrapper)
} \ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogTest.java
index ac8c6710e041..4c5495474018 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogTest.java
@@ -88,7 +88,7 @@ import java.util.concurrent.Executor;
@SmallTest
@RunWith(AndroidTestingRunner.class)
-@TestableLooper.RunWithLooper()
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
public class GlobalActionsDialogTest extends SysuiTestCase {
private GlobalActionsDialog mGlobalActionsDialog;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt
index c63781cb110a..8a30b00e609d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt
@@ -16,6 +16,7 @@
package com.android.systemui.media
+import android.content.Intent
import android.content.res.ColorStateList
import android.graphics.Color
import android.graphics.drawable.GradientDrawable
@@ -23,6 +24,7 @@ import android.graphics.drawable.RippleDrawable
import android.media.MediaMetadata
import android.media.session.MediaSession
import android.media.session.PlaybackState
+import android.provider.Settings.ACTION_MEDIA_CONTROLS_SETTINGS
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import android.view.View
@@ -35,24 +37,31 @@ import android.widget.TextView
import androidx.constraintlayout.widget.ConstraintSet
import androidx.lifecycle.LiveData
import androidx.test.filters.SmallTest
-import com.android.systemui.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.plugins.ActivityStarter
+import com.android.systemui.statusbar.phone.KeyguardDismissUtil
import com.android.systemui.util.animation.TransitionLayout
import com.android.systemui.util.concurrency.FakeExecutor
+import com.android.systemui.util.mockito.eq
+import com.android.systemui.util.mockito.any
import com.android.systemui.util.time.FakeSystemClock
import com.google.common.truth.Truth.assertThat
+import dagger.Lazy
import org.junit.After
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
+import org.mockito.ArgumentMatchers
+import org.mockito.ArgumentMatchers.anyLong
import org.mockito.Mock
+import org.mockito.Mockito.anyBoolean
import org.mockito.Mockito.mock
+import org.mockito.Mockito.never
import org.mockito.Mockito.verify
-import org.mockito.Mockito.`when` as whenever
import org.mockito.junit.MockitoJUnit
+import org.mockito.Mockito.`when` as whenever
private const val KEY = "TEST_KEY"
private const val APP = "APP"
@@ -81,6 +90,8 @@ public class MediaControlPanelTest : SysuiTestCase() {
@Mock private lateinit var seekBarViewModel: SeekBarViewModel
@Mock private lateinit var seekBarData: LiveData<SeekBarViewModel.Progress>
@Mock private lateinit var mediaViewController: MediaViewController
+ @Mock private lateinit var keyguardDismissUtil: KeyguardDismissUtil
+ @Mock private lateinit var mediaDataManager: MediaDataManager
@Mock private lateinit var expandedSet: ConstraintSet
@Mock private lateinit var collapsedSet: ConstraintSet
private lateinit var appIcon: ImageView
@@ -100,6 +111,9 @@ public class MediaControlPanelTest : SysuiTestCase() {
private lateinit var action2: ImageButton
private lateinit var action3: ImageButton
private lateinit var action4: ImageButton
+ private lateinit var settings: View
+ private lateinit var cancel: View
+ private lateinit var dismiss: View
private lateinit var session: MediaSession
private val device = MediaDeviceData(true, null, DEVICE_NAME)
@@ -114,7 +128,7 @@ public class MediaControlPanelTest : SysuiTestCase() {
whenever(mediaViewController.collapsedLayout).thenReturn(collapsedSet)
player = MediaControlPanel(context, bgExecutor, activityStarter, mediaViewController,
- seekBarViewModel)
+ seekBarViewModel, Lazy { mediaDataManager }, keyguardDismissUtil)
whenever(seekBarViewModel.progress).thenReturn(seekBarData)
// Mock out a view holder for the player to attach to.
@@ -156,6 +170,12 @@ public class MediaControlPanelTest : SysuiTestCase() {
whenever(holder.action3).thenReturn(action3)
action4 = ImageButton(context)
whenever(holder.action4).thenReturn(action4)
+ settings = View(context)
+ whenever(holder.settings).thenReturn(settings)
+ cancel = View(context)
+ whenever(holder.cancel).thenReturn(cancel)
+ dismiss = View(context)
+ whenever(holder.dismiss).thenReturn(dismiss)
// Create media session
val metadataBuilder = MediaMetadata.Builder().apply {
@@ -254,4 +274,79 @@ public class MediaControlPanelTest : SysuiTestCase() {
assertThat(seamlessText.getText()).isEqualTo(DEVICE_NAME)
assertThat(seamless.isEnabled()).isFalse()
}
+
+ @Test
+ fun longClick_gutsClosed() {
+ player.attach(holder)
+ whenever(mediaViewController.isGutsVisible).thenReturn(false)
+
+ val captor = ArgumentCaptor.forClass(View.OnLongClickListener::class.java)
+ verify(holder.player).setOnLongClickListener(captor.capture())
+
+ captor.value.onLongClick(holder.player)
+ verify(mediaViewController).openGuts()
+ }
+
+ @Test
+ fun longClick_gutsOpen() {
+ player.attach(holder)
+ whenever(mediaViewController.isGutsVisible).thenReturn(true)
+
+ val captor = ArgumentCaptor.forClass(View.OnLongClickListener::class.java)
+ verify(holder.player).setOnLongClickListener(captor.capture())
+
+ captor.value.onLongClick(holder.player)
+ verify(mediaViewController, never()).openGuts()
+ }
+
+ @Test
+ fun cancelButtonClick_animation() {
+ player.attach(holder)
+
+ cancel.callOnClick()
+
+ verify(mediaViewController).closeGuts(false)
+ }
+
+ @Test
+ fun settingsButtonClick() {
+ player.attach(holder)
+
+ settings.callOnClick()
+
+ val captor = ArgumentCaptor.forClass(Intent::class.java)
+ verify(activityStarter).startActivity(captor.capture(), eq(true))
+
+ assertThat(captor.value.action).isEqualTo(ACTION_MEDIA_CONTROLS_SETTINGS)
+ }
+
+ @Test
+ fun dismissButtonClick() {
+ player.attach(holder)
+ val state = MediaData(USER_ID, true, BG_COLOR, APP, null, ARTIST, TITLE, null, emptyList(),
+ emptyList(), PACKAGE, session.getSessionToken(), null, null, true, null,
+ notificationKey = KEY)
+ player.bind(state)
+
+ dismiss.callOnClick()
+ val captor = ArgumentCaptor.forClass(ActivityStarter.OnDismissAction::class.java)
+ verify(keyguardDismissUtil).executeWhenUnlocked(captor.capture(), anyBoolean())
+
+ captor.value.onDismiss()
+ verify(mediaDataManager).dismissMediaData(eq(KEY), anyLong())
+ }
+
+ @Test
+ fun dismissButtonClick_nullNotificationKey() {
+ player.attach(holder)
+ val state = MediaData(USER_ID, true, BG_COLOR, APP, null, ARTIST, TITLE, null, emptyList(),
+ emptyList(), PACKAGE, session.getSessionToken(), null, null, true, null)
+ player.bind(state)
+
+ verify(keyguardDismissUtil, never())
+ .executeWhenUnlocked(
+ any(ActivityStarter.OnDismissAction::class.java),
+ ArgumentMatchers.anyBoolean()
+ )
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt
index 59c2d0e86c56..3789e6ef1f65 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt
@@ -217,6 +217,20 @@ class MediaDataManagerTest : SysuiTestCase() {
assertThat(data.actions).hasSize(1)
}
+ @Test
+ fun testDismissMedia_listenerCalled() {
+ val listener = mock(MediaDataManager.Listener::class.java)
+ mediaDataManager.addListener(listener)
+ mediaDataManager.onNotificationAdded(KEY, mediaNotification)
+ mediaDataManager.onMediaDataLoaded(KEY, oldKey = null, data = mock(MediaData::class.java))
+ mediaDataManager.dismissMediaData(KEY, 0L)
+
+ foregroundExecutor.advanceClockToLast()
+ foregroundExecutor.runAllReady()
+
+ verify(listener).onMediaDataRemoved(eq(KEY))
+ }
+
/**
* Simple implementation of [MediaDataManager.Listener] for the test.
*
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaHierarchyManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaHierarchyManagerTest.kt
index 91c5ff8ee627..d86dfa5fa5f7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaHierarchyManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaHierarchyManagerTest.kt
@@ -142,4 +142,11 @@ class MediaHierarchyManagerTest : SysuiTestCase() {
verify(mediaCarouselController).onDesiredLocationChanged(ArgumentMatchers.anyInt(),
any(MediaHostState::class.java), anyBoolean(), anyLong(), anyLong())
}
+
+ @Test
+ fun testCloseGutsRelayToCarousel() {
+ mediaHiearchyManager.closeGuts()
+
+ verify(mediaCarouselController).closeGuts()
+ }
} \ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/pip/phone/PipTouchHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/pip/phone/PipTouchHandlerTest.java
index 96bb521a5d5b..9f67722041aa 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/pip/phone/PipTouchHandlerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/pip/phone/PipTouchHandlerTest.java
@@ -37,6 +37,7 @@ import com.android.systemui.model.SysUiState;
import com.android.systemui.pip.PipBoundsHandler;
import com.android.systemui.pip.PipSnapAlgorithm;
import com.android.systemui.pip.PipTaskOrganizer;
+import com.android.systemui.pip.PipUiEventLogger;
import com.android.systemui.shared.system.InputConsumerController;
import com.android.systemui.util.DeviceConfigProxy;
import com.android.systemui.util.FloatingContentCoordinator;
@@ -85,6 +86,9 @@ public class PipTouchHandlerTest extends SysuiTestCase {
@Mock
private SysUiState mSysUiState;
+ @Mock
+ private PipUiEventLogger mPipUiEventLogger;
+
private PipSnapAlgorithm mPipSnapAlgorithm;
private PipMotionHelper mMotionHelper;
private PipResizeGestureHandler mPipResizeGestureHandler;
@@ -104,7 +108,7 @@ public class PipTouchHandlerTest extends SysuiTestCase {
mPipTouchHandler = new PipTouchHandler(mContext, mActivityManager,
mPipMenuActivityController, mInputConsumerController, mPipBoundsHandler,
mPipTaskOrganizer, mFloatingContentCoordinator, mDeviceConfigProxy,
- mPipSnapAlgorithm, mSysUiState);
+ mPipSnapAlgorithm, mSysUiState, mPipUiEventLogger);
mMotionHelper = Mockito.spy(mPipTouchHandler.getMotionHelper());
mPipResizeGestureHandler = Mockito.spy(mPipTouchHandler.getPipResizeGestureHandler());
mPipTouchHandler.setPipMotionHelper(mMotionHelper);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerFlagsTest.kt b/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerFlagsTest.kt
new file mode 100644
index 000000000000..4ba29e6e02a6
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerFlagsTest.kt
@@ -0,0 +1,219 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.privacy
+
+import android.os.UserManager
+import android.provider.DeviceConfig
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.internal.config.sysui.SystemUiDeviceConfigFlags
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.appops.AppOpsController
+import com.android.systemui.broadcast.BroadcastDispatcher
+import com.android.systemui.dump.DumpManager
+import com.android.systemui.util.DeviceConfigProxy
+import com.android.systemui.util.DeviceConfigProxyFake
+import com.android.systemui.util.concurrency.FakeExecutor
+import com.android.systemui.util.time.FakeSystemClock
+import org.junit.Assert.assertFalse
+import org.junit.Assert.assertTrue
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentCaptor
+import org.mockito.Mock
+import org.mockito.Mockito
+import org.mockito.Mockito.anyBoolean
+import org.mockito.Mockito.atLeastOnce
+import org.mockito.Mockito.never
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+class PrivacyItemControllerFlagsTest : SysuiTestCase() {
+ companion object {
+ fun <T> capture(argumentCaptor: ArgumentCaptor<T>): T = argumentCaptor.capture()
+ fun <T> eq(value: T): T = Mockito.eq(value) ?: value
+ fun <T> any(): T = Mockito.any<T>()
+
+ private const val ALL_INDICATORS =
+ SystemUiDeviceConfigFlags.PROPERTY_PERMISSIONS_HUB_ENABLED
+ private const val MIC_CAMERA = SystemUiDeviceConfigFlags.PROPERTY_MIC_CAMERA_ENABLED
+ }
+
+ @Mock
+ private lateinit var appOpsController: AppOpsController
+ @Mock
+ private lateinit var callback: PrivacyItemController.Callback
+ @Mock
+ private lateinit var userManager: UserManager
+ @Mock
+ private lateinit var broadcastDispatcher: BroadcastDispatcher
+ @Mock
+ private lateinit var dumpManager: DumpManager
+
+ private lateinit var privacyItemController: PrivacyItemController
+ private lateinit var executor: FakeExecutor
+ private lateinit var deviceConfigProxy: DeviceConfigProxy
+
+ fun PrivacyItemController(): PrivacyItemController {
+ return PrivacyItemController(
+ appOpsController,
+ executor,
+ executor,
+ broadcastDispatcher,
+ deviceConfigProxy,
+ userManager,
+ dumpManager
+ )
+ }
+
+ @Before
+ fun setup() {
+ MockitoAnnotations.initMocks(this)
+ executor = FakeExecutor(FakeSystemClock())
+ deviceConfigProxy = DeviceConfigProxyFake()
+
+ privacyItemController = PrivacyItemController()
+ privacyItemController.addCallback(callback)
+
+ executor.runAllReady()
+ }
+
+ @Test
+ fun testNotListeningByDefault() {
+ assertFalse(privacyItemController.allIndicatorsAvailable)
+ assertFalse(privacyItemController.micCameraAvailable)
+
+ verify(appOpsController, never()).addCallback(any(), any())
+ }
+
+ @Test
+ fun testMicCameraChanged() {
+ changeMicCamera(true)
+ executor.runAllReady()
+
+ verify(callback).onFlagMicCameraChanged(true)
+ verify(callback, never()).onFlagAllChanged(anyBoolean())
+
+ assertTrue(privacyItemController.micCameraAvailable)
+ assertFalse(privacyItemController.allIndicatorsAvailable)
+ }
+
+ @Test
+ fun testAllChanged() {
+ changeAll(true)
+ executor.runAllReady()
+
+ verify(callback).onFlagAllChanged(true)
+ verify(callback, never()).onFlagMicCameraChanged(anyBoolean())
+
+ assertTrue(privacyItemController.allIndicatorsAvailable)
+ assertFalse(privacyItemController.micCameraAvailable)
+ }
+
+ @Test
+ fun testBothChanged() {
+ changeAll(true)
+ changeMicCamera(true)
+ executor.runAllReady()
+
+ verify(callback, atLeastOnce()).onFlagAllChanged(true)
+ verify(callback, atLeastOnce()).onFlagMicCameraChanged(true)
+
+ assertTrue(privacyItemController.allIndicatorsAvailable)
+ assertTrue(privacyItemController.micCameraAvailable)
+ }
+
+ @Test
+ fun testAll_listeningToAll() {
+ changeAll(true)
+ executor.runAllReady()
+
+ verify(appOpsController).addCallback(eq(PrivacyItemController.OPS), any())
+ }
+
+ @Test
+ fun testMicCamera_listening() {
+ changeMicCamera(true)
+ executor.runAllReady()
+
+ verify(appOpsController).addCallback(eq(PrivacyItemController.OPS), any())
+ }
+
+ @Test
+ fun testAll_listening() {
+ changeAll(true)
+ executor.runAllReady()
+
+ verify(appOpsController).addCallback(eq(PrivacyItemController.OPS), any())
+ }
+
+ @Test
+ fun testAllFalse_notListening() {
+ changeAll(true)
+ executor.runAllReady()
+ changeAll(false)
+ executor.runAllReady()
+
+ verify(appOpsController).removeCallback(any(), any())
+ }
+
+ @Test
+ fun testSomeListening_stillListening() {
+ changeAll(true)
+ changeMicCamera(true)
+ executor.runAllReady()
+ changeAll(false)
+ executor.runAllReady()
+
+ verify(appOpsController, never()).removeCallback(any(), any())
+ }
+
+ @Test
+ fun testAllDeleted_stopListening() {
+ changeAll(true)
+ executor.runAllReady()
+ changeAll(null)
+ executor.runAllReady()
+
+ verify(appOpsController).removeCallback(any(), any())
+ }
+
+ @Test
+ fun testMicDeleted_stopListening() {
+ changeMicCamera(true)
+ executor.runAllReady()
+ changeMicCamera(null)
+ executor.runAllReady()
+
+ verify(appOpsController).removeCallback(any(), any())
+ }
+
+ private fun changeMicCamera(value: Boolean?) = changeProperty(MIC_CAMERA, value)
+ private fun changeAll(value: Boolean?) = changeProperty(ALL_INDICATORS, value)
+
+ private fun changeProperty(name: String, value: Boolean?) {
+ deviceConfigProxy.setProperty(
+ DeviceConfig.NAMESPACE_PRIVACY,
+ name,
+ value?.toString(),
+ false
+ )
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerTest.kt
index dddc35072315..fb42baaa0cb5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerTest.kt
@@ -18,7 +18,6 @@ package com.android.systemui.privacy
import android.app.ActivityManager
import android.app.AppOpsManager
-import android.content.Context
import android.content.Intent
import android.content.pm.UserInfo
import android.os.UserHandle
@@ -69,10 +68,11 @@ class PrivacyItemControllerTest : SysuiTestCase() {
companion object {
val CURRENT_USER_ID = ActivityManager.getCurrentUser()
val TEST_UID = CURRENT_USER_ID * UserHandle.PER_USER_RANGE
- const val SYSTEM_UID = 1000
const val TEST_PACKAGE_NAME = "test"
- const val DEVICE_SERVICES_STRING = "Device services"
- const val TAG = "PrivacyItemControllerTest"
+
+ private const val ALL_INDICATORS =
+ SystemUiDeviceConfigFlags.PROPERTY_PERMISSIONS_HUB_ENABLED
+ private const val MIC_CAMERA = SystemUiDeviceConfigFlags.PROPERTY_MIC_CAMERA_ENABLED
fun <T> capture(argumentCaptor: ArgumentCaptor<T>): T = argumentCaptor.capture()
fun <T> eq(value: T): T = Mockito.eq(value) ?: value
fun <T> any(): T = Mockito.any<T>()
@@ -97,9 +97,8 @@ class PrivacyItemControllerTest : SysuiTestCase() {
private lateinit var executor: FakeExecutor
private lateinit var deviceConfigProxy: DeviceConfigProxy
- fun PrivacyItemController(context: Context): PrivacyItemController {
+ fun PrivacyItemController(): PrivacyItemController {
return PrivacyItemController(
- context,
appOpsController,
executor,
executor,
@@ -116,11 +115,8 @@ class PrivacyItemControllerTest : SysuiTestCase() {
executor = FakeExecutor(FakeSystemClock())
deviceConfigProxy = DeviceConfigProxyFake()
- appOpsController = mDependency.injectMockDependency(AppOpsController::class.java)
-
- deviceConfigProxy.setProperty(DeviceConfig.NAMESPACE_PRIVACY,
- SystemUiDeviceConfigFlags.PROPERTY_PERMISSIONS_HUB_ENABLED,
- "true", false)
+ // Listen to everything by default
+ changeAll(true)
doReturn(listOf(object : UserInfo() {
init {
@@ -128,7 +124,7 @@ class PrivacyItemControllerTest : SysuiTestCase() {
}
})).`when`(userManager).getProfiles(anyInt())
- privacyItemController = PrivacyItemController(mContext)
+ privacyItemController = PrivacyItemController()
}
@Test
@@ -276,15 +272,59 @@ class PrivacyItemControllerTest : SysuiTestCase() {
@Test
fun testNotListeningWhenIndicatorsDisabled() {
- deviceConfigProxy.setProperty(
- DeviceConfig.NAMESPACE_PRIVACY,
- SystemUiDeviceConfigFlags.PROPERTY_PERMISSIONS_HUB_ENABLED,
- "false",
- false
- )
+ changeAll(false)
privacyItemController.addCallback(callback)
executor.runAllReady()
verify(appOpsController, never()).addCallback(eq(PrivacyItemController.OPS),
any())
}
+
+ @Test
+ fun testNotSendingLocationWhenOnlyMicCamera() {
+ changeAll(false)
+ changeMicCamera(true)
+ executor.runAllReady()
+
+ doReturn(listOf(AppOpItem(AppOpsManager.OP_CAMERA, TEST_UID, "", 0),
+ AppOpItem(AppOpsManager.OP_COARSE_LOCATION, TEST_UID, "", 0)))
+ .`when`(appOpsController).getActiveAppOpsForUser(anyInt())
+
+ privacyItemController.addCallback(callback)
+ executor.runAllReady()
+
+ verify(callback).onPrivacyItemsChanged(capture(argCaptor))
+
+ assertEquals(1, argCaptor.value.size)
+ assertEquals(PrivacyType.TYPE_CAMERA, argCaptor.value[0].privacyType)
+ }
+
+ @Test
+ fun testNotUpdated_LocationChangeWhenOnlyMicCamera() {
+ doReturn(listOf(AppOpItem(AppOpsManager.OP_COARSE_LOCATION, TEST_UID, "", 0)))
+ .`when`(appOpsController).getActiveAppOpsForUser(anyInt())
+
+ privacyItemController.addCallback(callback)
+ changeAll(false)
+ changeMicCamera(true)
+ executor.runAllReady()
+ reset(callback) // Clean callback
+
+ verify(appOpsController).addCallback(any(), capture(argCaptorCallback))
+ argCaptorCallback.value.onActiveStateChanged(
+ AppOpsManager.OP_FINE_LOCATION, TEST_UID, TEST_PACKAGE_NAME, true)
+
+ verify(callback, never()).onPrivacyItemsChanged(any())
+ }
+
+ private fun changeMicCamera(value: Boolean?) = changeProperty(MIC_CAMERA, value)
+ private fun changeAll(value: Boolean?) = changeProperty(ALL_INDICATORS, value)
+
+ private fun changeProperty(name: String, value: Boolean?) {
+ deviceConfigProxy.setProperty(
+ DeviceConfig.NAMESPACE_PRIVACY,
+ name,
+ value?.toString(),
+ false
+ )
+ }
} \ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java
index 103e5586f395..cccb65d11228 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java
@@ -74,7 +74,7 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@RunWith(AndroidTestingRunner.class)
-@RunWithLooper
+@RunWithLooper(setAsMainLooper = true)
@SmallTest
public class QSTileImplTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ScreenRecordTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ScreenRecordTileTest.java
index 2d276bb876f3..6b54791dd143 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ScreenRecordTileTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ScreenRecordTileTest.java
@@ -47,7 +47,7 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@RunWith(AndroidTestingRunner.class)
-@TestableLooper.RunWithLooper()
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
@SmallTest
public class ScreenRecordTileTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragmentTest.java
index ae87eefd243c..781f875fd868 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragmentTest.java
@@ -41,7 +41,7 @@ import org.junit.runner.RunWith;
import org.mockito.Mockito;
@RunWith(AndroidTestingRunner.class)
-@RunWithLooper()
+@RunWithLooper(setAsMainLooper = true)
@SmallTest
public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CallbackControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CallbackControllerTest.java
index a16fb5e8dc17..86dacc13feab 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CallbackControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CallbackControllerTest.java
@@ -37,7 +37,7 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
-@RunWithLooper
+@RunWithLooper(setAsMainLooper = true)
@RunWith(AndroidTestingRunner.class)
@SmallTest
public class CallbackControllerTest extends SysuiTestCase {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/LifecycleFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/LifecycleFragmentTest.java
index 0e1c560c918b..b2f57d0726cc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/LifecycleFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/LifecycleFragmentTest.java
@@ -39,7 +39,7 @@ import com.android.systemui.SysuiBaseFragmentTest;
import org.junit.Test;
import org.junit.runner.RunWith;
-@RunWithLooper
+@RunWithLooper(setAsMainLooper = true)
@RunWith(AndroidTestingRunner.class)
@SmallTest
public class LifecycleFragmentTest extends SysuiBaseFragmentTest {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/SysuiLifecycleTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/SysuiLifecycleTest.java
index 486939d1f08e..4f509eaaadde 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/SysuiLifecycleTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/SysuiLifecycleTest.java
@@ -49,7 +49,7 @@ import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
-@RunWithLooper
+@RunWithLooper(setAsMainLooper = true)
@RunWith(AndroidTestingRunner.class)
@SmallTest
public class SysuiLifecycleTest extends SysuiTestCase {
diff --git a/packages/Tethering/res/values/config.xml b/packages/Tethering/res/values/config.xml
index 9b9dcde910e7..5f8d2997197f 100644
--- a/packages/Tethering/res/values/config.xml
+++ b/packages/Tethering/res/values/config.xml
@@ -73,6 +73,9 @@
<!-- Use the old dnsmasq DHCP server for tethering instead of the framework implementation. -->
<bool translatable="false" name="config_tether_enable_legacy_dhcp_server">false</bool>
+ <!-- Use legacy wifi p2p dedicated address instead of randomize address. -->
+ <bool translatable="false" name="config_tether_enable_legacy_wifi_p2p_dedicated_ip">false</bool>
+
<!-- Dhcp range (min, max) to use for tethering purposes -->
<string-array translatable="false" name="config_tether_dhcp_range">
</string-array>
diff --git a/packages/Tethering/res/values/overlayable.xml b/packages/Tethering/res/values/overlayable.xml
index 6a33d55cb0de..0ee7a992ee20 100644
--- a/packages/Tethering/res/values/overlayable.xml
+++ b/packages/Tethering/res/values/overlayable.xml
@@ -30,6 +30,7 @@
-->
<item type="bool" name="config_tether_enable_bpf_offload"/>
<item type="bool" name="config_tether_enable_legacy_dhcp_server"/>
+ <item type="bool" name="config_tether_enable_legacy_wifi_p2p_dedicated_ip"/>
<item type="integer" name="config_tether_offload_poll_interval"/>
<item type="array" name="config_tether_upstream_types"/>
<item type="bool" name="config_tether_upstream_automatic"/>
diff --git a/packages/Tethering/src/com/android/networkstack/tethering/PrivateAddressCoordinator.java b/packages/Tethering/src/com/android/networkstack/tethering/PrivateAddressCoordinator.java
index aa58a4b6a320..fd9e36080c80 100644
--- a/packages/Tethering/src/com/android/networkstack/tethering/PrivateAddressCoordinator.java
+++ b/packages/Tethering/src/com/android/networkstack/tethering/PrivateAddressCoordinator.java
@@ -15,6 +15,8 @@
*/
package com.android.networkstack.tethering;
+import static android.net.TetheringManager.TETHERING_WIFI_P2P;
+
import static java.util.Arrays.asList;
import android.content.Context;
@@ -58,6 +60,7 @@ public class PrivateAddressCoordinator {
private static final int BYTE_MASK = 0xff;
// reserved for bluetooth tethering.
private static final int BLUETOOTH_RESERVED = 44;
+ private static final int WIFI_P2P_RESERVED = 49;
private static final byte DEFAULT_ID = (byte) 42;
// Upstream monitor would be stopped when tethering is down. When tethering restart, downstream
@@ -71,15 +74,18 @@ public class PrivateAddressCoordinator {
// 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16
// Tethering use 192.168.0.0/16 that has 256 contiguous class C network numbers.
private static final String DEFAULT_TETHERING_PREFIX = "192.168.0.0/16";
+ private static final String LEGACY_WIFI_P2P_IFACE_ADDRESS = "192.168.49.1/24";
private final IpPrefix mTetheringPrefix;
private final ConnectivityManager mConnectivityMgr;
+ private final TetheringConfiguration mConfig;
- public PrivateAddressCoordinator(Context context) {
+ public PrivateAddressCoordinator(Context context, TetheringConfiguration config) {
mDownstreams = new ArraySet<>();
mUpstreamPrefixMap = new ArrayMap<>();
mTetheringPrefix = new IpPrefix(DEFAULT_TETHERING_PREFIX);
mConnectivityMgr = (ConnectivityManager) context.getSystemService(
Context.CONNECTIVITY_SERVICE);
+ mConfig = config;
}
/**
@@ -141,12 +147,21 @@ public class PrivateAddressCoordinator {
mUpstreamPrefixMap.removeAll(toBeRemoved);
}
+ private boolean isReservedSubnet(final int subnet) {
+ return subnet == BLUETOOTH_RESERVED || subnet == WIFI_P2P_RESERVED;
+ }
+
/**
* Pick a random available address and mark its prefix as in use for the provided IpServer,
* returns null if there is no available address.
*/
@Nullable
public LinkAddress requestDownstreamAddress(final IpServer ipServer) {
+ if (mConfig.shouldEnableWifiP2pDedicatedIp()
+ && ipServer.interfaceType() == TETHERING_WIFI_P2P) {
+ return new LinkAddress(LEGACY_WIFI_P2P_IFACE_ADDRESS);
+ }
+
// Address would be 192.168.[subAddress]/24.
final byte[] bytes = mTetheringPrefix.getRawAddress();
final int subAddress = getRandomSubAddr();
@@ -154,7 +169,7 @@ public class PrivateAddressCoordinator {
bytes[3] = getSanitizedAddressSuffix(subAddress, (byte) 0, (byte) 1, (byte) 0xff);
for (int i = 0; i < MAX_UBYTE; i++) {
final int newSubNet = (subNet + i) & BYTE_MASK;
- if (newSubNet == BLUETOOTH_RESERVED) continue;
+ if (isReservedSubnet(newSubNet)) continue;
bytes[2] = (byte) newSubNet;
final InetAddress addr;
diff --git a/packages/Tethering/src/com/android/networkstack/tethering/Tethering.java b/packages/Tethering/src/com/android/networkstack/tethering/Tethering.java
index cfc657587332..7dd5290ee83b 100644
--- a/packages/Tethering/src/com/android/networkstack/tethering/Tethering.java
+++ b/packages/Tethering/src/com/android/networkstack/tethering/Tethering.java
@@ -320,10 +320,13 @@ public class Tethering {
mExecutor = new TetheringThreadExecutor(mHandler);
mActiveDataSubIdListener = new ActiveDataSubIdListener(mExecutor);
mNetdCallback = new NetdCallback();
- mPrivateAddressCoordinator = new PrivateAddressCoordinator(mContext);
// Load tethering configuration.
updateConfiguration();
+ // It is OK for the configuration to be passed to the PrivateAddressCoordinator at
+ // construction time because the only part of the configuration it uses is
+ // shouldEnableWifiP2pDedicatedIp(), and currently do not support changing that.
+ mPrivateAddressCoordinator = new PrivateAddressCoordinator(mContext, mConfig);
// Must be initialized after tethering configuration is loaded because BpfCoordinator
// constructor needs to use the configuration.
diff --git a/packages/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java b/packages/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java
index e1771a561370..5783805861a3 100644
--- a/packages/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java
+++ b/packages/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java
@@ -84,6 +84,9 @@ public class TetheringConfiguration {
public static final String TETHER_ENABLE_LEGACY_DHCP_SERVER =
"tether_enable_legacy_dhcp_server";
+ public static final String USE_LEGACY_WIFI_P2P_DEDICATED_IP =
+ "use_legacy_wifi_p2p_dedicated_ip";
+
/**
* Default value that used to periodic polls tether offload stats from tethering offload HAL
* to make the data warnings work.
@@ -113,6 +116,7 @@ public class TetheringConfiguration {
private final int mOffloadPollInterval;
// TODO: Add to TetheringConfigurationParcel if required.
private final boolean mEnableBpfOffload;
+ private final boolean mEnableWifiP2pDedicatedIp;
public TetheringConfiguration(Context ctx, SharedLog log, int id) {
final SharedLog configLog = log.forSubComponent("config");
@@ -156,6 +160,10 @@ public class TetheringConfiguration {
R.integer.config_tether_offload_poll_interval,
DEFAULT_TETHER_OFFLOAD_POLL_INTERVAL_MS);
+ mEnableWifiP2pDedicatedIp = getResourceBoolean(res,
+ R.bool.config_tether_enable_legacy_wifi_p2p_dedicated_ip,
+ false /* defaultValue */);
+
configLog.log(toString());
}
@@ -199,6 +207,11 @@ public class TetheringConfiguration {
return !TextUtils.isEmpty(provisioningAppNoUi);
}
+ /** Check whether dedicated wifi p2p address is enabled. */
+ public boolean shouldEnableWifiP2pDedicatedIp() {
+ return mEnableWifiP2pDedicatedIp;
+ }
+
/** Does the dumping.*/
public void dump(PrintWriter pw) {
pw.print("activeDataSubId: ");
@@ -233,6 +246,9 @@ public class TetheringConfiguration {
pw.print("enableLegacyDhcpServer: ");
pw.println(enableLegacyDhcpServer);
+
+ pw.print("enableWifiP2pDedicatedIp: ");
+ pw.println(mEnableWifiP2pDedicatedIp);
}
/** Returns the string representation of this object.*/
diff --git a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java
index 2c0df6fc6327..8e93c2e447b3 100644
--- a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java
+++ b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java
@@ -15,6 +15,11 @@
*/
package com.android.networkstack.tethering;
+import static android.net.TetheringManager.TETHERING_ETHERNET;
+import static android.net.TetheringManager.TETHERING_USB;
+import static android.net.TetheringManager.TETHERING_WIFI;
+import static android.net.TetheringManager.TETHERING_WIFI_P2P;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.mockito.Mockito.never;
@@ -54,22 +59,34 @@ public final class PrivateAddressCoordinatorTest {
@Mock private IpServer mHotspotIpServer;
@Mock private IpServer mUsbIpServer;
@Mock private IpServer mEthernetIpServer;
+ @Mock private IpServer mWifiP2pIpServer;
@Mock private Context mContext;
@Mock private ConnectivityManager mConnectivityMgr;
+ @Mock private TetheringConfiguration mConfig;
private PrivateAddressCoordinator mPrivateAddressCoordinator;
private final IpPrefix mBluetoothPrefix = new IpPrefix("192.168.44.0/24");
+ private final LinkAddress mLegacyWifiP2pAddress = new LinkAddress("192.168.49.1/24");
private final Network mWifiNetwork = new Network(1);
private final Network mMobileNetwork = new Network(2);
private final Network[] mAllNetworks = {mMobileNetwork, mWifiNetwork};
+ private void setUpIpServers() throws Exception {
+ when(mUsbIpServer.interfaceType()).thenReturn(TETHERING_USB);
+ when(mEthernetIpServer.interfaceType()).thenReturn(TETHERING_ETHERNET);
+ when(mHotspotIpServer.interfaceType()).thenReturn(TETHERING_WIFI);
+ when(mWifiP2pIpServer.interfaceType()).thenReturn(TETHERING_WIFI_P2P);
+ }
+
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
when(mContext.getSystemService(Context.CONNECTIVITY_SERVICE)).thenReturn(mConnectivityMgr);
when(mConnectivityMgr.getAllNetworks()).thenReturn(mAllNetworks);
- mPrivateAddressCoordinator = spy(new PrivateAddressCoordinator(mContext));
+ when(mConfig.shouldEnableWifiP2pDedicatedIp()).thenReturn(false);
+ setUpIpServers();
+ mPrivateAddressCoordinator = spy(new PrivateAddressCoordinator(mContext, mConfig));
}
@Test
@@ -256,4 +273,38 @@ public final class PrivateAddressCoordinatorTest {
final IpPrefix ethPrefix = PrefixUtils.asIpPrefix(ethAddr);
assertEquals(predefinedPrefix, ethPrefix);
}
+
+ private int getSubAddress(final byte... ipv4Address) {
+ assertEquals(4, ipv4Address.length);
+
+ int subnet = Byte.toUnsignedInt(ipv4Address[2]);
+ return (subnet << 8) + ipv4Address[3];
+ }
+
+ private void assertReseveredWifiP2pPrefix() throws Exception {
+ LinkAddress address = mPrivateAddressCoordinator.requestDownstreamAddress(
+ mHotspotIpServer);
+ final IpPrefix hotspotPrefix = PrefixUtils.asIpPrefix(address);
+ final IpPrefix legacyWifiP2pPrefix = PrefixUtils.asIpPrefix(mLegacyWifiP2pAddress);
+ assertNotEquals(legacyWifiP2pPrefix, hotspotPrefix);
+ mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer);
+ }
+
+ @Test
+ public void testEnableLegacyWifiP2PAddress() throws Exception {
+ when(mPrivateAddressCoordinator.getRandomSubAddr()).thenReturn(
+ getSubAddress(mLegacyWifiP2pAddress.getAddress().getAddress()));
+ // No matter #shouldEnableWifiP2pDedicatedIp() is enabled or not, legacy wifi p2p prefix
+ // is resevered.
+ assertReseveredWifiP2pPrefix();
+
+ when(mConfig.shouldEnableWifiP2pDedicatedIp()).thenReturn(true);
+ assertReseveredWifiP2pPrefix();
+
+ // If #shouldEnableWifiP2pDedicatedIp() is enabled, wifi P2P gets the configured address.
+ LinkAddress address = mPrivateAddressCoordinator.requestDownstreamAddress(
+ mWifiP2pIpServer);
+ assertEquals(mLegacyWifiP2pAddress, address);
+ mPrivateAddressCoordinator.releaseDownstream(mWifiP2pIpServer);
+ }
}
diff --git a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringConfigurationTest.java b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringConfigurationTest.java
index a9ac4e2851f3..dc0940cc0222 100644
--- a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringConfigurationTest.java
+++ b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringConfigurationTest.java
@@ -128,6 +128,8 @@ public class TetheringConfigurationTest {
.thenReturn(new String[0]);
when(mResources.getBoolean(R.bool.config_tether_enable_legacy_dhcp_server)).thenReturn(
false);
+ when(mResources.getBoolean(R.bool.config_tether_enable_legacy_wifi_p2p_dedicated_ip))
+ .thenReturn(false);
initializeBpfOffloadConfiguration(true, null /* unset */);
mHasTelephonyManager = true;
@@ -413,4 +415,17 @@ public class TetheringConfigurationTest {
R.string.config_mobile_hotspot_provision_response)).thenReturn(
PROVISIONING_APP_RESPONSE);
}
+
+ @Test
+ public void testEnableLegacyWifiP2PAddress() throws Exception {
+ final TetheringConfiguration defaultCfg = new TetheringConfiguration(
+ mMockContext, mLog, INVALID_SUBSCRIPTION_ID);
+ assertFalse(defaultCfg.shouldEnableWifiP2pDedicatedIp());
+
+ when(mResources.getBoolean(R.bool.config_tether_enable_legacy_wifi_p2p_dedicated_ip))
+ .thenReturn(true);
+ final TetheringConfiguration testCfg = new TetheringConfiguration(
+ mMockContext, mLog, INVALID_SUBSCRIPTION_ID);
+ assertTrue(testCfg.shouldEnableWifiP2pDedicatedIp());
+ }
}
diff --git a/proto/src/metrics_constants/metrics_constants.proto b/proto/src/metrics_constants/metrics_constants.proto
index b0e401bdda8a..3f712dd1492f 100644
--- a/proto/src/metrics_constants/metrics_constants.proto
+++ b/proto/src/metrics_constants/metrics_constants.proto
@@ -3706,33 +3706,40 @@ message MetricsEvent {
// OS: O
BACKUP_SETTINGS = 818;
+ // DEPRECATED: The metrics has been migrated to UiEvent per go/uievent.
// ACTION: Picture-in-picture was explicitly entered for an activity
// VALUE: true if it was entered while hiding as a result of moving to
// another task, false otherwise
- ACTION_PICTURE_IN_PICTURE_ENTERED = 819;
+ ACTION_PICTURE_IN_PICTURE_ENTERED = 819 [deprecated=true];
+ // DEPRECATED: The metrics has been migrated to UiEvent per go/uievent.
// ACTION: The activity currently in picture-in-picture was expanded back to fullscreen
// PACKAGE: The package name of the activity that was expanded back to fullscreen
- ACTION_PICTURE_IN_PICTURE_EXPANDED_TO_FULLSCREEN = 820;
+ ACTION_PICTURE_IN_PICTURE_EXPANDED_TO_FULLSCREEN = 820 [deprecated=true];
+ // DEPRECATED: The metrics no longer used after migration to UiEvent per go/uievent.
// ACTION: The activity currently in picture-in-picture was minimized
// VALUE: True if the PiP was minimized, false otherwise
- ACTION_PICTURE_IN_PICTURE_MINIMIZED = 821;
+ ACTION_PICTURE_IN_PICTURE_MINIMIZED = 821 [deprecated=true];
+ // DEPRECATED: The metrics has been migrated to UiEvent per go/uievent.
// ACTION: Picture-in-picture was dismissed via the dismiss button
// VALUE: 0 if dismissed by tap, 1 if dismissed by drag
- ACTION_PICTURE_IN_PICTURE_DISMISSED = 822;
+ ACTION_PICTURE_IN_PICTURE_DISMISSED = 822 [deprecated=true];
- // ACTION: The visibility of the picture-in-picture meny
+ // DEPRECATED: The metrics has been migrated to UiEvent per go/uievent.
+ // ACTION: The visibility of the picture-in-picture menu
// VALUE: Whether or not the menu is visible
- ACTION_PICTURE_IN_PICTURE_MENU = 823;
+ ACTION_PICTURE_IN_PICTURE_MENU = 823 [deprecated=true];
+ // DEPRECATED: The metrics has been migrated to UiEvent per go/uievent.
// Enclosing category for group of PICTURE_IN_PICTURE_ASPECT_RATIO_FOO events,
// logged when the aspect ratio changes
- ACTION_PICTURE_IN_PICTURE_ASPECT_RATIO_CHANGED = 824;
+ ACTION_PICTURE_IN_PICTURE_ASPECT_RATIO_CHANGED = 824 [deprecated=true];
+ // DEPRECATED: The metrics no longer used after migration to UiEvent per go/uievent.
// The current aspect ratio of the PiP, logged when it changes.
- PICTURE_IN_PICTURE_ASPECT_RATIO = 825;
+ PICTURE_IN_PICTURE_ASPECT_RATIO = 825 [deprecated=true];
// FIELD - length in dp of ACTION_LS_* gestures, or zero if not applicable
// CATEGORY: GLOBAL_SYSTEM_UI
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 2cd4c6939fa9..b1340228ffa0 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -443,7 +443,11 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
if (reboundAService || configurationChanged) {
onUserStateChangedLocked(userState);
}
- migrateAccessibilityButtonSettingsIfNecessaryLocked(userState, packageName);
+ // Passing 0 for restoreFromSdkInt to have this migration check execute each
+ // time. It can make sure a11y button settings are correctly if there's an a11y
+ // service updated and modifies the a11y button configuration.
+ migrateAccessibilityButtonSettingsIfNecessaryLocked(userState, packageName,
+ /* restoreFromSdkInt = */0);
}
}
@@ -554,7 +558,9 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
synchronized (mLock) {
restoreEnabledAccessibilityServicesLocked(
intent.getStringExtra(Intent.EXTRA_SETTING_PREVIOUS_VALUE),
- intent.getStringExtra(Intent.EXTRA_SETTING_NEW_VALUE));
+ intent.getStringExtra(Intent.EXTRA_SETTING_NEW_VALUE),
+ intent.getIntExtra(Intent.EXTRA_SETTING_RESTORED_FROM_SDK_INT,
+ 0));
}
} else if (ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED.equals(which)) {
synchronized (mLock) {
@@ -563,6 +569,12 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
intent.getIntExtra(Intent.EXTRA_SETTING_RESTORED_FROM_SDK_INT,
0));
}
+ } else if (Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS.equals(which)) {
+ synchronized (mLock) {
+ restoreAccessibilityButtonTargetsLocked(
+ intent.getStringExtra(Intent.EXTRA_SETTING_PREVIOUS_VALUE),
+ intent.getStringExtra(Intent.EXTRA_SETTING_NEW_VALUE));
+ }
}
}
}
@@ -588,7 +600,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
final AccessibilityUserState userState = getUserStateLocked(UserHandle.USER_SYSTEM);
final Set<String> targetsFromSetting = new ArraySet<>();
readColonDelimitedSettingToSet(Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS,
- userState.mUserId, targetsFromSetting, str -> str);
+ userState.mUserId, str -> str, targetsFromSetting);
final boolean targetsContainMagnification = targetsFromSetting.contains(
MAGNIFICATION_CONTROLLER_NAME);
if (targetsContainMagnification == displayMagnificationNavBarEnabled) {
@@ -1189,7 +1201,14 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
// the state since the context in which the current user
// state was used has changed since it was inactive.
onUserStateChangedLocked(userState);
- migrateAccessibilityButtonSettingsIfNecessaryLocked(userState, null);
+ // It's better to have this migration in SettingsProvider. Unfortunately,
+ // SettingsProvider migrated database in a very early stage which A11yManagerService
+ // haven't finished or started the initialization. We cannot get enough information from
+ // A11yManagerService to execute these migrations in SettingsProvider. Passing 0 for
+ // restoreFromSdkInt to have this migration check execute every time, because we did not
+ // find out a way to detect the device finished the OTA and switch the user.
+ migrateAccessibilityButtonSettingsIfNecessaryLocked(userState, null,
+ /* restoreFromSdkInt = */0);
if (announceNewUser) {
// Schedule announcement of the current user if needed.
@@ -1234,7 +1253,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
// Called only during settings restore; currently supports only the owner user
// TODO: http://b/22388012
- void restoreEnabledAccessibilityServicesLocked(String oldSetting, String newSetting) {
+ void restoreEnabledAccessibilityServicesLocked(String oldSetting, String newSetting,
+ int restoreFromSdkInt) {
readComponentNamesFromStringLocked(oldSetting, mTempComponentNameSet, false);
readComponentNamesFromStringLocked(newSetting, mTempComponentNameSet, true);
@@ -1246,7 +1266,32 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
userState.mEnabledServices,
UserHandle.USER_SYSTEM);
onUserStateChangedLocked(userState);
- migrateAccessibilityButtonSettingsIfNecessaryLocked(userState, null);
+ migrateAccessibilityButtonSettingsIfNecessaryLocked(userState, null, restoreFromSdkInt);
+ }
+
+ /**
+ * User could enable accessibility services and configure accessibility button during the SUW.
+ * Merges current value of accessibility button settings into the restored one to make sure
+ * user's preferences of accessibility button updated in SUW are not lost.
+ *
+ * Called only during settings restore; currently supports only the owner user
+ * TODO: http://b/22388012
+ */
+ void restoreAccessibilityButtonTargetsLocked(String oldSetting, String newSetting) {
+ final Set<String> targetsFromSetting = new ArraySet<>();
+ readColonDelimitedStringToSet(oldSetting, str -> str, targetsFromSetting,
+ /* doMerge = */false);
+ readColonDelimitedStringToSet(newSetting, str -> str, targetsFromSetting,
+ /* doMerge = */true);
+
+ final AccessibilityUserState userState = getUserStateLocked(UserHandle.USER_SYSTEM);
+ userState.mAccessibilityButtonTargets.clear();
+ userState.mAccessibilityButtonTargets.addAll(targetsFromSetting);
+ persistColonDelimitedSetToSettingLocked(Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS,
+ UserHandle.USER_SYSTEM, userState.mAccessibilityButtonTargets, str -> str);
+
+ scheduleNotifyClientsOfServicesStateChangeLocked(userState);
+ onUserStateChangedLocked(userState);
}
private int getClientStateLocked(AccessibilityUserState userState) {
@@ -1569,8 +1614,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
*/
private void readComponentNamesFromSettingLocked(String settingName, int userId,
Set<ComponentName> outComponentNames) {
- readColonDelimitedSettingToSet(settingName, userId, outComponentNames,
- str -> ComponentName.unflattenFromString(str));
+ readColonDelimitedSettingToSet(settingName, userId,
+ str -> ComponentName.unflattenFromString(str), outComponentNames);
}
/**
@@ -1585,8 +1630,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
private void readComponentNamesFromStringLocked(String names,
Set<ComponentName> outComponentNames,
boolean doMerge) {
- readColonDelimitedStringToSet(names, outComponentNames, doMerge,
- str -> ComponentName.unflattenFromString(str));
+ readColonDelimitedStringToSet(names, str -> ComponentName.unflattenFromString(str),
+ outComponentNames, doMerge);
}
@Override
@@ -1596,15 +1641,15 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
componentName -> componentName.flattenToShortString());
}
- private <T> void readColonDelimitedSettingToSet(String settingName, int userId, Set<T> outSet,
- Function<String, T> toItem) {
+ private <T> void readColonDelimitedSettingToSet(String settingName, int userId,
+ Function<String, T> toItem, Set<T> outSet) {
final String settingValue = Settings.Secure.getStringForUser(mContext.getContentResolver(),
settingName, userId);
- readColonDelimitedStringToSet(settingValue, outSet, false, toItem);
+ readColonDelimitedStringToSet(settingValue, toItem, outSet, false);
}
- private <T> void readColonDelimitedStringToSet(String names, Set<T> outSet, boolean doMerge,
- Function<String, T> toItem) {
+ private <T> void readColonDelimitedStringToSet(String names, Function<String, T> toItem,
+ Set<T> outSet, boolean doMerge) {
if (!doMerge) {
outSet.clear();
}
@@ -2104,7 +2149,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
final String settingValue = Settings.Secure.getStringForUser(mContext.getContentResolver(),
Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, userState.mUserId);
final Set<String> targetsFromSetting = new ArraySet<>();
- readColonDelimitedStringToSet(settingValue, targetsFromSetting, false, str -> str);
+ readColonDelimitedStringToSet(settingValue, str -> str, targetsFromSetting, false);
// Fall back to device's default a11y service, only when setting is never updated.
if (settingValue == null) {
final String defaultService = mContext.getString(
@@ -2128,7 +2173,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
private boolean readAccessibilityButtonTargetsLocked(AccessibilityUserState userState) {
final Set<String> targetsFromSetting = new ArraySet<>();
readColonDelimitedSettingToSet(Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS,
- userState.mUserId, targetsFromSetting, str -> str);
+ userState.mUserId, str -> str, targetsFromSetting);
final Set<String> currentTargets =
userState.getShortcutTargetsLocked(ACCESSIBILITY_BUTTON);
@@ -2392,9 +2437,15 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
* (It happens when an enabled accessibility service package is upgraded.)
*
* @param packageName The package name to check, or {@code null} to check all services.
+ * @param restoreFromSdkInt The target sdk version of the restored source device, or {@code 0}
+ * if the caller is not related to the restore.
*/
private void migrateAccessibilityButtonSettingsIfNecessaryLocked(
- AccessibilityUserState userState, @Nullable String packageName) {
+ AccessibilityUserState userState, @Nullable String packageName, int restoreFromSdkInt) {
+ // No need to migrate settings if they are restored from a version after Q.
+ if (restoreFromSdkInt > Build.VERSION_CODES.Q) {
+ return;
+ }
final Set<String> buttonTargets =
userState.getShortcutTargetsLocked(ACCESSIBILITY_BUTTON);
int lastSize = buttonTargets.size();
diff --git a/services/core/Android.bp b/services/core/Android.bp
index 1093515ac525..e76ec743661c 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -79,6 +79,7 @@ java_library_static {
":framework_native_aidl",
":gsiservice_aidl",
":idmap2_aidl",
+ ":inputconstants_aidl",
":installd_aidl",
":storaged_aidl",
":vold_aidl",
diff --git a/services/core/java/android/os/BatteryStatsInternal.java b/services/core/java/android/os/BatteryStatsInternal.java
index 7cf5fd621f18..b7fed87d570d 100644
--- a/services/core/java/android/os/BatteryStatsInternal.java
+++ b/services/core/java/android/os/BatteryStatsInternal.java
@@ -50,5 +50,5 @@ public abstract class BatteryStatsInternal {
* Informs battery stats of binder stats for the given work source UID.
*/
public abstract void noteBinderCallStats(int workSourceUid, long incrementalBinderCallCount,
- Collection<BinderCallsStats.CallStat> callStats);
+ Collection<BinderCallsStats.CallStat> callStats, int[] binderThreadNativeTids);
}
diff --git a/services/core/java/com/android/server/UiModeManagerService.java b/services/core/java/com/android/server/UiModeManagerService.java
index df9dee89f5a2..6dbb1e922f60 100644
--- a/services/core/java/com/android/server/UiModeManagerService.java
+++ b/services/core/java/com/android/server/UiModeManagerService.java
@@ -137,6 +137,7 @@ final class UiModeManagerService extends SystemService {
int mCurUiMode = 0;
private int mSetUiMode = 0;
private boolean mHoldingConfiguration = false;
+ private int mCurrentUser;
private Configuration mConfiguration = new Configuration();
boolean mSystemReady;
@@ -325,6 +326,7 @@ final class UiModeManagerService extends SystemService {
@Override
public void onUserSwitching(@Nullable TargetUser from, @NonNull TargetUser to) {
+ mCurrentUser = to.getUserIdentifier();
getContext().getContentResolver().unregisterContentObserver(mSetupWizardObserver);
verifySetupWizardCompleted();
}
@@ -727,16 +729,30 @@ final class UiModeManagerService extends SystemService {
@Override
public boolean setNightModeActivated(boolean active) {
+ if (isNightModeLocked() && (getContext().checkCallingOrSelfPermission(
+ android.Manifest.permission.MODIFY_DAY_NIGHT_MODE)
+ != PackageManager.PERMISSION_GRANTED)) {
+ Slog.e(TAG, "Night mode locked, requires MODIFY_DAY_NIGHT_MODE permission");
+ return false;
+ }
+ final int user = Binder.getCallingUserHandle().getIdentifier();
+ if (user != mCurrentUser && getContext().checkCallingOrSelfPermission(
+ android.Manifest.permission.INTERACT_ACROSS_USERS)
+ != PackageManager.PERMISSION_GRANTED) {
+ Slog.e(TAG, "Target user is not current user,"
+ + " INTERACT_ACROSS_USERS permission is required");
+ return false;
+
+ }
synchronized (mLock) {
- final int user = UserHandle.getCallingUserId();
final long ident = Binder.clearCallingIdentity();
try {
if (mNightMode == MODE_NIGHT_AUTO || mNightMode == MODE_NIGHT_CUSTOM) {
unregisterScreenOffEventLocked();
mOverrideNightModeOff = !active;
mOverrideNightModeOn = active;
- mOverrideNightModeUser = user;
- persistNightModeOverrides(user);
+ mOverrideNightModeUser = mCurrentUser;
+ persistNightModeOverrides(mCurrentUser);
} else if (mNightMode == UiModeManager.MODE_NIGHT_NO
&& active) {
mNightMode = UiModeManager.MODE_NIGHT_YES;
@@ -746,7 +762,7 @@ final class UiModeManagerService extends SystemService {
}
updateConfigurationLocked();
applyConfigurationExternallyLocked();
- persistNightMode(user);
+ persistNightMode(mCurrentUser);
return true;
} finally {
Binder.restoreCallingIdentity(ident);
diff --git a/services/core/java/com/android/server/VibratorService.java b/services/core/java/com/android/server/VibratorService.java
index 72f29b431880..2534a535079e 100644
--- a/services/core/java/com/android/server/VibratorService.java
+++ b/services/core/java/com/android/server/VibratorService.java
@@ -76,6 +76,8 @@ import com.android.internal.app.IBatteryStats;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.FrameworkStatsLog;
+import libcore.util.NativeAllocationRegistry;
+
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -115,7 +117,6 @@ public class VibratorService extends IVibratorService.Stub
// If HAL supports callbacks set the timeout to ASYNC_TIMEOUT_MULTIPLIER * duration.
private static final long ASYNC_TIMEOUT_MULTIPLIER = 2;
-
// A mapping from the intensity adjustment to the scaling to apply, where the intensity
// adjustment is defined as the delta between the default intensity level and the user selected
// intensity level. It's important that we apply the scaling on the delta between the two so
@@ -128,8 +129,6 @@ public class VibratorService extends IVibratorService.Stub
private final LinkedList<VibrationInfo> mPreviousVibrations;
private final int mPreviousVibrationsLimit;
private final boolean mAllowPriorityVibrationsInLowPowerMode;
- private final boolean mSupportsAmplitudeControl;
- private final boolean mSupportsExternalControl;
private final List<Integer> mSupportedEffects;
private final long mCapabilities;
private final int mDefaultVibrationAmplitude;
@@ -174,22 +173,23 @@ public class VibratorService extends IVibratorService.Stub
private int mRingIntensity;
private SparseArray<Vibration> mAlwaysOnEffects = new SparseArray<>();
- static native boolean vibratorExists();
- static native void vibratorInit();
+ static native long vibratorInit();
+
+ static native long vibratorGetFinalizer();
+ static native boolean vibratorExists(long controllerPtr);
static native void vibratorOn(long milliseconds);
- static native void vibratorOff();
- static native boolean vibratorSupportsAmplitudeControl();
- static native void vibratorSetAmplitude(int amplitude);
- static native int[] vibratorGetSupportedEffects();
+ static native void vibratorOff(long controllerPtr);
+ static native void vibratorSetAmplitude(long controllerPtr, int amplitude);
+ static native int[] vibratorGetSupportedEffects(long controllerPtr);
static native long vibratorPerformEffect(long effect, long strength, Vibration vibration,
boolean withCallback);
static native void vibratorPerformComposedEffect(
VibrationEffect.Composition.PrimitiveEffect[] effect, Vibration vibration);
- static native boolean vibratorSupportsExternalControl();
- static native void vibratorSetExternalControl(boolean enabled);
- static native long vibratorGetCapabilities();
- static native void vibratorAlwaysOnEnable(long id, long effect, long strength);
- static native void vibratorAlwaysOnDisable(long id);
+ static native void vibratorSetExternalControl(long controllerPtr, boolean enabled);
+ static native long vibratorGetCapabilities(long controllerPtr);
+ static native void vibratorAlwaysOnEnable(long controllerPtr, long id, long effect,
+ long strength);
+ static native void vibratorAlwaysOnDisable(long controllerPtr, long id);
private final IUidObserver mUidObserver = new IUidObserver.Stub() {
@Override public void onUidStateChanged(int uid, int procState, long procStateSeq,
@@ -370,13 +370,20 @@ public class VibratorService extends IVibratorService.Stub
mNativeWrapper = injector.getNativeWrapper();
mH = injector.createHandler(Looper.myLooper());
- mNativeWrapper.vibratorInit();
+ long controllerPtr = mNativeWrapper.vibratorInit();
+ long finalizerPtr = mNativeWrapper.vibratorGetFinalizer();
+
+ if (finalizerPtr != 0) {
+ NativeAllocationRegistry registry =
+ NativeAllocationRegistry.createMalloced(
+ VibratorService.class.getClassLoader(), finalizerPtr);
+ registry.registerNativeAllocation(this, controllerPtr);
+ }
+
// Reset the hardware to a default state, in case this is a runtime
// restart instead of a fresh boot.
mNativeWrapper.vibratorOff();
- mSupportsAmplitudeControl = mNativeWrapper.vibratorSupportsAmplitudeControl();
- mSupportsExternalControl = mNativeWrapper.vibratorSupportsExternalControl();
mSupportedEffects = asList(mNativeWrapper.vibratorGetSupportedEffects());
mCapabilities = mNativeWrapper.vibratorGetCapabilities();
@@ -605,7 +612,8 @@ public class VibratorService extends IVibratorService.Stub
synchronized (mInputDeviceVibrators) {
// Input device vibrators don't support amplitude controls yet, but are still used over
// the system vibrator when connected.
- return mSupportsAmplitudeControl && mInputDeviceVibrators.isEmpty();
+ return hasCapability(IVibrator.CAP_AMPLITUDE_CONTROL)
+ && mInputDeviceVibrators.isEmpty();
}
}
@@ -1288,7 +1296,7 @@ public class VibratorService extends IVibratorService.Stub
}
private void doVibratorSetAmplitude(int amplitude) {
- if (mSupportsAmplitudeControl) {
+ if (hasCapability(IVibrator.CAP_AMPLITUDE_CONTROL)) {
mNativeWrapper.vibratorSetAmplitude(amplitude);
}
}
@@ -1708,14 +1716,25 @@ public class VibratorService extends IVibratorService.Stub
@VisibleForTesting
public static class NativeWrapper {
+ private long mNativeControllerPtr = 0;
+
/** Checks if vibrator exists on device. */
public boolean vibratorExists() {
- return VibratorService.vibratorExists();
+ return VibratorService.vibratorExists(mNativeControllerPtr);
}
- /** Initializes connection to vibrator HAL service. */
- public void vibratorInit() {
- VibratorService.vibratorInit();
+ /**
+ * Returns native pointer to newly created controller and initializes connection to vibrator
+ * HAL service.
+ */
+ public long vibratorInit() {
+ mNativeControllerPtr = VibratorService.vibratorInit();
+ return mNativeControllerPtr;
+ }
+
+ /** Returns pointer to native finalizer function to be called by GC. */
+ public long vibratorGetFinalizer() {
+ return VibratorService.vibratorGetFinalizer();
}
/** Turns vibrator on for given time. */
@@ -1725,22 +1744,17 @@ public class VibratorService extends IVibratorService.Stub
/** Turns vibrator off. */
public void vibratorOff() {
- VibratorService.vibratorOff();
- }
-
- /** Returns true if vibrator supports {@link #vibratorSetAmplitude(int)}. */
- public boolean vibratorSupportsAmplitudeControl() {
- return VibratorService.vibratorSupportsAmplitudeControl();
+ VibratorService.vibratorOff(mNativeControllerPtr);
}
/** Sets the amplitude for the vibrator to run. */
public void vibratorSetAmplitude(int amplitude) {
- VibratorService.vibratorSetAmplitude(amplitude);
+ VibratorService.vibratorSetAmplitude(mNativeControllerPtr, amplitude);
}
/** Returns all predefined effects supported by the device vibrator. */
public int[] vibratorGetSupportedEffects() {
- return VibratorService.vibratorGetSupportedEffects();
+ return VibratorService.vibratorGetSupportedEffects(mNativeControllerPtr);
}
/** Turns vibrator on to perform one of the supported effects. */
@@ -1755,29 +1769,24 @@ public class VibratorService extends IVibratorService.Stub
VibratorService.vibratorPerformComposedEffect(effect, vibration);
}
- /** Returns true if vibrator supports {@link #vibratorSetExternalControl(boolean)}. */
- public boolean vibratorSupportsExternalControl() {
- return VibratorService.vibratorSupportsExternalControl();
- }
-
/** Enabled the device vibrator to be controlled by another service. */
public void vibratorSetExternalControl(boolean enabled) {
- VibratorService.vibratorSetExternalControl(enabled);
+ VibratorService.vibratorSetExternalControl(mNativeControllerPtr, enabled);
}
/** Returns all capabilities of the device vibrator. */
public long vibratorGetCapabilities() {
- return VibratorService.vibratorGetCapabilities();
+ return VibratorService.vibratorGetCapabilities(mNativeControllerPtr);
}
/** Enable always-on vibration with given id and effect. */
public void vibratorAlwaysOnEnable(long id, long effect, long strength) {
- VibratorService.vibratorAlwaysOnEnable(id, effect, strength);
+ VibratorService.vibratorAlwaysOnEnable(mNativeControllerPtr, id, effect, strength);
}
/** Disable always-on vibration for given id. */
public void vibratorAlwaysOnDisable(long id) {
- VibratorService.vibratorAlwaysOnDisable(id);
+ VibratorService.vibratorAlwaysOnDisable(mNativeControllerPtr, id);
}
}
@@ -1852,7 +1861,7 @@ public class VibratorService extends IVibratorService.Stub
@Override
public int onExternalVibrationStart(ExternalVibration vib) {
- if (!mSupportsExternalControl) {
+ if (!hasCapability(IVibrator.CAP_EXTERNAL_CONTROL)) {
return SCALE_MUTE;
}
if (ActivityManager.checkComponentPermission(android.Manifest.permission.VIBRATE,
@@ -2142,10 +2151,10 @@ public class VibratorService extends IVibratorService.Stub
if (hasCapability(IVibrator.CAP_COMPOSE_EFFECTS)) {
pw.println(" Compose effects");
}
- if (mSupportsAmplitudeControl || hasCapability(IVibrator.CAP_AMPLITUDE_CONTROL)) {
+ if (hasCapability(IVibrator.CAP_AMPLITUDE_CONTROL)) {
pw.println(" Amplitude control");
}
- if (mSupportsExternalControl || hasCapability(IVibrator.CAP_EXTERNAL_CONTROL)) {
+ if (hasCapability(IVibrator.CAP_EXTERNAL_CONTROL)) {
pw.println(" External control");
}
if (hasCapability(IVibrator.CAP_EXTERNAL_AMPLITUDE_CONTROL)) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index c187772df6e4..91a1487c5245 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -41,6 +41,7 @@ import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.os.FactoryTest.FACTORY_TEST_OFF;
+import static android.os.IInputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_CRITICAL;
import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_HIGH;
import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_NORMAL;
@@ -130,10 +131,10 @@ import static com.android.server.wm.ActivityTaskManagerService.DUMP_LASTANR_TRAC
import static com.android.server.wm.ActivityTaskManagerService.DUMP_RECENTS_CMD;
import static com.android.server.wm.ActivityTaskManagerService.DUMP_RECENTS_SHORT_CMD;
import static com.android.server.wm.ActivityTaskManagerService.DUMP_STARTER_CMD;
-import static com.android.server.wm.ActivityTaskManagerService.KEY_DISPATCHING_TIMEOUT_MS;
import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_NONE;
import static com.android.server.wm.ActivityTaskManagerService.relaunchReasonToString;
+
import android.Manifest;
import android.Manifest.permission;
import android.annotation.BroadcastBehavior;
@@ -1955,7 +1956,7 @@ public class ActivityManagerService extends IActivityManager.Stub
nativeTotalPss += Debug.getPss(stats.get(j).pid, null, null);
}
memInfo.readMemInfo();
- synchronized (ActivityManagerService.this) {
+ synchronized (mProcessStats.mLock) {
if (DEBUG_PSS) Slog.d(TAG_PSS, "Collected native and kernel memory in "
+ (SystemClock.uptimeMillis()-start) + "ms");
final long cachedKb = memInfo.getCachedSizeKb();
@@ -7047,9 +7048,7 @@ public class ActivityManagerService extends IActivityManager.Stub
mUsageStatsService.prepareShutdown();
}
mBatteryStatsService.shutdown();
- synchronized (this) {
- mProcessStats.shutdownLocked();
- }
+ mProcessStats.shutdown();
return timedout;
}
@@ -12351,7 +12350,7 @@ public class ActivityManagerService extends IActivityManager.Stub
MemInfoReader memInfo = new MemInfoReader();
memInfo.readMemInfo();
if (nativeProcTotalPss > 0) {
- synchronized (this) {
+ synchronized (mProcessStats.mLock) {
final long cachedKb = memInfo.getCachedSizeKb();
final long freeKb = memInfo.getFreeSizeKb();
final long zramKb = memInfo.getZramTotalSizeKb();
@@ -12933,7 +12932,7 @@ public class ActivityManagerService extends IActivityManager.Stub
MemInfoReader memInfo = new MemInfoReader();
memInfo.readMemInfo();
if (nativeProcTotalPss > 0) {
- synchronized (this) {
+ synchronized (mProcessStats.mLock) {
final long cachedKb = memInfo.getCachedSizeKb();
final long freeKb = memInfo.getFreeSizeKb();
final long zramKb = memInfo.getZramTotalSizeKb();
@@ -16504,9 +16503,7 @@ public class ActivityManagerService extends IActivityManager.Stub
}
@Override public void run() {
- synchronized (mService) {
- mProcessStats.writeStateAsyncLocked();
- }
+ mProcessStats.writeStateAsync();
}
}
@@ -16556,9 +16553,13 @@ public class ActivityManagerService extends IActivityManager.Stub
}
mLastMemoryLevel = memFactor;
mLastNumProcesses = mProcessList.getLruSizeLocked();
- boolean allChanged = mProcessStats.setMemFactorLocked(
- memFactor, mAtmInternal != null ? !mAtmInternal.isSleeping() : true, now);
- final int trackerMemFactor = mProcessStats.getMemFactorLocked();
+ boolean allChanged;
+ int trackerMemFactor;
+ synchronized (mProcessStats.mLock) {
+ allChanged = mProcessStats.setMemFactorLocked(
+ memFactor, mAtmInternal != null ? !mAtmInternal.isSleeping() : true, now);
+ trackerMemFactor = mProcessStats.getMemFactorLocked();
+ }
if (memFactor != ProcessStats.ADJ_MEM_FACTOR_NORMAL) {
if (mLowRamStartTime == 0) {
mLowRamStartTime = now;
@@ -18353,19 +18354,20 @@ public class ActivityManagerService extends IActivityManager.Stub
throw new SecurityException("Requires permission " + FILTER_EVENTS);
}
ProcessRecord proc;
- long timeout;
+ long timeoutMillis;
synchronized (this) {
synchronized (mPidsSelfLocked) {
proc = mPidsSelfLocked.get(pid);
}
- timeout = proc != null ? proc.getInputDispatchingTimeout() : KEY_DISPATCHING_TIMEOUT_MS;
+ timeoutMillis = proc != null ? proc.getInputDispatchingTimeoutMillis() :
+ DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
}
if (inputDispatchingTimedOut(proc, null, null, null, null, aboveSystem, reason)) {
- return -1;
+ return 0;
}
- return timeout;
+ return timeoutMillis;
}
/**
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 5081b360b4fe..d72998ba95f1 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -227,8 +227,9 @@ public final class BatteryStatsService extends IBatteryStats.Stub
@Override
public void noteBinderCallStats(int workSourceUid, long incrementatCallCount,
- Collection<BinderCallsStats.CallStat> callStats) {
- mStats.noteBinderCallStats(workSourceUid, incrementatCallCount, callStats);
+ Collection<BinderCallsStats.CallStat> callStats, int[] binderThreadNativeTids) {
+ mStats.noteBinderCallStats(workSourceUid, incrementatCallCount, callStats,
+ binderThreadNativeTids);
}
}
diff --git a/services/core/java/com/android/server/am/CoreSettingsObserver.java b/services/core/java/com/android/server/am/CoreSettingsObserver.java
index 8970ec4c7bb7..0f2dfcc699e2 100644
--- a/services/core/java/com/android/server/am/CoreSettingsObserver.java
+++ b/services/core/java/com/android/server/am/CoreSettingsObserver.java
@@ -116,6 +116,10 @@ final class CoreSettingsObserver extends ContentObserver {
WidgetFlags.KEY_ENABLE_CURSOR_DRAG_FROM_ANYWHERE, boolean.class,
WidgetFlags.ENABLE_CURSOR_DRAG_FROM_ANYWHERE_DEFAULT));
sDeviceConfigEntries.add(new DeviceConfigEntry<Integer>(
+ DeviceConfig.NAMESPACE_WIDGET, WidgetFlags.CURSOR_DRAG_MIN_ANGLE_FROM_VERTICAL,
+ WidgetFlags.KEY_CURSOR_DRAG_MIN_ANGLE_FROM_VERTICAL, int.class,
+ WidgetFlags.CURSOR_DRAG_MIN_ANGLE_FROM_VERTICAL_DEFAULT));
+ sDeviceConfigEntries.add(new DeviceConfigEntry<Integer>(
DeviceConfig.NAMESPACE_WIDGET, WidgetFlags.FINGER_TO_CURSOR_DISTANCE,
WidgetFlags.KEY_FINGER_TO_CURSOR_DISTANCE, int.class,
WidgetFlags.FINGER_TO_CURSOR_DISTANCE_DEFAULT));
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index f0343e1d807c..bf15f1737cfc 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -659,13 +659,15 @@ public final class OomAdjuster {
updateUidsLocked(activeUids, nowElapsed);
- if (mService.mProcessStats.shouldWriteNowLocked(now)) {
- mService.mHandler.post(new ActivityManagerService.ProcStatsRunnable(mService,
- mService.mProcessStats));
- }
+ synchronized (mService.mProcessStats.mLock) {
+ if (mService.mProcessStats.shouldWriteNowLocked(now)) {
+ mService.mHandler.post(new ActivityManagerService.ProcStatsRunnable(mService,
+ mService.mProcessStats));
+ }
- // Run this after making sure all procstates are updated.
- mService.mProcessStats.updateTrackingAssociationsLocked(mAdjSeq, now);
+ // Run this after making sure all procstates are updated.
+ mService.mProcessStats.updateTrackingAssociationsLocked(mAdjSeq, now);
+ }
if (DEBUG_OOM_ADJ) {
final long duration = SystemClock.uptimeMillis() - now;
diff --git a/services/core/java/com/android/server/am/PendingTempWhitelists.java b/services/core/java/com/android/server/am/PendingTempWhitelists.java
index b36e3c7b9e35..50d58f02baa7 100644
--- a/services/core/java/com/android/server/am/PendingTempWhitelists.java
+++ b/services/core/java/com/android/server/am/PendingTempWhitelists.java
@@ -32,13 +32,13 @@ final class PendingTempWhitelists {
void put(int uid, ActivityManagerService.PendingTempWhitelist value) {
mPendingTempWhitelist.put(uid, value);
- mService.mAtmInternal.onUidAddedToPendingTempWhitelist(uid, value.tag);
+ mService.mAtmInternal.onUidAddedToPendingTempAllowlist(uid, value.tag);
}
void removeAt(int index) {
final int uid = mPendingTempWhitelist.keyAt(index);
mPendingTempWhitelist.removeAt(index);
- mService.mAtmInternal.onUidRemovedFromPendingTempWhitelist(uid);
+ mService.mAtmInternal.onUidRemovedFromPendingTempAllowlist(uid);
}
ActivityManagerService.PendingTempWhitelist get(int uid) {
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index cd4302bb42fa..e3e13391a8b0 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -673,30 +673,33 @@ class ProcessRecord implements WindowProcessListener {
public void makeActive(IApplicationThread _thread, ProcessStatsService tracker) {
if (thread == null) {
- final ProcessState origBase = baseProcessTracker;
- if (origBase != null) {
- origBase.setState(ProcessStats.STATE_NOTHING,
- tracker.getMemFactorLocked(), SystemClock.uptimeMillis(), pkgList.mPkgList);
- for (int ipkg = pkgList.size() - 1; ipkg >= 0; ipkg--) {
- FrameworkStatsLog.write(FrameworkStatsLog.PROCESS_STATE_CHANGED,
- uid, processName, pkgList.keyAt(ipkg),
- ActivityManager.processStateAmToProto(ProcessStats.STATE_NOTHING),
- pkgList.valueAt(ipkg).appVersion);
- }
- origBase.makeInactive();
- }
- baseProcessTracker = tracker.getProcessStateLocked(info.packageName, info.uid,
- info.longVersionCode, processName);
- baseProcessTracker.makeActive();
- for (int i=0; i<pkgList.size(); i++) {
- ProcessStats.ProcessStateHolder holder = pkgList.valueAt(i);
- if (holder.state != null && holder.state != origBase) {
- holder.state.makeInactive();
+ synchronized (tracker.mLock) {
+ final ProcessState origBase = baseProcessTracker;
+ if (origBase != null) {
+ origBase.setState(ProcessStats.STATE_NOTHING,
+ tracker.getMemFactorLocked(), SystemClock.uptimeMillis(),
+ pkgList.mPkgList);
+ for (int ipkg = pkgList.size() - 1; ipkg >= 0; ipkg--) {
+ FrameworkStatsLog.write(FrameworkStatsLog.PROCESS_STATE_CHANGED,
+ uid, processName, pkgList.keyAt(ipkg),
+ ActivityManager.processStateAmToProto(ProcessStats.STATE_NOTHING),
+ pkgList.valueAt(ipkg).appVersion);
+ }
+ origBase.makeInactive();
}
- tracker.updateProcessStateHolderLocked(holder, pkgList.keyAt(i), info.uid,
+ baseProcessTracker = tracker.getProcessStateLocked(info.packageName, info.uid,
info.longVersionCode, processName);
- if (holder.state != baseProcessTracker) {
- holder.state.makeActive();
+ baseProcessTracker.makeActive();
+ for (int i = 0, ipkg = pkgList.size(); i < ipkg; i++) {
+ ProcessStats.ProcessStateHolder holder = pkgList.valueAt(i);
+ if (holder.state != null && holder.state != origBase) {
+ holder.state.makeInactive();
+ }
+ tracker.updateProcessStateHolderLocked(holder, pkgList.keyAt(i), info.uid,
+ info.longVersionCode, processName);
+ if (holder.state != baseProcessTracker) {
+ holder.state.makeActive();
+ }
}
}
}
@@ -707,27 +710,30 @@ class ProcessRecord implements WindowProcessListener {
public void makeInactive(ProcessStatsService tracker) {
thread = null;
mWindowProcessController.setThread(null);
- final ProcessState origBase = baseProcessTracker;
- if (origBase != null) {
+ synchronized (tracker.mLock) {
+ final ProcessState origBase = baseProcessTracker;
if (origBase != null) {
- origBase.setState(ProcessStats.STATE_NOTHING,
- tracker.getMemFactorLocked(), SystemClock.uptimeMillis(), pkgList.mPkgList);
- for (int ipkg = pkgList.size() - 1; ipkg >= 0; ipkg--) {
- FrameworkStatsLog.write(FrameworkStatsLog.PROCESS_STATE_CHANGED,
- uid, processName, pkgList.keyAt(ipkg),
- ActivityManager.processStateAmToProto(ProcessStats.STATE_NOTHING),
- pkgList.valueAt(ipkg).appVersion);
+ if (origBase != null) {
+ origBase.setState(ProcessStats.STATE_NOTHING,
+ tracker.getMemFactorLocked(), SystemClock.uptimeMillis(),
+ pkgList.mPkgList);
+ for (int ipkg = pkgList.size() - 1; ipkg >= 0; ipkg--) {
+ FrameworkStatsLog.write(FrameworkStatsLog.PROCESS_STATE_CHANGED,
+ uid, processName, pkgList.keyAt(ipkg),
+ ActivityManager.processStateAmToProto(ProcessStats.STATE_NOTHING),
+ pkgList.valueAt(ipkg).appVersion);
+ }
+ origBase.makeInactive();
}
- origBase.makeInactive();
- }
- baseProcessTracker = null;
- for (int i=0; i<pkgList.size(); i++) {
- ProcessStats.ProcessStateHolder holder = pkgList.valueAt(i);
- if (holder.state != null && holder.state != origBase) {
- holder.state.makeInactive();
+ baseProcessTracker = null;
+ for (int i = 0, ipkg = pkgList.size(); i < ipkg; i++) {
+ ProcessStats.ProcessStateHolder holder = pkgList.valueAt(i);
+ if (holder.state != null && holder.state != origBase) {
+ holder.state.makeInactive();
+ }
+ holder.pkg = null;
+ holder.state = null;
}
- holder.pkg = null;
- holder.state = null;
}
}
}
@@ -1026,17 +1032,19 @@ class ProcessRecord implements WindowProcessListener {
*/
public boolean addPackage(String pkg, long versionCode, ProcessStatsService tracker) {
if (!pkgList.containsKey(pkg)) {
- ProcessStats.ProcessStateHolder holder = new ProcessStats.ProcessStateHolder(
- versionCode);
- if (baseProcessTracker != null) {
- tracker.updateProcessStateHolderLocked(holder, pkg, info.uid, versionCode,
- processName);
- pkgList.put(pkg, holder);
- if (holder.state != baseProcessTracker) {
- holder.state.makeActive();
+ synchronized (tracker.mLock) {
+ ProcessStats.ProcessStateHolder holder = new ProcessStats.ProcessStateHolder(
+ versionCode);
+ if (baseProcessTracker != null) {
+ tracker.updateProcessStateHolderLocked(holder, pkg, info.uid, versionCode,
+ processName);
+ pkgList.put(pkg, holder);
+ if (holder.state != baseProcessTracker) {
+ holder.state.makeActive();
+ }
+ } else {
+ pkgList.put(pkg, holder);
}
- } else {
- pkgList.put(pkg, holder);
}
return true;
}
@@ -1072,31 +1080,33 @@ class ProcessRecord implements WindowProcessListener {
public void resetPackageList(ProcessStatsService tracker) {
final int N = pkgList.size();
if (baseProcessTracker != null) {
- long now = SystemClock.uptimeMillis();
- baseProcessTracker.setState(ProcessStats.STATE_NOTHING,
- tracker.getMemFactorLocked(), now, pkgList.mPkgList);
- for (int ipkg = pkgList.size() - 1; ipkg >= 0; ipkg--) {
- FrameworkStatsLog.write(FrameworkStatsLog.PROCESS_STATE_CHANGED,
- uid, processName, pkgList.keyAt(ipkg),
- ActivityManager.processStateAmToProto(ProcessStats.STATE_NOTHING),
- pkgList.valueAt(ipkg).appVersion);
- }
- if (N != 1) {
- for (int i=0; i<N; i++) {
- ProcessStats.ProcessStateHolder holder = pkgList.valueAt(i);
- if (holder.state != null && holder.state != baseProcessTracker) {
- holder.state.makeInactive();
- }
-
+ synchronized (tracker.mLock) {
+ long now = SystemClock.uptimeMillis();
+ baseProcessTracker.setState(ProcessStats.STATE_NOTHING,
+ tracker.getMemFactorLocked(), now, pkgList.mPkgList);
+ for (int ipkg = pkgList.size() - 1; ipkg >= 0; ipkg--) {
+ FrameworkStatsLog.write(FrameworkStatsLog.PROCESS_STATE_CHANGED,
+ uid, processName, pkgList.keyAt(ipkg),
+ ActivityManager.processStateAmToProto(ProcessStats.STATE_NOTHING),
+ pkgList.valueAt(ipkg).appVersion);
}
- pkgList.clear();
- ProcessStats.ProcessStateHolder holder = new ProcessStats.ProcessStateHolder(
- info.longVersionCode);
- tracker.updateProcessStateHolderLocked(holder, info.packageName, info.uid,
- info.longVersionCode, processName);
- pkgList.put(info.packageName, holder);
- if (holder.state != baseProcessTracker) {
- holder.state.makeActive();
+ if (N != 1) {
+ for (int i = 0; i < N; i++) {
+ ProcessStats.ProcessStateHolder holder = pkgList.valueAt(i);
+ if (holder.state != null && holder.state != baseProcessTracker) {
+ holder.state.makeInactive();
+ }
+
+ }
+ pkgList.clear();
+ ProcessStats.ProcessStateHolder holder = new ProcessStats.ProcessStateHolder(
+ info.longVersionCode);
+ tracker.updateProcessStateHolderLocked(holder, info.packageName, info.uid,
+ info.longVersionCode, processName);
+ pkgList.put(info.packageName, holder);
+ if (holder.state != baseProcessTracker) {
+ holder.state.makeActive();
+ }
}
}
} else if (N != 1) {
@@ -1522,8 +1532,8 @@ class ProcessRecord implements WindowProcessListener {
}
}
- public long getInputDispatchingTimeout() {
- return mWindowProcessController.getInputDispatchingTimeout();
+ public long getInputDispatchingTimeoutMillis() {
+ return mWindowProcessController.getInputDispatchingTimeoutMillis();
}
public int getProcessClassEnum() {
diff --git a/services/core/java/com/android/server/am/ProcessStatsService.java b/services/core/java/com/android/server/am/ProcessStatsService.java
index a168af5ad842..4e8c386a3c66 100644
--- a/services/core/java/com/android/server/am/ProcessStatsService.java
+++ b/services/core/java/com/android/server/am/ProcessStatsService.java
@@ -71,33 +71,62 @@ public final class ProcessStatsService extends IProcessStats.Stub {
final ActivityManagerService mAm;
final File mBaseDir;
- ProcessStats mProcessStats;
+
+ // Note: The locking order of the below 3 locks should be:
+ // mLock, mPendingWriteLock, mFileLock
+
+ // The lock object to protect the internal state/structures
+ final Object mLock = new Object();
+
+ // The lock object to protect the access to pending writes
+ final Object mPendingWriteLock = new Object();
+
+ // The lock object to protect the access to all of the file read/write
+ final ReentrantLock mFileLock = new ReentrantLock();
+
+ @GuardedBy("mLock")
+ final ProcessStats mProcessStats;
+
+ @GuardedBy("mFileLock")
AtomicFile mFile;
+
+ @GuardedBy("mLock")
boolean mCommitPending;
+
+ @GuardedBy("mLock")
boolean mShuttingDown;
+
+ @GuardedBy("mLock")
int mLastMemOnlyState = -1;
boolean mMemFactorLowered;
- final ReentrantLock mWriteLock = new ReentrantLock();
- final Object mPendingWriteLock = new Object();
+ @GuardedBy("mPendingWriteLock")
AtomicFile mPendingWriteFile;
+
+ @GuardedBy("mPendingWriteLock")
Parcel mPendingWrite;
+
+ @GuardedBy("mPendingWriteLock")
boolean mPendingWriteCommitted;
+
+ @GuardedBy("mLock")
long mLastWriteTime;
/** For CTS to inject the screen state. */
- @GuardedBy("mAm")
+ @GuardedBy("mLock")
Boolean mInjectedScreenState;
public ProcessStatsService(ActivityManagerService am, File file) {
mAm = am;
mBaseDir = file;
mBaseDir.mkdirs();
- mProcessStats = new ProcessStats(true);
- updateFile();
+ synchronized (mLock) {
+ mProcessStats = new ProcessStats(true);
+ updateFileLocked();
+ }
SystemProperties.addChangeCallback(new Runnable() {
@Override public void run() {
- synchronized (mAm) {
+ synchronized (mLock) {
if (mProcessStats.evaluateSystemProperties(false)) {
mProcessStats.mFlags |= ProcessStats.FLAG_SYSPROPS;
writeStateLocked(true, true);
@@ -121,32 +150,33 @@ public final class ProcessStatsService extends IProcessStats.Stub {
}
}
- @GuardedBy("mAm")
- public void updateProcessStateHolderLocked(ProcessStats.ProcessStateHolder holder,
+ @GuardedBy("mLock")
+ void updateProcessStateHolderLocked(ProcessStats.ProcessStateHolder holder,
String packageName, int uid, long versionCode, String processName) {
holder.pkg = mProcessStats.getPackageStateLocked(packageName, uid, versionCode);
holder.state = mProcessStats.getProcessStateLocked(holder.pkg, processName);
}
- @GuardedBy("mAm")
- public ProcessState getProcessStateLocked(String packageName,
+ @GuardedBy("mLock")
+ ProcessState getProcessStateLocked(String packageName,
int uid, long versionCode, String processName) {
return mProcessStats.getProcessStateLocked(packageName, uid, versionCode, processName);
}
- @GuardedBy("mAm")
- public ServiceState getServiceStateLocked(String packageName, int uid,
+ ServiceState getServiceState(String packageName, int uid,
long versionCode, String processName, String className) {
- return mProcessStats.getServiceStateLocked(packageName, uid, versionCode, processName,
- className);
+ synchronized (mLock) {
+ return mProcessStats.getServiceStateLocked(packageName, uid, versionCode, processName,
+ className);
+ }
}
- public boolean isMemFactorLowered() {
+ boolean isMemFactorLowered() {
return mMemFactorLowered;
}
- @GuardedBy("mAm")
- public boolean setMemFactorLocked(int memFactor, boolean screenOn, long now) {
+ @GuardedBy("mLock")
+ boolean setMemFactorLocked(int memFactor, boolean screenOn, long now) {
mMemFactorLowered = memFactor < mLastMemOnlyState;
mLastMemOnlyState = memFactor;
if (mInjectedScreenState != null) {
@@ -184,24 +214,24 @@ public final class ProcessStatsService extends IProcessStats.Stub {
return false;
}
- @GuardedBy("mAm")
- public int getMemFactorLocked() {
+ @GuardedBy("mLock")
+ int getMemFactorLocked() {
return mProcessStats.mMemFactor != ProcessStats.STATE_NOTHING ? mProcessStats.mMemFactor : 0;
}
- @GuardedBy("mAm")
- public void addSysMemUsageLocked(long cachedMem, long freeMem, long zramMem, long kernelMem,
+ @GuardedBy("mLock")
+ void addSysMemUsageLocked(long cachedMem, long freeMem, long zramMem, long kernelMem,
long nativeMem) {
mProcessStats.addSysMemUsage(cachedMem, freeMem, zramMem, kernelMem, nativeMem);
}
- @GuardedBy("mAm")
- public void updateTrackingAssociationsLocked(int curSeq, long now) {
+ @GuardedBy("mLock")
+ void updateTrackingAssociationsLocked(int curSeq, long now) {
mProcessStats.updateTrackingAssociationsLocked(curSeq, now);
}
- @GuardedBy("mAm")
- public boolean shouldWriteNowLocked(long now) {
+ @GuardedBy("mLock")
+ boolean shouldWriteNowLocked(long now) {
if (now > (mLastWriteTime+WRITE_PERIOD)) {
if (SystemClock.elapsedRealtime()
> (mProcessStats.mTimePeriodStartRealtime+ProcessStats.COMMIT_PERIOD) &&
@@ -214,25 +244,27 @@ public final class ProcessStatsService extends IProcessStats.Stub {
return false;
}
- @GuardedBy("mAm")
- public void shutdownLocked() {
+ void shutdown() {
Slog.w(TAG, "Writing process stats before shutdown...");
- mProcessStats.mFlags |= ProcessStats.FLAG_SHUTDOWN;
- writeStateSyncLocked();
- mShuttingDown = true;
+ synchronized (mLock) {
+ mProcessStats.mFlags |= ProcessStats.FLAG_SHUTDOWN;
+ writeStateSyncLocked();
+ mShuttingDown = true;
+ }
}
- @GuardedBy("mAm")
- public void writeStateAsyncLocked() {
- writeStateLocked(false);
+ void writeStateAsync() {
+ synchronized (mLock) {
+ writeStateLocked(false);
+ }
}
- @GuardedBy("mAm")
- public void writeStateSyncLocked() {
+ @GuardedBy("mLock")
+ private void writeStateSyncLocked() {
writeStateLocked(true);
}
- @GuardedBy("mAm")
+ @GuardedBy("mLock")
private void writeStateLocked(boolean sync) {
if (mShuttingDown) {
return;
@@ -242,8 +274,8 @@ public final class ProcessStatsService extends IProcessStats.Stub {
writeStateLocked(sync, commitPending);
}
- @GuardedBy("mAm")
- public void writeStateLocked(boolean sync, final boolean commit) {
+ @GuardedBy("mLock")
+ private void writeStateLocked(boolean sync, final boolean commit) {
final long totalTime;
synchronized (mPendingWriteLock) {
final long now = SystemClock.uptimeMillis();
@@ -255,13 +287,13 @@ public final class ProcessStatsService extends IProcessStats.Stub {
mProcessStats.mFlags |= ProcessStats.FLAG_COMPLETE;
}
mProcessStats.writeToParcel(mPendingWrite, 0);
- mPendingWriteFile = new AtomicFile(mFile.getBaseFile());
+ mPendingWriteFile = new AtomicFile(getCurrentFile());
mPendingWriteCommitted = commit;
}
if (commit) {
mProcessStats.resetSafely();
- updateFile();
- mAm.requestPssAllProcsLocked(SystemClock.uptimeMillis(), true, false);
+ updateFileLocked();
+ scheduleRequestPssAllProcs(true, false);
}
mLastWriteTime = SystemClock.uptimeMillis();
totalTime = SystemClock.uptimeMillis() - now;
@@ -279,14 +311,37 @@ public final class ProcessStatsService extends IProcessStats.Stub {
performWriteState(totalTime);
}
- private void updateFile() {
- mFile = new AtomicFile(new File(mBaseDir, STATE_FILE_PREFIX
- + mProcessStats.mTimePeriodStartClockStr + STATE_FILE_SUFFIX));
+ private void scheduleRequestPssAllProcs(boolean always, boolean memLowered) {
+ mAm.mHandler.post(() -> {
+ synchronized (mAm) {
+ mAm.requestPssAllProcsLocked(SystemClock.uptimeMillis(), always, memLowered);
+ }
+ });
+ }
+
+ @GuardedBy("mLock")
+ private void updateFileLocked() {
+ mFileLock.lock();
+ try {
+ mFile = new AtomicFile(new File(mBaseDir, STATE_FILE_PREFIX
+ + mProcessStats.mTimePeriodStartClockStr + STATE_FILE_SUFFIX));
+ } finally {
+ mFileLock.unlock();
+ }
mLastWriteTime = SystemClock.uptimeMillis();
}
- void performWriteState(long initialTime) {
- if (DEBUG) Slog.d(TAG, "Performing write to " + mFile.getBaseFile());
+ private File getCurrentFile() {
+ mFileLock.lock();
+ try {
+ return mFile.getBaseFile();
+ } finally {
+ mFileLock.unlock();
+ }
+ }
+
+ private void performWriteState(long initialTime) {
+ if (DEBUG) Slog.d(TAG, "Performing write to " + getCurrentFile());
Parcel data;
AtomicFile file;
synchronized (mPendingWriteLock) {
@@ -298,7 +353,7 @@ public final class ProcessStatsService extends IProcessStats.Stub {
}
mPendingWrite = null;
mPendingWriteFile = null;
- mWriteLock.lock();
+ mFileLock.lock();
}
final long startTime = SystemClock.uptimeMillis();
@@ -316,13 +371,13 @@ public final class ProcessStatsService extends IProcessStats.Stub {
file.failWrite(stream);
} finally {
data.recycle();
- trimHistoricStatesWriteLocked();
- mWriteLock.unlock();
+ trimHistoricStatesWriteLF();
+ mFileLock.unlock();
}
}
- @GuardedBy("mAm")
- boolean readLocked(ProcessStats stats, AtomicFile file) {
+ @GuardedBy("mFileLock")
+ private boolean readLF(ProcessStats stats, AtomicFile file) {
try {
FileInputStream stream = file.openRead();
stats.read(stream);
@@ -387,7 +442,8 @@ public final class ProcessStatsService extends IProcessStats.Stub {
return true;
}
- private ArrayList<String> getCommittedFiles(int minNum, boolean inclCurrent,
+ @GuardedBy("mFileLock")
+ private ArrayList<String> getCommittedFilesLF(int minNum, boolean inclCurrent,
boolean inclCheckedIn) {
File[] files = mBaseDir.listFiles();
if (files == null || files.length <= minNum) {
@@ -414,9 +470,9 @@ public final class ProcessStatsService extends IProcessStats.Stub {
return filesArray;
}
- @GuardedBy("mAm")
- public void trimHistoricStatesWriteLocked() {
- ArrayList<String> filesArray = getCommittedFiles(MAX_HISTORIC_STATES, false, true);
+ @GuardedBy("mFileLock")
+ private void trimHistoricStatesWriteLF() {
+ ArrayList<String> filesArray = getCommittedFilesLF(MAX_HISTORIC_STATES, false, true);
if (filesArray == null) {
return;
}
@@ -427,8 +483,8 @@ public final class ProcessStatsService extends IProcessStats.Stub {
}
}
- @GuardedBy("mAm")
- boolean dumpFilteredProcessesCsvLocked(PrintWriter pw, String header,
+ @GuardedBy("mLock")
+ private boolean dumpFilteredProcessesCsvLocked(PrintWriter pw, String header,
boolean sepScreenStates, int[] screenStates, boolean sepMemStates, int[] memStates,
boolean sepProcStates, int[] procStates, long now, String reqPackage) {
ArrayList<ProcessState> procs = mProcessStats.collectProcessesLocked(
@@ -502,20 +558,21 @@ public final class ProcessStatsService extends IProcessStats.Stub {
return res;
}
+ @Override
public byte[] getCurrentStats(List<ParcelFileDescriptor> historic) {
mAm.mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.PACKAGE_USAGE_STATS, null);
Parcel current = Parcel.obtain();
- synchronized (mAm) {
+ synchronized (mLock) {
long now = SystemClock.uptimeMillis();
mProcessStats.mTimePeriodEndRealtime = SystemClock.elapsedRealtime();
mProcessStats.mTimePeriodEndUptime = now;
mProcessStats.writeToParcel(current, now, 0);
}
- mWriteLock.lock();
+ mFileLock.lock();
try {
if (historic != null) {
- ArrayList<String> files = getCommittedFiles(0, false, true);
+ ArrayList<String> files = getCommittedFilesLF(0, false, true);
if (files != null) {
for (int i=files.size()-1; i>=0; i--) {
try {
@@ -529,7 +586,7 @@ public final class ProcessStatsService extends IProcessStats.Stub {
}
}
} finally {
- mWriteLock.unlock();
+ mFileLock.unlock();
}
return current.marshall();
}
@@ -563,9 +620,9 @@ public final class ProcessStatsService extends IProcessStats.Stub {
android.Manifest.permission.PACKAGE_USAGE_STATS, null);
long newHighWaterMark = highWaterMarkMs;
- mWriteLock.lock();
+ mFileLock.lock();
try {
- ArrayList<String> files = getCommittedFiles(0, false, true);
+ ArrayList<String> files = getCommittedFilesLF(0, false, true);
if (files != null) {
String highWaterMarkStr =
DateFormat.format("yyyy-MM-dd-HH-mm-ss", highWaterMarkMs).toString();
@@ -612,7 +669,7 @@ public final class ProcessStatsService extends IProcessStats.Stub {
} catch (IOException e) {
Slog.w(TAG, "Failure opening procstat file", e);
} finally {
- mWriteLock.unlock();
+ mFileLock.unlock();
}
return newHighWaterMark;
}
@@ -625,7 +682,7 @@ public final class ProcessStatsService extends IProcessStats.Stub {
return mAm.mConstants.MIN_ASSOC_LOG_DURATION;
}
- private ParcelFileDescriptor protoToParcelFileDescriptor(ProcessStats stats, int section)
+ private static ParcelFileDescriptor protoToParcelFileDescriptor(ProcessStats stats, int section)
throws IOException {
final ParcelFileDescriptor[] fds = ParcelFileDescriptor.createPipe();
Thread thr = new Thread("ProcessStats pipe output") {
@@ -645,12 +702,13 @@ public final class ProcessStatsService extends IProcessStats.Stub {
return fds[0];
}
+ @Override
public ParcelFileDescriptor getStatsOverTime(long minTime) {
mAm.mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.PACKAGE_USAGE_STATS, null);
Parcel current = Parcel.obtain();
long curTime;
- synchronized (mAm) {
+ synchronized (mLock) {
long now = SystemClock.uptimeMillis();
mProcessStats.mTimePeriodEndRealtime = SystemClock.elapsedRealtime();
mProcessStats.mTimePeriodEndUptime = now;
@@ -658,11 +716,11 @@ public final class ProcessStatsService extends IProcessStats.Stub {
curTime = mProcessStats.mTimePeriodEndRealtime
- mProcessStats.mTimePeriodStartRealtime;
}
- mWriteLock.lock();
+ mFileLock.lock();
try {
if (curTime < minTime) {
// Need to add in older stats to reach desired time.
- ArrayList<String> files = getCommittedFiles(0, false, true);
+ ArrayList<String> files = getCommittedFilesLF(0, false, true);
if (files != null && files.size() > 0) {
current.setDataPosition(0);
ProcessStats stats = ProcessStats.CREATOR.createFromParcel(current);
@@ -673,7 +731,7 @@ public final class ProcessStatsService extends IProcessStats.Stub {
AtomicFile file = new AtomicFile(new File(files.get(i)));
i--;
ProcessStats moreStats = new ProcessStats(false);
- readLocked(moreStats, file);
+ readLF(moreStats, file);
if (moreStats.mReadError == null) {
stats.add(moreStats);
StringBuilder sb = new StringBuilder();
@@ -712,13 +770,14 @@ public final class ProcessStatsService extends IProcessStats.Stub {
} catch (IOException e) {
Slog.w(TAG, "Failed building output pipe", e);
} finally {
- mWriteLock.unlock();
+ mFileLock.unlock();
}
return null;
}
+ @Override
public int getCurrentMemoryState() {
- synchronized (mAm) {
+ synchronized (mLock) {
return mLastMemOnlyState;
}
}
@@ -947,7 +1006,7 @@ public final class ProcessStatsService extends IProcessStats.Stub {
} else if ("--current".equals(arg)) {
currentOnly = true;
} else if ("--commit".equals(arg)) {
- synchronized (mAm) {
+ synchronized (mLock) {
mProcessStats.mFlags |= ProcessStats.FLAG_COMPLETE;
writeStateLocked(true, true);
pw.println("Process stats committed.");
@@ -962,29 +1021,39 @@ public final class ProcessStatsService extends IProcessStats.Stub {
}
section = parseSectionOptions(args[i]);
} else if ("--clear".equals(arg)) {
- synchronized (mAm) {
+ synchronized (mLock) {
mProcessStats.resetSafely();
- mAm.requestPssAllProcsLocked(SystemClock.uptimeMillis(), true, false);
- ArrayList<String> files = getCommittedFiles(0, true, true);
- if (files != null) {
- for (int fi=0; fi<files.size(); fi++) {
- (new File(files.get(fi))).delete();
+ scheduleRequestPssAllProcs(true, false);
+ mFileLock.lock();
+ try {
+ ArrayList<String> files = getCommittedFilesLF(0, true, true);
+ if (files != null) {
+ for (int fi = files.size() - 1; fi >= 0; fi--) {
+ (new File(files.get(fi))).delete();
+ }
}
+ } finally {
+ mFileLock.unlock();
}
pw.println("All process stats cleared.");
quit = true;
}
} else if ("--write".equals(arg)) {
- synchronized (mAm) {
+ synchronized (mLock) {
writeStateSyncLocked();
pw.println("Process stats written.");
quit = true;
}
} else if ("--read".equals(arg)) {
- synchronized (mAm) {
- readLocked(mProcessStats, mFile);
- pw.println("Process stats read.");
- quit = true;
+ synchronized (mLock) {
+ mFileLock.lock();
+ try {
+ readLF(mProcessStats, mFile);
+ pw.println("Process stats read.");
+ quit = true;
+ } finally {
+ mFileLock.unlock();
+ }
}
} else if ("--start-testing".equals(arg)) {
synchronized (mAm) {
@@ -999,17 +1068,17 @@ public final class ProcessStatsService extends IProcessStats.Stub {
quit = true;
}
} else if ("--pretend-screen-on".equals(arg)) {
- synchronized (mAm) {
+ synchronized (mLock) {
mInjectedScreenState = true;
}
quit = true;
} else if ("--pretend-screen-off".equals(arg)) {
- synchronized (mAm) {
+ synchronized (mLock) {
mInjectedScreenState = false;
}
quit = true;
} else if ("--stop-pretend-screen".equals(arg)) {
- synchronized (mAm) {
+ synchronized (mLock) {
mInjectedScreenState = null;
}
quit = true;
@@ -1060,7 +1129,7 @@ public final class ProcessStatsService extends IProcessStats.Stub {
}
}
pw.println();
- synchronized (mAm) {
+ synchronized (mLock) {
dumpFilteredProcessesCsvLocked(pw, null,
csvSepScreenStats, csvScreenStats, csvSepMemStats, csvMemStats,
csvSepProcStats, csvProcStats, now, reqPackage);
@@ -1090,14 +1159,26 @@ public final class ProcessStatsService extends IProcessStats.Stub {
return;
} else if (lastIndex > 0) {
pw.print("LAST STATS AT INDEX "); pw.print(lastIndex); pw.println(":");
- ArrayList<String> files = getCommittedFiles(0, false, true);
- if (lastIndex >= files.size()) {
- pw.print("Only have "); pw.print(files.size()); pw.println(" data sets");
- return;
+
+ ArrayList<String> files;
+ AtomicFile file;
+ ProcessStats processStats;
+
+ mFileLock.lock();
+ try {
+ files = getCommittedFilesLF(0, false, true);
+ if (lastIndex >= files.size()) {
+ pw.print("Only have "); pw.print(files.size()); pw.println(" data sets");
+ return;
+ }
+ file = new AtomicFile(new File(files.get(lastIndex)));
+ processStats = new ProcessStats(false);
+ readLF(processStats, file);
+ } finally {
+ mFileLock.unlock();
}
- AtomicFile file = new AtomicFile(new File(files.get(lastIndex)));
- ProcessStats processStats = new ProcessStats(false);
- readLocked(processStats, file);
+
+ // No lock is needed now, since only us have the access to the 'processStats'.
if (processStats.mReadError != null) {
if (isCheckin || isCompact) pw.print("err,");
pw.print("Failure reading "); pw.print(files.get(lastIndex));
@@ -1118,7 +1199,7 @@ public final class ProcessStatsService extends IProcessStats.Stub {
processStats.dumpLocked(pw, reqPackage, now, !dumpFullDetails, dumpDetails,
dumpAll, activeOnly, section);
if (dumpAll) {
- pw.print(" mFile="); pw.println(mFile.getBaseFile());
+ pw.print(" mFile="); pw.println(getCurrentFile());
}
} else {
processStats.dumpSummaryLocked(pw, reqPackage, now, activeOnly);
@@ -1129,9 +1210,9 @@ public final class ProcessStatsService extends IProcessStats.Stub {
boolean sepNeeded = false;
if ((dumpAll || isCheckin) && !currentOnly) {
- mWriteLock.lock();
+ mFileLock.lock();
try {
- ArrayList<String> files = getCommittedFiles(0, false, !isCheckin);
+ ArrayList<String> files = getCommittedFilesLF(0, false, !isCheckin);
if (files != null) {
int start = isCheckin ? 0 : (files.size() - maxNum);
if (start < 0) {
@@ -1142,7 +1223,7 @@ public final class ProcessStatsService extends IProcessStats.Stub {
try {
AtomicFile file = new AtomicFile(new File(files.get(i)));
ProcessStats processStats = new ProcessStats(false);
- readLocked(processStats, file);
+ readLF(processStats, file);
if (processStats.mReadError != null) {
if (isCheckin || isCompact) pw.print("err,");
pw.print("Failure reading "); pw.print(files.get(i));
@@ -1188,11 +1269,11 @@ public final class ProcessStatsService extends IProcessStats.Stub {
}
}
} finally {
- mWriteLock.unlock();
+ mFileLock.unlock();
}
}
if (!isCheckin) {
- synchronized (mAm) {
+ synchronized (mLock) {
if (isCompact) {
mProcessStats.dumpCheckinLocked(pw, reqPackage, section);
} else {
@@ -1204,7 +1285,7 @@ public final class ProcessStatsService extends IProcessStats.Stub {
mProcessStats.dumpLocked(pw, reqPackage, now, !dumpFullDetails, dumpDetails,
dumpAll, activeOnly, section);
if (dumpAll) {
- pw.print(" mFile="); pw.println(mFile.getBaseFile());
+ pw.print(" mFile="); pw.println(getCurrentFile());
}
} else {
mProcessStats.dumpSummaryLocked(pw, reqPackage, now, activeOnly);
@@ -1249,7 +1330,7 @@ public final class ProcessStatsService extends IProcessStats.Stub {
// dump current procstats
long now;
- synchronized (mAm) {
+ synchronized (mLock) {
now = SystemClock.uptimeMillis();
final long token = proto.start(ProcessStatsServiceDumpProto.PROCSTATS_NOW);
mProcessStats.dumpDebug(proto, now, ProcessStats.REPORT_ALL);
diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java
index 022b04d89774..4a2703056871 100644
--- a/services/core/java/com/android/server/am/ServiceRecord.java
+++ b/services/core/java/com/android/server/am/ServiceRecord.java
@@ -528,8 +528,9 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN
return tracker;
}
if ((serviceInfo.applicationInfo.flags&ApplicationInfo.FLAG_PERSISTENT) == 0) {
- tracker = ams.mProcessStats.getServiceStateLocked(serviceInfo.packageName,
- serviceInfo.applicationInfo.uid, serviceInfo.applicationInfo.longVersionCode,
+ tracker = ams.mProcessStats.getServiceState(serviceInfo.packageName,
+ serviceInfo.applicationInfo.uid,
+ serviceInfo.applicationInfo.longVersionCode,
serviceInfo.processName, serviceInfo.name);
tracker.applyNewOwner(this);
}
@@ -546,7 +547,8 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN
public void makeRestarting(int memFactor, long now) {
if (restartTracker == null) {
if ((serviceInfo.applicationInfo.flags&ApplicationInfo.FLAG_PERSISTENT) == 0) {
- restartTracker = ams.mProcessStats.getServiceStateLocked(serviceInfo.packageName,
+ restartTracker = ams.mProcessStats.getServiceState(
+ serviceInfo.packageName,
serviceInfo.applicationInfo.uid,
serviceInfo.applicationInfo.longVersionCode,
serviceInfo.processName, serviceInfo.name);
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index e6480fc6cde8..ee441bf06d04 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -1889,6 +1889,7 @@ public class AppOpsService extends IAppOpsService.Stub {
synchronized (this) {
if (mWriteScheduled) {
mWriteScheduled = false;
+ mHandler.removeCallbacks(mWriteRunner);
doWrite = true;
}
}
diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
index 45f95fd3f663..2bbbbf1664d1 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
@@ -224,12 +224,35 @@ import java.util.concurrent.atomic.AtomicBoolean;
if (!addSpeakerphoneClient(cb, pid, on)) {
return false;
}
+ if (on) {
+ // Cancel BT SCO ON request by this same client: speakerphone and BT SCO routes
+ // are mutually exclusive.
+ // See symmetrical operation for startBluetoothScoForClient_Sync().
+ mBtHelper.stopBluetoothScoForPid(pid);
+ }
final boolean wasOn = isSpeakerphoneOn();
updateSpeakerphoneOn(eventSource);
return (wasOn != isSpeakerphoneOn());
}
}
+ /**
+ * Turns speakerphone off for a given pid and update speakerphone state.
+ * @param pid
+ */
+ @GuardedBy("mDeviceStateLock")
+ private void setSpeakerphoneOffForPid(int pid) {
+ SpeakerphoneClient client = getSpeakerphoneClientForPid(pid);
+ if (client == null) {
+ return;
+ }
+ client.unregisterDeathRecipient();
+ mSpeakerphoneClients.remove(client);
+ final String eventSource = new StringBuilder("setSpeakerphoneOffForPid(")
+ .append(pid).append(")").toString();
+ updateSpeakerphoneOn(eventSource);
+ }
+
@GuardedBy("mDeviceStateLock")
private void updateSpeakerphoneOn(String eventSource) {
if (isSpeakerphoneOnRequested()) {
@@ -488,6 +511,10 @@ import java.util.concurrent.atomic.AtomicBoolean;
/*package*/ void startBluetoothScoForClient_Sync(IBinder cb, int scoAudioMode,
@NonNull String eventSource) {
synchronized (mDeviceStateLock) {
+ // Cancel speakerphone ON request by this same client: speakerphone and BT SCO routes
+ // are mutually exclusive.
+ // See symmetrical operation for setSpeakerphoneOn(true).
+ setSpeakerphoneOffForPid(Binder.getCallingPid());
mBtHelper.startBluetoothScoForClient(cb, scoAudioMode, eventSource);
}
}
@@ -1379,6 +1406,16 @@ import java.util.concurrent.atomic.AtomicBoolean;
return false;
}
+ @GuardedBy("mDeviceStateLock")
+ private SpeakerphoneClient getSpeakerphoneClientForPid(int pid) {
+ for (SpeakerphoneClient cl : mSpeakerphoneClients) {
+ if (cl.getPid() == pid) {
+ return cl;
+ }
+ }
+ return null;
+ }
+
// List of clients requesting speakerPhone ON
@GuardedBy("mDeviceStateLock")
private final @NonNull ArrayList<SpeakerphoneClient> mSpeakerphoneClients =
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 32be03fb4ef8..366f30318cd5 100755
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -414,13 +414,6 @@ public class AudioService extends IAudioService.Stub
AppOpsManager.OP_AUDIO_MEDIA_VOLUME // STREAM_ASSISTANT
};
- private static Set<Integer> sDeviceVolumeBehaviorSupportedDeviceOutSet = new HashSet<>(
- Arrays.asList(
- AudioSystem.DEVICE_OUT_HDMI,
- AudioSystem.DEVICE_OUT_HDMI_ARC,
- AudioSystem.DEVICE_OUT_SPDIF,
- AudioSystem.DEVICE_OUT_LINE));
-
private final boolean mUseFixedVolume;
// If absolute volume is supported in AVRCP device
@@ -4952,11 +4945,6 @@ public class AudioService extends IAudioService.Stub
private void setDeviceVolumeBehaviorInternal(int audioSystemDeviceOut,
@AudioManager.DeviceVolumeBehavior int deviceVolumeBehavior, @NonNull String caller) {
- if (!sDeviceVolumeBehaviorSupportedDeviceOutSet.contains(audioSystemDeviceOut)) {
- // unsupported for now
- throw new IllegalArgumentException("Unsupported device type " + audioSystemDeviceOut);
- }
-
// update device masks based on volume behavior
switch (deviceVolumeBehavior) {
case AudioManager.DEVICE_VOLUME_BEHAVIOR_VARIABLE:
@@ -4990,20 +4978,14 @@ public class AudioService extends IAudioService.Stub
* @param device the audio output device type
* @return the volume behavior for the device
*/
- public @AudioManager.DeviceVolumeBehaviorState int getDeviceVolumeBehavior(
- @NonNull AudioDeviceAttributes device) {
+ public @AudioManager.DeviceVolumeBehavior
+ int getDeviceVolumeBehavior(@NonNull AudioDeviceAttributes device) {
// verify permissions
enforceModifyAudioRoutingPermission();
// translate Java device type to native device type (for the devices masks for full / fixed)
final int audioSystemDeviceOut = AudioDeviceInfo.convertDeviceTypeToInternalDevice(
device.getType());
- if (!sDeviceVolumeBehaviorSupportedDeviceOutSet.contains(audioSystemDeviceOut)
- && audioSystemDeviceOut != AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP
- && audioSystemDeviceOut != AudioSystem.DEVICE_OUT_HEARING_AID) {
- throw new IllegalArgumentException("Unsupported volume behavior "
- + audioSystemDeviceOut);
- }
int setDeviceVolumeBehavior = retrieveStoredDeviceVolumeBehavior(audioSystemDeviceOut);
if (setDeviceVolumeBehavior != AudioManager.DEVICE_VOLUME_BEHAVIOR_UNSET) {
@@ -9081,7 +9063,7 @@ public class AudioService extends IAudioService.Stub
}
private void restoreDeviceVolumeBehavior() {
- for (int deviceType : sDeviceVolumeBehaviorSupportedDeviceOutSet) {
+ for (int deviceType : AudioSystem.DEVICE_OUT_ALL_SET) {
if (DEBUG_VOL) {
Log.d(TAG, "Retrieving Volume Behavior for DeviceType: " + deviceType);
}
diff --git a/services/core/java/com/android/server/audio/BtHelper.java b/services/core/java/com/android/server/audio/BtHelper.java
index 5e8f1ef0db85..ded0f9a3dca7 100644
--- a/services/core/java/com/android/server/audio/BtHelper.java
+++ b/services/core/java/com/android/server/audio/BtHelper.java
@@ -432,19 +432,35 @@ public class BtHelper {
// and this must be done on behalf of system server to make sure permissions are granted.
final long ident = Binder.clearCallingIdentity();
if (client != null) {
- AudioService.sDeviceLogger.log(new AudioEventLogger.StringEvent(eventSource));
- client.requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED,
- SCO_MODE_VIRTUAL_CALL);
- // If a disconnection is pending, the client will be removed whne clearAllScoClients()
- // is called form receiveBtEvent()
- if (mScoAudioState != SCO_STATE_DEACTIVATE_REQ
- && mScoAudioState != SCO_STATE_DEACTIVATING) {
- client.remove(false /*stop */, true /*unregister*/);
- }
+ stopAndRemoveClient(client, eventSource);
}
Binder.restoreCallingIdentity(ident);
}
+ // @GuardedBy("AudioDeviceBroker.mSetModeLock")
+ @GuardedBy("AudioDeviceBroker.mDeviceStateLock")
+ /*package*/ synchronized void stopBluetoothScoForPid(int pid) {
+ ScoClient client = getScoClientForPid(pid);
+ if (client == null) {
+ return;
+ }
+ final String eventSource = new StringBuilder("stopBluetoothScoForPid(")
+ .append(pid).append(")").toString();
+ stopAndRemoveClient(client, eventSource);
+ }
+
+ @GuardedBy("AudioDeviceBroker.mDeviceStateLock")
+ private void stopAndRemoveClient(ScoClient client, @NonNull String eventSource) {
+ AudioService.sDeviceLogger.log(new AudioEventLogger.StringEvent(eventSource));
+ client.requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED,
+ SCO_MODE_VIRTUAL_CALL);
+ // If a disconnection is pending, the client will be removed when clearAllScoClients()
+ // is called form receiveBtEvent()
+ if (mScoAudioState != SCO_STATE_DEACTIVATE_REQ
+ && mScoAudioState != SCO_STATE_DEACTIVATING) {
+ client.remove(false /*stop */, true /*unregister*/);
+ }
+ }
/*package*/ synchronized void setHearingAidVolume(int index, int streamType) {
if (mHearingAid == null) {
@@ -982,6 +998,16 @@ public class BtHelper {
return null;
}
+ @GuardedBy("BtHelper.this")
+ private ScoClient getScoClientForPid(int pid) {
+ for (ScoClient cl : mScoClients) {
+ if (cl.getPid() == pid) {
+ return cl;
+ }
+ }
+ return null;
+ }
+
// @GuardedBy("AudioDeviceBroker.mSetModeLock")
//@GuardedBy("AudioDeviceBroker.mDeviceStateLock")
@GuardedBy("BtHelper.this")
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index 1f85d1046523..1c93d4eb599b 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -48,6 +48,7 @@ import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
import android.content.pm.UserInfo;
import android.net.ConnectivityManager;
+import android.net.DnsResolver;
import android.net.INetworkManagementEventObserver;
import android.net.Ikev2VpnProfile;
import android.net.IpPrefix;
@@ -79,6 +80,7 @@ import android.net.ipsec.ike.IkeSessionParams;
import android.os.Binder;
import android.os.Build.VERSION_CODES;
import android.os.Bundle;
+import android.os.CancellationSignal;
import android.os.FileUtils;
import android.os.IBinder;
import android.os.INetworkManagementService;
@@ -123,6 +125,7 @@ import java.math.BigInteger;
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
+import java.net.UnknownHostException;
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.util.ArrayList;
@@ -134,6 +137,8 @@ import java.util.Objects;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@@ -190,6 +195,7 @@ public class Vpn {
// automated reconnection
private final Context mContext;
+ @VisibleForTesting final Dependencies mDeps;
private final NetworkInfo mNetworkInfo;
@VisibleForTesting protected String mPackage;
private int mOwnerUID;
@@ -252,17 +258,143 @@ public class Vpn {
// Handle of the user initiating VPN.
private final int mUserHandle;
+ interface RetryScheduler {
+ void checkInterruptAndDelay(boolean sleepLonger) throws InterruptedException;
+ }
+
+ static class Dependencies {
+ public void startService(final String serviceName) {
+ SystemService.start(serviceName);
+ }
+
+ public void stopService(final String serviceName) {
+ SystemService.stop(serviceName);
+ }
+
+ public boolean isServiceRunning(final String serviceName) {
+ return SystemService.isRunning(serviceName);
+ }
+
+ public boolean isServiceStopped(final String serviceName) {
+ return SystemService.isStopped(serviceName);
+ }
+
+ public File getStateFile() {
+ return new File("/data/misc/vpn/state");
+ }
+
+ public void sendArgumentsToDaemon(
+ final String daemon, final LocalSocket socket, final String[] arguments,
+ final RetryScheduler retryScheduler) throws IOException, InterruptedException {
+ final LocalSocketAddress address = new LocalSocketAddress(
+ daemon, LocalSocketAddress.Namespace.RESERVED);
+
+ // Wait for the socket to connect.
+ while (true) {
+ try {
+ socket.connect(address);
+ break;
+ } catch (Exception e) {
+ // ignore
+ }
+ retryScheduler.checkInterruptAndDelay(true /* sleepLonger */);
+ }
+ socket.setSoTimeout(500);
+
+ final OutputStream out = socket.getOutputStream();
+ for (String argument : arguments) {
+ byte[] bytes = argument.getBytes(StandardCharsets.UTF_8);
+ if (bytes.length >= 0xFFFF) {
+ throw new IllegalArgumentException("Argument is too large");
+ }
+ out.write(bytes.length >> 8);
+ out.write(bytes.length);
+ out.write(bytes);
+ retryScheduler.checkInterruptAndDelay(false /* sleepLonger */);
+ }
+ out.write(0xFF);
+ out.write(0xFF);
+
+ // Wait for End-of-File.
+ final InputStream in = socket.getInputStream();
+ while (true) {
+ try {
+ if (in.read() == -1) {
+ break;
+ }
+ } catch (Exception e) {
+ // ignore
+ }
+ retryScheduler.checkInterruptAndDelay(true /* sleepLonger */);
+ }
+ }
+
+ @NonNull
+ public InetAddress resolve(final String endpoint)
+ throws ExecutionException, InterruptedException {
+ try {
+ return InetAddress.parseNumericAddress(endpoint);
+ } catch (IllegalArgumentException e) {
+ // Endpoint is not numeric : fall through and resolve
+ }
+
+ final CancellationSignal cancellationSignal = new CancellationSignal();
+ try {
+ final DnsResolver resolver = DnsResolver.getInstance();
+ final CompletableFuture<InetAddress> result = new CompletableFuture();
+ final DnsResolver.Callback<List<InetAddress>> cb =
+ new DnsResolver.Callback<List<InetAddress>>() {
+ @Override
+ public void onAnswer(@NonNull final List<InetAddress> answer,
+ final int rcode) {
+ if (answer.size() > 0) {
+ result.complete(answer.get(0));
+ } else {
+ result.completeExceptionally(
+ new UnknownHostException(endpoint));
+ }
+ }
+
+ @Override
+ public void onError(@Nullable final DnsResolver.DnsException error) {
+ // Unfortunately UnknownHostException doesn't accept a cause, so
+ // print a message here instead. Only show the summary, not the
+ // full stack trace.
+ Log.e(TAG, "Async dns resolver error : " + error);
+ result.completeExceptionally(new UnknownHostException(endpoint));
+ }
+ };
+ resolver.query(null /* network, null for default */, endpoint,
+ DnsResolver.FLAG_EMPTY, r -> r.run(), cancellationSignal, cb);
+ return result.get();
+ } catch (final ExecutionException e) {
+ Log.e(TAG, "Cannot resolve VPN endpoint : " + endpoint + ".", e);
+ throw e;
+ } catch (final InterruptedException e) {
+ Log.e(TAG, "Legacy VPN was interrupted while resolving the endpoint", e);
+ cancellationSignal.cancel();
+ throw e;
+ }
+ }
+
+ public boolean checkInterfacePresent(final Vpn vpn, final String iface) {
+ return vpn.jniCheck(iface) == 0;
+ }
+ }
+
public Vpn(Looper looper, Context context, INetworkManagementService netService,
@UserIdInt int userHandle, @NonNull KeyStore keyStore) {
- this(looper, context, netService, userHandle, keyStore,
+ this(looper, context, new Dependencies(), netService, userHandle, keyStore,
new SystemServices(context), new Ikev2SessionCreator());
}
@VisibleForTesting
- protected Vpn(Looper looper, Context context, INetworkManagementService netService,
+ protected Vpn(Looper looper, Context context, Dependencies deps,
+ INetworkManagementService netService,
int userHandle, @NonNull KeyStore keyStore, SystemServices systemServices,
Ikev2SessionCreator ikev2SessionCreator) {
mContext = context;
+ mDeps = deps;
mNetd = netService;
mUserHandle = userHandle;
mLooper = looper;
@@ -2129,7 +2261,8 @@ public class Vpn {
}
/** This class represents the common interface for all VPN runners. */
- private abstract class VpnRunner extends Thread {
+ @VisibleForTesting
+ abstract class VpnRunner extends Thread {
protected VpnRunner(String name) {
super(name);
@@ -2638,7 +2771,7 @@ public class Vpn {
} catch (InterruptedException e) {
}
for (String daemon : mDaemons) {
- SystemService.stop(daemon);
+ mDeps.stopService(daemon);
}
}
agentDisconnect();
@@ -2655,21 +2788,55 @@ public class Vpn {
}
}
+ private void checkAndFixupArguments(@NonNull final InetAddress endpointAddress) {
+ final String endpointAddressString = endpointAddress.getHostAddress();
+ // Perform some safety checks before inserting the address in place.
+ // Position 0 in mDaemons and mArguments must be racoon, and position 1 must be mtpd.
+ if (!"racoon".equals(mDaemons[0]) || !"mtpd".equals(mDaemons[1])) {
+ throw new IllegalStateException("Unexpected daemons order");
+ }
+
+ // Respectively, the positions at which racoon and mtpd take the server address
+ // argument are 1 and 2. Not all types of VPN require both daemons however, and
+ // in that case the corresponding argument array is null.
+ if (mArguments[0] != null) {
+ if (!mProfile.server.equals(mArguments[0][1])) {
+ throw new IllegalStateException("Invalid server argument for racoon");
+ }
+ mArguments[0][1] = endpointAddressString;
+ }
+
+ if (mArguments[1] != null) {
+ if (!mProfile.server.equals(mArguments[1][2])) {
+ throw new IllegalStateException("Invalid server argument for mtpd");
+ }
+ mArguments[1][2] = endpointAddressString;
+ }
+ }
+
private void bringup() {
// Catch all exceptions so we can clean up a few things.
try {
+ // resolve never returns null. If it does because of some bug, it will be
+ // caught by the catch() block below and cleanup gracefully.
+ final InetAddress endpointAddress = mDeps.resolve(mProfile.server);
+
+ // Big hack : dynamically replace the address of the server in the arguments
+ // with the resolved address.
+ checkAndFixupArguments(endpointAddress);
+
// Initialize the timer.
mBringupStartTime = SystemClock.elapsedRealtime();
// Wait for the daemons to stop.
for (String daemon : mDaemons) {
- while (!SystemService.isStopped(daemon)) {
+ while (!mDeps.isServiceStopped(daemon)) {
checkInterruptAndDelay(true);
}
}
// Clear the previous state.
- File state = new File("/data/misc/vpn/state");
+ final File state = mDeps.getStateFile();
state.delete();
if (state.exists()) {
throw new IllegalStateException("Cannot delete the state");
@@ -2696,57 +2863,19 @@ public class Vpn {
// Start the daemon.
String daemon = mDaemons[i];
- SystemService.start(daemon);
+ mDeps.startService(daemon);
// Wait for the daemon to start.
- while (!SystemService.isRunning(daemon)) {
+ while (!mDeps.isServiceRunning(daemon)) {
checkInterruptAndDelay(true);
}
// Create the control socket.
mSockets[i] = new LocalSocket();
- LocalSocketAddress address = new LocalSocketAddress(
- daemon, LocalSocketAddress.Namespace.RESERVED);
-
- // Wait for the socket to connect.
- while (true) {
- try {
- mSockets[i].connect(address);
- break;
- } catch (Exception e) {
- // ignore
- }
- checkInterruptAndDelay(true);
- }
- mSockets[i].setSoTimeout(500);
-
- // Send over the arguments.
- OutputStream out = mSockets[i].getOutputStream();
- for (String argument : arguments) {
- byte[] bytes = argument.getBytes(StandardCharsets.UTF_8);
- if (bytes.length >= 0xFFFF) {
- throw new IllegalArgumentException("Argument is too large");
- }
- out.write(bytes.length >> 8);
- out.write(bytes.length);
- out.write(bytes);
- checkInterruptAndDelay(false);
- }
- out.write(0xFF);
- out.write(0xFF);
-
- // Wait for End-of-File.
- InputStream in = mSockets[i].getInputStream();
- while (true) {
- try {
- if (in.read() == -1) {
- break;
- }
- } catch (Exception e) {
- // ignore
- }
- checkInterruptAndDelay(true);
- }
+
+ // Wait for the socket to connect and send over the arguments.
+ mDeps.sendArgumentsToDaemon(daemon, mSockets[i], arguments,
+ this::checkInterruptAndDelay);
}
// Wait for the daemons to create the new state.
@@ -2754,7 +2883,7 @@ public class Vpn {
// Check if a running daemon is dead.
for (int i = 0; i < mDaemons.length; ++i) {
String daemon = mDaemons[i];
- if (mArguments[i] != null && !SystemService.isRunning(daemon)) {
+ if (mArguments[i] != null && !mDeps.isServiceRunning(daemon)) {
throw new IllegalStateException(daemon + " is dead");
}
}
@@ -2764,7 +2893,8 @@ public class Vpn {
// Now we are connected. Read and parse the new state.
String[] parameters = FileUtils.readTextFile(state, 0, null).split("\n", -1);
if (parameters.length != 7) {
- throw new IllegalStateException("Cannot parse the state");
+ throw new IllegalStateException("Cannot parse the state: '"
+ + String.join("', '", parameters) + "'");
}
// Set the interface and the addresses in the config.
@@ -2793,20 +2923,15 @@ public class Vpn {
}
// Add a throw route for the VPN server endpoint, if one was specified.
- String endpoint = parameters[5].isEmpty() ? mProfile.server : parameters[5];
- if (!endpoint.isEmpty()) {
- try {
- InetAddress addr = InetAddress.parseNumericAddress(endpoint);
- if (addr instanceof Inet4Address) {
- mConfig.routes.add(new RouteInfo(new IpPrefix(addr, 32), RTN_THROW));
- } else if (addr instanceof Inet6Address) {
- mConfig.routes.add(new RouteInfo(new IpPrefix(addr, 128), RTN_THROW));
- } else {
- Log.e(TAG, "Unknown IP address family for VPN endpoint: " + endpoint);
- }
- } catch (IllegalArgumentException e) {
- Log.e(TAG, "Exception constructing throw route to " + endpoint + ": " + e);
- }
+ if (endpointAddress instanceof Inet4Address) {
+ mConfig.routes.add(new RouteInfo(
+ new IpPrefix(endpointAddress, 32), RTN_THROW));
+ } else if (endpointAddress instanceof Inet6Address) {
+ mConfig.routes.add(new RouteInfo(
+ new IpPrefix(endpointAddress, 128), RTN_THROW));
+ } else {
+ Log.e(TAG, "Unknown IP address family for VPN endpoint: "
+ + endpointAddress);
}
// Here is the last step and it must be done synchronously.
@@ -2818,7 +2943,7 @@ public class Vpn {
checkInterruptAndDelay(false);
// Check if the interface is gone while we are waiting.
- if (jniCheck(mConfig.interfaze) == 0) {
+ if (mDeps.checkInterfacePresent(Vpn.this, mConfig.interfaze)) {
throw new IllegalStateException(mConfig.interfaze + " is gone");
}
@@ -2849,7 +2974,7 @@ public class Vpn {
while (true) {
Thread.sleep(2000);
for (int i = 0; i < mDaemons.length; i++) {
- if (mArguments[i] != null && SystemService.isStopped(mDaemons[i])) {
+ if (mArguments[i] != null && mDeps.isServiceStopped(mDaemons[i])) {
return;
}
}
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index 74ed815f080a..5a4237938086 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -17,6 +17,7 @@
package com.android.server.input;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
@@ -66,6 +67,7 @@ import android.provider.DeviceConfig;
import android.provider.Settings;
import android.provider.Settings.SettingNotFoundException;
import android.text.TextUtils;
+import android.util.ArrayMap;
import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
@@ -181,8 +183,7 @@ public class InputManagerService extends IInputManager.Stub
// State for vibrator tokens.
private Object mVibratorLock = new Object();
- private HashMap<IBinder, VibratorToken> mVibratorTokens =
- new HashMap<IBinder, VibratorToken>();
+ private Map<IBinder, VibratorToken> mVibratorTokens = new ArrayMap<IBinder, VibratorToken>();
private int mNextVibratorTokenValue;
// State for the currently installed input filter.
@@ -190,12 +191,16 @@ public class InputManagerService extends IInputManager.Stub
IInputFilter mInputFilter; // guarded by mInputFilterLock
InputFilterHost mInputFilterHost; // guarded by mInputFilterLock
+ private final Object mGestureMonitorPidsLock = new Object();
+ @GuardedBy("mGestureMonitorPidsLock")
+ private final ArrayMap<IBinder, Integer> mGestureMonitorPidsByToken = new ArrayMap<>();
+
// The associations of input devices to displays by port. Maps from input device port (String)
// to display id (int). Currently only accessed by InputReader.
private final Map<String, Integer> mStaticAssociations;
private final Object mAssociationsLock = new Object();
@GuardedBy("mAssociationLock")
- private final Map<String, Integer> mRuntimeAssociations = new HashMap<String, Integer>();
+ private final Map<String, Integer> mRuntimeAssociations = new ArrayMap<String, Integer>();
private static native long nativeInit(InputManagerService service,
Context context, MessageQueue messageQueue);
@@ -540,13 +545,17 @@ public class InputManagerService extends IInputManager.Stub
if (displayId < Display.DEFAULT_DISPLAY) {
throw new IllegalArgumentException("displayId must >= 0.");
}
+ final int pid = Binder.getCallingPid();
final long ident = Binder.clearCallingIdentity();
try {
InputChannel[] inputChannels = InputChannel.openInputChannelPair(inputChannelName);
InputMonitorHost host = new InputMonitorHost(inputChannels[0]);
- nativeRegisterInputMonitor(mPtr, inputChannels[0], displayId,
- true /*isGestureMonitor*/);
+ nativeRegisterInputMonitor(
+ mPtr, inputChannels[0], displayId, true /*isGestureMonitor*/);
+ synchronized (mGestureMonitorPidsLock) {
+ mGestureMonitorPidsByToken.put(inputChannels[1].getToken(), pid);
+ }
return new InputMonitor(inputChannels[1], host);
} finally {
Binder.restoreCallingIdentity(ident);
@@ -575,6 +584,9 @@ public class InputManagerService extends IInputManager.Stub
if (inputChannel == null) {
throw new IllegalArgumentException("inputChannel must not be null.");
}
+ synchronized (mGestureMonitorPidsLock) {
+ mGestureMonitorPidsByToken.remove(inputChannel.getToken());
+ }
nativeUnregisterInputChannel(mPtr, inputChannel);
}
@@ -1838,6 +1850,7 @@ public class InputManagerService extends IInputManager.Stub
if (dumpStr != null) {
pw.println(dumpStr);
dumpAssociations(pw);
+ dumpGestureMonitorPidsByToken(pw);
}
}
@@ -1861,6 +1874,19 @@ public class InputManagerService extends IInputManager.Stub
}
}
+ private void dumpGestureMonitorPidsByToken(PrintWriter pw) {
+ synchronized (mGestureMonitorPidsLock) {
+ if (!mGestureMonitorPidsByToken.isEmpty()) {
+ pw.println("Gesture monitor pids by token:");
+ for (int i = 0; i < mGestureMonitorPidsByToken.size(); i++) {
+ pw.print(" " + i + ": ");
+ pw.print(" token: " + mGestureMonitorPidsByToken.keyAt(i));
+ pw.println(" pid: " + mGestureMonitorPidsByToken.valueAt(i));
+ }
+ }
+ }
+ }
+
private boolean checkCallingPermission(String permission, String func) {
// Quick check: if the calling permission is me, it's all okay.
if (Binder.getCallingPid() == Process.myPid()) {
@@ -1883,6 +1909,7 @@ public class InputManagerService extends IInputManager.Stub
public void monitor() {
synchronized (mInputFilterLock) { }
synchronized (mAssociationsLock) { /* Test if blocked by associations lock. */}
+ synchronized (mGestureMonitorPidsLock) { /* Test if blocked by gesture monitor pids lock */}
nativeMonitor(mPtr);
}
@@ -1944,6 +1971,9 @@ public class InputManagerService extends IInputManager.Stub
// Native callback.
private void notifyInputChannelBroken(IBinder token) {
+ synchronized (mGestureMonitorPidsLock) {
+ mGestureMonitorPidsByToken.remove(token);
+ }
mWindowManagerCallbacks.notifyInputChannelBroken(token);
}
@@ -1959,8 +1989,12 @@ public class InputManagerService extends IInputManager.Stub
// Native callback.
private long notifyANR(InputApplicationHandle inputApplicationHandle, IBinder token,
String reason) {
- return mWindowManagerCallbacks.notifyANR(inputApplicationHandle,
- token, reason);
+ Integer gestureMonitorPid;
+ synchronized (mGestureMonitorPidsLock) {
+ gestureMonitorPid = mGestureMonitorPidsByToken.get(token);
+ }
+ return mWindowManagerCallbacks.notifyANR(inputApplicationHandle, token, gestureMonitorPid,
+ reason);
}
// Native callback.
@@ -2206,22 +2240,48 @@ public class InputManagerService extends IInputManager.Stub
* Callback interface implemented by the Window Manager.
*/
public interface WindowManagerCallbacks {
+ /**
+ * This callback is invoked when the confuguration changes.
+ */
public void notifyConfigurationChanged();
+ /**
+ * This callback is invoked when the lid switch changes state.
+ * @param whenNanos the time when the change occurred
+ * @param lidOpen true if the lid is open
+ */
public void notifyLidSwitchChanged(long whenNanos, boolean lidOpen);
+ /**
+ * This callback is invoked when the camera lens cover switch changes state.
+ * @param whenNanos the time when the change occurred
+ * @param lensCovered true is the lens is covered
+ */
public void notifyCameraLensCoverSwitchChanged(long whenNanos, boolean lensCovered);
+ /**
+ * This callback is invoked when an input channel is closed unexpectedly.
+ * @param token the connection token of the broken channel
+ */
public void notifyInputChannelBroken(IBinder token);
/**
- * Notifies the window manager about an application that is not responding.
- * Returns a new timeout to continue waiting in nanoseconds, or 0 to abort dispatch.
+ * Notify the window manager about an application that is not responding.
+ * Return a new timeout to continue waiting in nanoseconds, or 0 to abort dispatch.
*/
long notifyANR(InputApplicationHandle inputApplicationHandle, IBinder token,
- String reason);
+ @Nullable Integer pid, String reason);
- public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags);
+ /**
+ * This callback is invoked when an event first arrives to InputDispatcher and before it is
+ * placed onto InputDispatcher's queue. If this event is intercepted, it will never be
+ * processed by InputDispacher.
+ * @param event The key event that's arriving to InputDispatcher
+ * @param policyFlags The policy flags
+ * @return the flags that tell InputDispatcher how to handle the event (for example, whether
+ * to pass it to the user)
+ */
+ int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags);
/**
* Provides an opportunity for the window manager policy to intercept early motion event
@@ -2231,11 +2291,23 @@ public class InputManagerService extends IInputManager.Stub
int interceptMotionBeforeQueueingNonInteractive(int displayId, long whenNanos,
int policyFlags);
- public long interceptKeyBeforeDispatching(IBinder token,
- KeyEvent event, int policyFlags);
+ /**
+ * This callback is invoked just before the key is about to be sent to an application.
+ * This allows the policy to make some last minute decisions on whether to intercept this
+ * key.
+ * @param token the window token that's about to receive this event
+ * @param event the key event that's being dispatched
+ * @param policyFlags the policy flags
+ * @return negative value if the key should be skipped (not sent to the app). 0 if the key
+ * should proceed getting dispatched to the app. positive value to indicate the additional
+ * time delay, in nanoseconds, to wait before sending this key to the app.
+ */
+ long interceptKeyBeforeDispatching(IBinder token, KeyEvent event, int policyFlags);
- public KeyEvent dispatchUnhandledKey(IBinder token,
- KeyEvent event, int policyFlags);
+ /**
+ * Dispatch unhandled key
+ */
+ KeyEvent dispatchUnhandledKey(IBinder token, KeyEvent event, int policyFlags);
public int getPointerLayer();
diff --git a/services/core/java/com/android/server/location/LocationFudger.java b/services/core/java/com/android/server/location/LocationFudger.java
index 1f458ed4e29d..6f35c8ba1e0a 100644
--- a/services/core/java/com/android/server/location/LocationFudger.java
+++ b/services/core/java/com/android/server/location/LocationFudger.java
@@ -112,7 +112,7 @@ public class LocationFudger {
public Location createCoarse(Location fine) {
synchronized (this) {
if (fine == mCachedFineLocation) {
- return new Location(mCachedCoarseLocation);
+ return mCachedCoarseLocation;
}
}
@@ -154,7 +154,7 @@ public class LocationFudger {
mCachedCoarseLocation = coarse;
}
- return new Location(mCachedCoarseLocation);
+ return mCachedCoarseLocation;
}
/**
diff --git a/services/core/java/com/android/server/location/LocationManagerService.java b/services/core/java/com/android/server/location/LocationManagerService.java
index d3558f1458b8..71f1833854ce 100644
--- a/services/core/java/com/android/server/location/LocationManagerService.java
+++ b/services/core/java/com/android/server/location/LocationManagerService.java
@@ -17,43 +17,27 @@
package com.android.server.location;
import static android.Manifest.permission.ACCESS_FINE_LOCATION;
-import static android.app.AppOpsManager.OP_MOCK_LOCATION;
-import static android.app.AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION;
-import static android.app.AppOpsManager.OP_MONITOR_LOCATION;
import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE;
import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
-import static android.location.LocationManager.EXTRA_LOCATION_ENABLED;
-import static android.location.LocationManager.EXTRA_PROVIDER_ENABLED;
-import static android.location.LocationManager.EXTRA_PROVIDER_NAME;
import static android.location.LocationManager.FUSED_PROVIDER;
import static android.location.LocationManager.GPS_PROVIDER;
-import static android.location.LocationManager.KEY_LOCATION_CHANGED;
-import static android.location.LocationManager.KEY_PROVIDER_ENABLED;
-import static android.location.LocationManager.MODE_CHANGED_ACTION;
import static android.location.LocationManager.NETWORK_PROVIDER;
-import static android.location.LocationManager.PASSIVE_PROVIDER;
-import static android.location.LocationManager.PROVIDERS_CHANGED_ACTION;
-import static android.location.LocationManager.invalidateLocalLocationEnabledCaches;
-import static android.os.PowerManager.locationPowerSaveModeToString;
import static com.android.server.location.LocationPermissions.PERMISSION_COARSE;
import static com.android.server.location.LocationPermissions.PERMISSION_FINE;
-import static com.android.server.location.LocationPermissions.PERMISSION_NONE;
+import static com.android.server.location.LocationProviderManager.FASTEST_COARSE_INTERVAL_MS;
import static java.util.concurrent.TimeUnit.NANOSECONDS;
import android.Manifest.permission;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.annotation.UserIdInt;
import android.app.ActivityManager;
import android.app.AppOpsManager;
import android.app.PendingIntent;
-import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
-import android.content.IntentFilter;
import android.location.Criteria;
import android.location.GeocoderParams;
import android.location.Geofence;
@@ -78,17 +62,9 @@ import android.location.LocationRequest;
import android.location.LocationTime;
import android.location.util.identity.CallerIdentity;
import android.os.Binder;
-import android.os.Build;
import android.os.Bundle;
-import android.os.CancellationSignal;
-import android.os.Handler;
-import android.os.IBinder;
import android.os.ICancellationSignal;
-import android.os.IRemoteCallback;
import android.os.ParcelFileDescriptor;
-import android.os.PowerManager;
-import android.os.PowerManager.ServiceType;
-import android.os.PowerManagerInternal;
import android.os.Process;
import android.os.RemoteException;
import android.os.SystemClock;
@@ -96,24 +72,16 @@ import android.os.UserHandle;
import android.os.WorkSource;
import android.os.WorkSource.WorkChain;
import android.stats.location.LocationStatsEnums;
-import android.text.TextUtils;
-import android.util.EventLog;
import android.util.IndentingPrintWriter;
import android.util.Log;
-import android.util.SparseArray;
import android.util.TimeUtils;
import com.android.internal.annotations.GuardedBy;
-import com.android.internal.content.PackageMonitor;
import com.android.internal.location.ProviderProperties;
-import com.android.internal.location.ProviderRequest;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.Preconditions;
-import com.android.server.FgThread;
import com.android.server.LocalServices;
-import com.android.server.PendingIntentUtils;
import com.android.server.SystemService;
-import com.android.server.location.AbstractLocationProvider.State;
import com.android.server.location.LocationPermissions.PermissionLevel;
import com.android.server.location.LocationRequestStatistics.PackageProviderKey;
import com.android.server.location.LocationRequestStatistics.PackageStatistics;
@@ -137,24 +105,17 @@ import com.android.server.location.util.SystemScreenInteractiveHelper;
import com.android.server.location.util.SystemSettingsHelper;
import com.android.server.location.util.SystemUserInfoHelper;
import com.android.server.location.util.UserInfoHelper;
-import com.android.server.location.util.UserInfoHelper.UserListener;
import com.android.server.pm.permission.PermissionManagerServiceInternal;
-import java.io.ByteArrayOutputStream;
import java.io.FileDescriptor;
-import java.io.PrintStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
import java.util.List;
import java.util.Map;
-import java.util.Map.Entry;
import java.util.Objects;
import java.util.TreeMap;
import java.util.concurrent.CopyOnWriteArrayList;
-import java.util.concurrent.Executor;
/**
* The service class that manages LocationProviders and issues location
@@ -241,54 +202,21 @@ public class LocationManagerService extends ILocationManager.Stub {
public static final String TAG = "LocationManagerService";
public static final boolean D = Log.isLoggable(TAG, Log.DEBUG);
- private static final String WAKELOCK_KEY = "*location*";
-
private static final String NETWORK_LOCATION_SERVICE_ACTION =
"com.android.location.service.v3.NetworkLocationProvider";
private static final String FUSED_LOCATION_SERVICE_ACTION =
"com.android.location.service.FusedLocationProvider";
- // The maximum interval a location request can have and still be considered "high power".
- private static final long HIGH_POWER_INTERVAL_MS = 5 * 60 * 1000;
-
- // The fastest interval that applications can receive coarse locations
- private static final long FASTEST_COARSE_INTERVAL_MS = 10 * 60 * 1000;
-
- // maximum age of a location before it is no longer considered "current"
- private static final long MAX_CURRENT_LOCATION_AGE_MS = 10 * 1000;
-
- // Location Providers may sometimes deliver location updates
- // slightly faster that requested - provide grace period so
- // we don't unnecessarily filter events that are otherwise on
- // time
- private static final int MAX_PROVIDER_SCHEDULING_JITTER_MS = 100;
-
- private static final long GET_CURRENT_LOCATION_MAX_TIMEOUT_MS = 30000;
-
private static final String ATTRIBUTION_TAG = "LocationService";
private final Object mLock = new Object();
- private final Handler mHandler;
- private final LocalService mLocalService;
-
- private final Injector mInjector;
-
private final Context mContext;
- private final AppOpsHelper mAppOpsHelper;
- private final UserInfoHelper mUserInfoHelper;
- private final SettingsHelper mSettingsHelper;
- private final AppForegroundHelper mAppForegroundHelper;
- private final LocationUsageLogger mLocationUsageLogger;
+ private final Injector mInjector;
+ private final LocalService mLocalService;
private final GeofenceManager mGeofenceManager;
-
@Nullable private volatile GnssManagerService mGnssManagerService = null;
-
- private final PassiveLocationProviderManager mPassiveManager;
-
- private PowerManager mPowerManager;
-
private GeocoderProxy mGeocodeProvider;
@GuardedBy("mLock")
@@ -296,46 +224,30 @@ public class LocationManagerService extends ILocationManager.Stub {
@GuardedBy("mLock")
private boolean mExtraLocationControllerPackageEnabled;
- // @GuardedBy("mLock")
- // hold lock for write or to prevent write, no lock for read
- final CopyOnWriteArrayList<LocationProviderManager> mProviderManagers =
- new CopyOnWriteArrayList<>();
-
- @GuardedBy("mLock")
- private final HashMap<Object, Receiver> mReceivers = new HashMap<>();
- private final HashMap<String, ArrayList<UpdateRecord>> mRecordsByProvider =
- new HashMap<>();
+ // location provider managers
- private final LocationRequestStatistics mRequestStatistics = new LocationRequestStatistics();
+ private final PassiveLocationProviderManager mPassiveManager;
- @GuardedBy("mLock")
- @PowerManager.LocationPowerSaveMode
- private int mBatterySaverMode;
+ // @GuardedBy("mProviderManagers")
+ // hold lock for writes, no lock necessary for simple reads
+ private final CopyOnWriteArrayList<LocationProviderManager> mProviderManagers =
+ new CopyOnWriteArrayList<>();
LocationManagerService(Context context, Injector injector) {
- mHandler = FgThread.getHandler();
- mLocalService = new LocalService();
-
- LocalServices.addService(LocationManagerInternal.class, mLocalService);
-
+ mContext = context.createAttributionContext(ATTRIBUTION_TAG);
mInjector = injector;
- mContext = context.createAttributionContext(ATTRIBUTION_TAG);
- mUserInfoHelper = injector.getUserInfoHelper();
- mAppOpsHelper = injector.getAppOpsHelper();
- mSettingsHelper = injector.getSettingsHelper();
- mAppForegroundHelper = injector.getAppForegroundHelper();
- mLocationUsageLogger = injector.getLocationUsageLogger();
+ mLocalService = new LocalService();
+ LocalServices.addService(LocationManagerInternal.class, mLocalService);
mGeofenceManager = new GeofenceManager(mContext, injector);
- // set up passive provider - we do this early because it has no dependencies on system
- // services or external code that isn't ready yet, and because this allows the variable to
- // be final. other more complex providers are initialized later, when system services are
- // ready
- mPassiveManager = new PassiveLocationProviderManager();
- mProviderManagers.add(mPassiveManager);
- mPassiveManager.setRealProvider(new PassiveProvider(mContext));
+ // set up passive provider first since it will be required for all other location providers,
+ // which are loaded later once the system is ready.
+ mPassiveManager = new PassiveLocationProviderManager(mContext, injector);
+ addLocationProviderManager(mPassiveManager, new PassiveProvider(mContext));
+
+ // TODO: load the gps provider here as well, which will require refactoring
// Let the package manager query which are the default location
// providers as they get certain permissions granted by default.
@@ -347,253 +259,77 @@ public class LocationManagerService extends ILocationManager.Stub {
permissionManagerInternal.setLocationExtraPackagesProvider(
userId -> mContext.getResources().getStringArray(
com.android.internal.R.array.config_locationExtraPackageNames));
-
- // most startup is deferred until systemReady()
- }
-
- void onSystemReady() {
- synchronized (mLock) {
- mPowerManager = mContext.getSystemService(PowerManager.class);
-
- // add listeners
- mContext.getPackageManager().addOnPermissionsChangeListener(
- uid -> {
- // listener invoked on ui thread, move to our thread to reduce risk of
- // blocking ui thread
- mHandler.post(() -> {
- synchronized (mLock) {
- onPermissionsChangedLocked();
- }
- });
- });
-
- LocalServices.getService(PowerManagerInternal.class).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();
-
- mAppOpsHelper.addListener(this::onAppOpChanged);
-
- mSettingsHelper.addOnLocationEnabledChangedListener(this::onLocationModeChanged);
- mSettingsHelper.addOnBackgroundThrottleIntervalChangedListener(
- this::onBackgroundThrottleIntervalChanged);
- mSettingsHelper.addOnBackgroundThrottlePackageWhitelistChangedListener(
- this::onBackgroundThrottleWhitelistChanged);
- mSettingsHelper.addOnIgnoreSettingsPackageWhitelistChangedListener(
- this::onIgnoreSettingsWhitelistChanged);
-
- PackageMonitor packageMonitor = new PackageMonitor() {
- @Override
- public void onPackageDisappeared(String packageName, int reason) {
- synchronized (mLock) {
- LocationManagerService.this.onPackageDisappeared(packageName);
- }
- }
- };
- packageMonitor.register(mContext, null, true, mHandler);
-
- mUserInfoHelper.addListener(this::onUserChanged);
-
- mAppForegroundHelper.addListener(this::onAppForegroundChanged);
-
- IntentFilter screenIntentFilter = new IntentFilter();
- screenIntentFilter.addAction(Intent.ACTION_SCREEN_OFF);
- screenIntentFilter.addAction(Intent.ACTION_SCREEN_ON);
- mContext.registerReceiverAsUser(new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- if (Intent.ACTION_SCREEN_ON.equals(intent.getAction())
- || Intent.ACTION_SCREEN_OFF.equals(intent.getAction())) {
- onScreenStateChanged();
- }
- }
- }, UserHandle.ALL, screenIntentFilter, null, mHandler);
-
- // initialize the current users. we would get the user started notifications for these
- // users eventually anyways, but this takes care of it as early as possible.
- onUserChanged(UserHandle.USER_ALL, UserListener.USER_STARTED);
- }
}
- void onSystemThirdPartyAppsCanStart() {
- synchronized (mLock) {
- // prepare providers
- initializeProvidersLocked();
- }
-
- // initialize gnss last because it has no awareness of boot phases and blindly assumes that
- // all other location providers are loaded at initialization
- initializeGnss();
- }
-
- private void onAppOpChanged(String packageName) {
- synchronized (mLock) {
- for (Receiver receiver : mReceivers.values()) {
- if (receiver.mCallerIdentity.getPackageName().equals(packageName)) {
- receiver.updateMonitoring(true);
- }
- }
-
- HashSet<String> affectedProviders = new HashSet<>(mRecordsByProvider.size());
- for (Entry<String, ArrayList<UpdateRecord>> entry : mRecordsByProvider.entrySet()) {
- String provider = entry.getKey();
- for (UpdateRecord record : entry.getValue()) {
- if (record.mReceiver.mCallerIdentity.getPackageName().equals(packageName)) {
- affectedProviders.add(provider);
- }
- }
- }
- for (String provider : affectedProviders) {
- applyRequirementsLocked(provider);
- }
- }
- }
-
- @GuardedBy("mLock")
- private void onPermissionsChangedLocked() {
- for (LocationProviderManager manager : mProviderManagers) {
- applyRequirementsLocked(manager);
- }
- }
-
- @GuardedBy("mLock")
- private void onBatterySaverModeChangedLocked(int newLocationMode) {
- if (mBatterySaverMode == newLocationMode) {
- return;
- }
-
- if (D) {
- Log.d(TAG,
- "Battery Saver location mode changed from "
- + locationPowerSaveModeToString(mBatterySaverMode) + " to "
- + locationPowerSaveModeToString(newLocationMode));
+ @Nullable
+ private LocationProviderManager getLocationProviderManager(String providerName) {
+ if (providerName == null) {
+ return null;
}
- mBatterySaverMode = newLocationMode;
-
for (LocationProviderManager manager : mProviderManagers) {
- applyRequirementsLocked(manager);
- }
- }
-
- private void onScreenStateChanged() {
- synchronized (mLock) {
- if (mBatterySaverMode == PowerManager.LOCATION_MODE_THROTTLE_REQUESTS_WHEN_SCREEN_OFF) {
- for (LocationProviderManager manager : mProviderManagers) {
- applyRequirementsLocked(manager);
- }
+ if (providerName.equals(manager.getName())) {
+ return manager;
}
}
- }
-
- private void onLocationModeChanged(int userId) {
- boolean enabled = mSettingsHelper.isLocationEnabled(userId);
- LocationManager.invalidateLocalLocationEnabledCaches();
- if (D) {
- Log.d(TAG, "[u" + userId + "] location enabled = " + enabled);
- }
-
- Intent intent = new Intent(MODE_CHANGED_ACTION)
- .putExtra(EXTRA_LOCATION_ENABLED, enabled)
- .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY)
- .addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
- mContext.sendBroadcastAsUser(intent, UserHandle.of(userId));
-
- synchronized (mLock) {
- for (LocationProviderManager manager : mProviderManagers) {
- manager.onEnabledChangedLocked(userId);
- }
- }
+ return null;
}
- private void onPackageDisappeared(String packageName) {
- synchronized (mLock) {
- ArrayList<Receiver> deadReceivers = null;
-
- for (Receiver receiver : mReceivers.values()) {
- if (receiver.mCallerIdentity.getPackageName().equals(packageName)) {
- if (deadReceivers == null) {
- deadReceivers = new ArrayList<>();
- }
- deadReceivers.add(receiver);
+ private LocationProviderManager getOrAddLocationProviderManager(String providerName) {
+ synchronized (mProviderManagers) {
+ for (LocationProviderManager manager : mProviderManagers) {
+ if (providerName.equals(manager.getName())) {
+ return manager;
}
}
- // perform removal outside of mReceivers loop
- if (deadReceivers != null) {
- for (Receiver receiver : deadReceivers) {
- removeUpdatesLocked(receiver);
- }
- }
+ LocationProviderManager manager = new LocationProviderManager(mContext, mInjector,
+ providerName, mPassiveManager);
+ addLocationProviderManager(manager, null);
+ return manager;
}
}
- private void onAppForegroundChanged(int uid, boolean foreground) {
- synchronized (mLock) {
- HashSet<String> affectedProviders = new HashSet<>(mRecordsByProvider.size());
- for (Entry<String, ArrayList<UpdateRecord>> entry : mRecordsByProvider.entrySet()) {
- String provider = entry.getKey();
- for (UpdateRecord record : entry.getValue()) {
- if (record.mReceiver.mCallerIdentity.getUid() == uid
- && record.mIsForegroundUid != foreground) {
- record.updateForeground(foreground);
-
- if (!isThrottlingExempt(record.mReceiver.mCallerIdentity)) {
- affectedProviders.add(provider);
- }
- }
- }
- }
- for (String provider : affectedProviders) {
- applyRequirementsLocked(provider);
- }
- }
- }
+ private void addLocationProviderManager(LocationProviderManager manager,
+ @Nullable AbstractLocationProvider realProvider) {
+ synchronized (mProviderManagers) {
+ Preconditions.checkState(getLocationProviderManager(manager.getName()) == null);
- private void onBackgroundThrottleIntervalChanged() {
- synchronized (mLock) {
- for (LocationProviderManager manager : mProviderManagers) {
- applyRequirementsLocked(manager);
+ manager.startManager();
+ if (realProvider != null) {
+ manager.setRealProvider(realProvider);
}
+ mProviderManagers.add(manager);
}
}
- private void onBackgroundThrottleWhitelistChanged() {
- synchronized (mLock) {
- for (LocationProviderManager manager : mProviderManagers) {
- applyRequirementsLocked(manager);
- }
+ private void removeLocationProviderManager(LocationProviderManager manager) {
+ synchronized (mProviderManagers) {
+ Preconditions.checkState(getLocationProviderManager(manager.getName()) == manager);
+
+ mProviderManagers.remove(manager);
+ manager.setMockProvider(null);
+ manager.setRealProvider(null);
+ manager.stopManager();
}
}
- private void onIgnoreSettingsWhitelistChanged() {
- synchronized (mLock) {
- for (LocationProviderManager manager : mProviderManagers) {
- applyRequirementsLocked(manager);
- }
- }
+ void onSystemReady() {
+ mInjector.getSettingsHelper().addOnLocationEnabledChangedListener(
+ this::onLocationModeChanged);
}
- @GuardedBy("mLock")
- private void initializeProvidersLocked() {
+ void onSystemThirdPartyAppsCanStart() {
LocationProviderProxy networkProvider = LocationProviderProxy.createAndRegister(
mContext,
NETWORK_LOCATION_SERVICE_ACTION,
com.android.internal.R.bool.config_enableNetworkLocationOverlay,
com.android.internal.R.string.config_networkLocationProviderPackageName);
if (networkProvider != null) {
- LocationProviderManager networkManager = new LocationProviderManager(NETWORK_PROVIDER);
- mProviderManagers.add(networkManager);
- networkManager.setRealProvider(networkProvider);
+ LocationProviderManager networkManager = new LocationProviderManager(mContext,
+ mInjector, NETWORK_PROVIDER, mPassiveManager);
+ addLocationProviderManager(networkManager, networkProvider);
} else {
Log.w(TAG, "no network location provider found");
}
@@ -604,18 +340,28 @@ public class LocationManagerService extends ILocationManager.Stub {
MATCH_DIRECT_BOOT_AWARE | MATCH_SYSTEM_ONLY, UserHandle.USER_SYSTEM).isEmpty(),
"Unable to find a direct boot aware fused location provider");
- // bind to fused provider
LocationProviderProxy fusedProvider = LocationProviderProxy.createAndRegister(
mContext,
FUSED_LOCATION_SERVICE_ACTION,
com.android.internal.R.bool.config_enableFusedLocationOverlay,
com.android.internal.R.string.config_fusedLocationProviderPackageName);
if (fusedProvider != null) {
- LocationProviderManager fusedManager = new LocationProviderManager(FUSED_PROVIDER);
- mProviderManagers.add(fusedManager);
- fusedManager.setRealProvider(fusedProvider);
+ LocationProviderManager fusedManager = new LocationProviderManager(mContext, mInjector,
+ FUSED_PROVIDER, mPassiveManager);
+ addLocationProviderManager(fusedManager, fusedProvider);
} else {
- Log.e(TAG, "no fused location provider found");
+ Log.wtf(TAG, "no fused location provider found");
+ }
+
+ // initialize gnss last because it has no awareness of boot phases and blindly assumes that
+ // all other location providers are loaded at initialization
+ if (GnssManagerService.isGnssSupported()) {
+ mGnssManagerService = new GnssManagerService(mContext, mInjector);
+ mGnssManagerService.onSystemReady();
+
+ LocationProviderManager gnssManager = new LocationProviderManager(mContext, mInjector,
+ GPS_PROVIDER, mPassiveManager);
+ addLocationProviderManager(gnssManager, mGnssManagerService.getGnssLocationProvider());
}
// bind to geocoder provider
@@ -631,6 +377,18 @@ public class LocationManagerService extends ILocationManager.Stub {
Log.e(TAG, "unable to bind ActivityRecognitionProxy");
}
+ // bind to gnss geofence proxy
+ if (GnssManagerService.isGnssSupported()) {
+ IGpsGeofenceHardware gpsGeofenceHardware = mGnssManagerService.getGpsGeofenceProxy();
+ if (gpsGeofenceHardware != null) {
+ GeofenceProxy provider = GeofenceProxy.createAndBind(mContext, gpsGeofenceHardware);
+ if (provider == null) {
+ Log.e(TAG, "unable to bind to GeofenceProxy");
+ }
+ }
+ }
+
+ // create any predefined test providers
String[] testProviderStrings = mContext.getResources().getStringArray(
com.android.internal.R.array.config_testLocationProviders);
for (String testProviderString : testProviderStrings) {
@@ -646,763 +404,24 @@ public class LocationManagerService extends ILocationManager.Stub {
Boolean.parseBoolean(fragments[7]) /* supportsBearing */,
Integer.parseInt(fragments[8]) /* powerRequirement */,
Integer.parseInt(fragments[9]) /* accuracy */);
- LocationProviderManager manager = getLocationProviderManager(name);
- if (manager == null) {
- manager = new LocationProviderManager(name);
- mProviderManagers.add(manager);
- }
- manager.setMockProvider(
+ getOrAddLocationProviderManager(name).setMockProvider(
new MockProvider(properties, CallerIdentity.fromContext(mContext)));
}
}
- private void initializeGnss() {
- // Do not hold mLock when calling GnssManagerService#isGnssSupported() which calls into HAL.
- if (GnssManagerService.isGnssSupported()) {
- mGnssManagerService = new GnssManagerService(mContext, mInjector);
- mGnssManagerService.onSystemReady();
-
- LocationProviderManager gnssManager = new LocationProviderManager(GPS_PROVIDER);
- synchronized (mLock) {
- mProviderManagers.add(gnssManager);
- }
- gnssManager.setRealProvider(mGnssManagerService.getGnssLocationProvider());
-
- // bind to geofence proxy
- IGpsGeofenceHardware gpsGeofenceHardware = mGnssManagerService.getGpsGeofenceProxy();
- if (gpsGeofenceHardware != null) {
- GeofenceProxy provider = GeofenceProxy.createAndBind(mContext, gpsGeofenceHardware);
- if (provider == null) {
- Log.e(TAG, "unable to bind to GeofenceProxy");
- }
- }
- }
- }
-
- private void onUserChanged(@UserIdInt int userId, @UserListener.UserChange int change) {
- switch (change) {
- case UserListener.CURRENT_USER_CHANGED:
- synchronized (mLock) {
- for (LocationProviderManager manager : mProviderManagers) {
- manager.onEnabledChangedLocked(userId);
- }
- }
- break;
- case UserListener.USER_STARTED:
- synchronized (mLock) {
- for (LocationProviderManager manager : mProviderManagers) {
- manager.onUserStarted(userId);
- }
- }
- break;
- case UserListener.USER_STOPPED:
- synchronized (mLock) {
- for (LocationProviderManager manager : mProviderManagers) {
- manager.onUserStopped(userId);
- }
- }
- break;
- }
- }
-
- /**
- * Location provider manager, manages a LocationProvider.
- */
- class LocationProviderManager implements MockableLocationProvider.Listener {
-
- private final String mName;
-
- private final LocationFudger mLocationFudger;
-
- // if the provider is enabled for a given user id - null or not present means unknown
- @GuardedBy("mLock")
- private final SparseArray<Boolean> mEnabled;
-
- // last location for a given user
- @GuardedBy("mLock")
- private final SparseArray<Location> mLastLocation;
-
- // last coarse location for a given user
- @GuardedBy("mLock")
- private final SparseArray<Location> mLastCoarseLocation;
-
- // acquiring mLock makes operations on mProvider atomic, but is otherwise unnecessary
- protected final MockableLocationProvider mProvider;
-
- LocationProviderManager(String name) {
- mName = name;
- mLocationFudger = new LocationFudger(mSettingsHelper.getCoarseLocationAccuracyM());
- mEnabled = new SparseArray<>(2);
- mLastLocation = new SparseArray<>(2);
- mLastCoarseLocation = new SparseArray<>(2);
-
- // initialize last since this lets our reference escape
- mProvider = new MockableLocationProvider(mLock, this);
- }
-
- public String getName() {
- return mName;
- }
-
- public boolean hasProvider() {
- return mProvider.getProvider() != null;
- }
-
- public void setRealProvider(AbstractLocationProvider provider) {
- mProvider.setRealProvider(provider);
- }
-
- public void setMockProvider(@Nullable MockProvider provider) {
- synchronized (mLock) {
- mProvider.setMockProvider(provider);
-
- // when removing a mock provider, also clear any mock last locations and reset the
- // location fudger. the mock provider could have been used to infer the current
- // location fudger offsets.
- if (provider == null) {
- for (int i = 0; i < mLastLocation.size(); i++) {
- Location lastLocation = mLastLocation.valueAt(i);
- if (lastLocation != null && lastLocation.isFromMockProvider()) {
- mLastLocation.setValueAt(i, null);
- }
- }
-
- for (int i = 0; i < mLastCoarseLocation.size(); i++) {
- Location lastCoarseLocation = mLastCoarseLocation.valueAt(i);
- if (lastCoarseLocation != null && lastCoarseLocation.isFromMockProvider()) {
- mLastCoarseLocation.setValueAt(i, null);
- }
- }
-
- mLocationFudger.resetOffsets();
- }
- }
- }
-
- @Nullable
- public CallerIdentity getProviderIdentity() {
- return mProvider.getState().identity;
- }
-
- @Nullable
- public ProviderProperties getProperties() {
- return mProvider.getState().properties;
- }
-
- @Nullable
- public Location getLastLocation(int userId, @PermissionLevel int permissionlevel) {
- synchronized (mLock) {
- switch (permissionlevel) {
- case PERMISSION_COARSE:
- return mLastCoarseLocation.get(userId);
- case PERMISSION_FINE:
- return mLastLocation.get(userId);
- default:
- throw new AssertionError();
- }
- }
- }
-
- public void injectLastLocation(Location location, int userId) {
- synchronized (mLock) {
- if (mLastLocation.get(userId) == null) {
- setLastLocation(location, userId);
- }
- }
- }
-
- private void setLastLocation(Location location, int userId) {
- synchronized (mLock) {
- mLastLocation.put(userId, location);
-
- // update last coarse interval only if enough time has passed
- long timeDeltaMs = Long.MAX_VALUE;
- Location coarseLocation = mLastCoarseLocation.get(userId);
- if (coarseLocation != null) {
- timeDeltaMs = NANOSECONDS.toMillis(location.getElapsedRealtimeNanos())
- - NANOSECONDS.toMillis(coarseLocation.getElapsedRealtimeNanos());
- }
- if (timeDeltaMs > FASTEST_COARSE_INTERVAL_MS) {
- mLastCoarseLocation.put(userId, mLocationFudger.createCoarse(location));
- }
- }
- }
-
- public void setMockProviderAllowed(boolean enabled) {
- synchronized (mLock) {
- if (!mProvider.isMock()) {
- throw new IllegalArgumentException(mName + " provider is not a test provider");
- }
-
- mProvider.setMockProviderAllowed(enabled);
- }
- }
-
- public void setMockProviderLocation(Location location) {
- synchronized (mLock) {
- if (!mProvider.isMock()) {
- throw new IllegalArgumentException(mName + " provider is not a test provider");
- }
-
- String locationProvider = location.getProvider();
- if (!TextUtils.isEmpty(locationProvider) && !mName.equals(locationProvider)) {
- // The location has an explicit provider that is different from the mock
- // provider name. The caller may be trying to fool us via b/33091107.
- EventLog.writeEvent(0x534e4554, "33091107", Binder.getCallingUid(),
- mName + "!=" + locationProvider);
- }
-
- mProvider.setMockProviderLocation(location);
- }
- }
-
- public List<LocationRequest> getMockProviderRequests() {
- synchronized (mLock) {
- if (!mProvider.isMock()) {
- throw new IllegalArgumentException(mName + " provider is not a test provider");
- }
-
- return mProvider.getCurrentRequest().locationRequests;
- }
- }
-
- public void setRequest(ProviderRequest request) {
- mProvider.setRequest(request);
- }
-
- public void sendExtraCommand(int uid, int pid, String command, Bundle extras) {
- mProvider.sendExtraCommand(uid, pid, command, extras);
- }
-
- @GuardedBy("mLock")
- @Override
- public void onReportLocation(Location location) {
- // don't validate mock locations
- if (!location.isFromMockProvider()) {
- if (location.getLatitude() == 0 && location.getLongitude() == 0) {
- Log.w(TAG, "blocking 0,0 location from " + mName + " provider");
- return;
- }
- }
-
- if (!location.isComplete()) {
- Log.w(TAG, "blocking incomplete location from " + mName + " provider");
- return;
- }
-
- // update last location if the provider is enabled or if servicing a bypass request
- boolean locationSettingsIgnored = mProvider.getCurrentRequest().locationSettingsIgnored;
- for (int userId : mUserInfoHelper.getRunningUserIds()) {
- if (locationSettingsIgnored || isEnabled(userId)) {
- setLastLocation(location, userId);
- }
- }
-
- handleLocationChangedLocked(this, location, mLocationFudger.createCoarse(location));
- }
-
- @GuardedBy("mLock")
- @Override
- public void onReportLocation(List<Location> locations) {
- if (mGnssManagerService == null || !GPS_PROVIDER.equals(mName)) {
- return;
- }
-
- mGnssManagerService.onReportLocation(locations);
- }
-
- @GuardedBy("mLock")
- @Override
- public void onStateChanged(State oldState, State newState) {
- if (oldState.allowed != newState.allowed) {
- if (D) {
- Log.d(TAG, mName + " provider allowed = " + newState.allowed);
- }
-
- onEnabledChangedLocked(UserHandle.USER_ALL);
- }
- }
-
- public void onUserStarted(int userId) {
- if (userId == UserHandle.USER_NULL) {
- return;
- } else if (userId == UserHandle.USER_ALL) {
- for (int runningUserId : mUserInfoHelper.getRunningUserIds()) {
- onUserStarted(runningUserId);
- }
- return;
- }
-
- Preconditions.checkArgument(userId >= 0);
-
- synchronized (mLock) {
- // clear the user's prior enabled state to prevent broadcast of enabled state
- // change. user starts should never result in a broadcast since the state has
- // technically not changed.
- mEnabled.put(userId, null);
- onEnabledChangedLocked(userId);
- }
- }
-
- public void onUserStopped(int userId) {
- if (userId == UserHandle.USER_NULL) {
- return;
- } else if (userId == UserHandle.USER_ALL) {
- mEnabled.clear();
- mLastLocation.clear();
- mLastCoarseLocation.clear();
- return;
- }
-
- Preconditions.checkArgument(userId >= 0);
-
- synchronized (mLock) {
- mEnabled.remove(userId);
- mLastLocation.remove(userId);
- mLastCoarseLocation.remove(userId);
- }
- }
-
- public boolean isEnabled(int userId) {
- if (userId == UserHandle.USER_NULL) {
- // used during initialization - ignore since many lower level operations (checking
- // settings for instance) do not support the null user
- return false;
- }
-
- Preconditions.checkArgument(userId >= 0);
-
- synchronized (mLock) {
- Boolean enabled = mEnabled.get(userId);
- if (enabled == null) {
- // this generally shouldn't occur, but might be possible due to race conditions
- // on when we are notified of new users
- Log.w(TAG, mName + " provider saw user " + userId + " unexpectedly");
- onEnabledChangedLocked(userId);
- enabled = Objects.requireNonNull(mEnabled.get(userId));
- }
-
- return enabled;
- }
- }
-
- @GuardedBy("mLock")
- public void onEnabledChangedLocked(int userId) {
- if (userId == UserHandle.USER_NULL) {
- // used during initialization - ignore since many lower level operations (checking
- // settings for instance) do not support the null user
- return;
- } else if (userId == UserHandle.USER_ALL) {
- for (int runningUserId : mUserInfoHelper.getRunningUserIds()) {
- onEnabledChangedLocked(runningUserId);
- }
- return;
- }
-
- Preconditions.checkArgument(userId >= 0);
-
- // if any property that contributes to "enabled" here changes state, it MUST result
- // in a direct or indrect call to onEnabledChangedLocked. this allows the provider to
- // guarantee that it will always eventually reach the correct state.
- boolean enabled = mProvider.getState().allowed
- && mUserInfoHelper.isCurrentUserId(userId)
- && mSettingsHelper.isLocationEnabled(userId);
-
- Boolean wasEnabled = mEnabled.get(userId);
- if (wasEnabled != null && wasEnabled == enabled) {
- return;
- }
-
- mEnabled.put(userId, enabled);
-
- if (D) {
- Log.d(TAG, "[u" + userId + "] " + mName + " provider enabled = " + enabled);
- }
-
- // clear last locations if we become disabled and if not servicing a bypass request
- if (!enabled && !mProvider.getCurrentRequest().locationSettingsIgnored) {
- mLastLocation.put(userId, null);
- mLastCoarseLocation.put(userId, null);
- }
-
- // do not send change notifications if we just saw this user for the first time
- if (wasEnabled != null) {
- // fused and passive provider never get public updates for legacy reasons
- if (!FUSED_PROVIDER.equals(mName) && !PASSIVE_PROVIDER.equals(mName)) {
- Intent intent = new Intent(PROVIDERS_CHANGED_ACTION)
- .putExtra(EXTRA_PROVIDER_NAME, mName)
- .putExtra(EXTRA_PROVIDER_ENABLED, enabled)
- .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY)
- .addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
- mContext.sendBroadcastAsUser(intent, UserHandle.of(userId));
- }
- }
-
- updateProviderEnabledLocked(this, enabled);
- }
-
- public void dump(FileDescriptor fd, IndentingPrintWriter pw, String[] args) {
- synchronized (mLock) {
- pw.print(mName + " provider");
- if (mProvider.isMock()) {
- pw.print(" [mock]");
- }
- pw.println(":");
-
- pw.increaseIndent();
-
- int[] userIds = mUserInfoHelper.getRunningUserIds();
- for (int userId : userIds) {
- if (userIds.length != 1) {
- pw.println("user " + userId + ":");
- pw.increaseIndent();
- }
- pw.println("last location=" + mLastLocation.get(userId));
- pw.println("last coarse location=" + mLastCoarseLocation.get(userId));
- pw.println("enabled=" + isEnabled(userId));
- if (userIds.length != 1) {
- pw.decreaseIndent();
- }
- }
- }
-
- mProvider.dump(fd, pw, args);
-
- pw.decreaseIndent();
- }
- }
-
- class PassiveLocationProviderManager extends LocationProviderManager {
-
- private PassiveLocationProviderManager() {
- super(PASSIVE_PROVIDER);
- }
-
- @Override
- public void setRealProvider(AbstractLocationProvider provider) {
- Preconditions.checkArgument(provider instanceof PassiveProvider);
- super.setRealProvider(provider);
- }
-
- @Override
- public void setMockProvider(@Nullable MockProvider provider) {
- if (provider != null) {
- throw new IllegalArgumentException("Cannot mock the passive provider");
- }
- }
-
- public void updateLocation(Location location) {
- synchronized (mLock) {
- PassiveProvider passiveProvider = (PassiveProvider) mProvider.getProvider();
- Preconditions.checkState(passiveProvider != null);
-
- long identity = Binder.clearCallingIdentity();
- try {
- passiveProvider.updateLocation(location);
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
- }
- }
- }
-
- /**
- * A wrapper class holding either an ILocationListener or a PendingIntent to receive
- * location updates.
- */
- private final class Receiver extends LocationManagerServiceUtils.LinkedListenerBase implements
- PendingIntent.OnFinished {
- private static final long WAKELOCK_TIMEOUT_MILLIS = 60 * 1000;
-
- private final ILocationListener mListener;
- final PendingIntent mPendingIntent;
- final WorkSource mWorkSource; // WorkSource for battery blame, or null to assign to caller.
- private final boolean mHideFromAppOps; // True if AppOps should not monitor this receiver.
- private final Object mKey;
-
- final HashMap<String, UpdateRecord> mUpdateRecords = new HashMap<>();
-
- // True if app ops has started monitoring this receiver for locations.
- private boolean mOpMonitoring;
- // True if app ops has started monitoring this receiver for high power (gps) locations.
- private boolean mOpHighPowerMonitoring;
- private int mPendingBroadcasts;
- PowerManager.WakeLock mWakeLock;
-
- private Receiver(ILocationListener listener, PendingIntent intent, CallerIdentity identity,
- WorkSource workSource, boolean hideFromAppOps) {
- super(identity);
- mListener = listener;
- mPendingIntent = intent;
- if (listener != null) {
- mKey = listener.asBinder();
- } else {
- mKey = intent;
- }
- if (workSource != null && workSource.isEmpty()) {
- workSource = null;
- }
- mWorkSource = workSource;
- mHideFromAppOps = hideFromAppOps;
-
- updateMonitoring(true);
-
- // construct/configure wakelock
- mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY);
- if (workSource == null) {
- workSource = mCallerIdentity.addToWorkSource(null);
- }
- mWakeLock.setWorkSource(workSource);
-
- // For a non-reference counted wakelock, each acquire will reset the timeout, and we
- // only need to release it once.
- mWakeLock.setReferenceCounted(false);
- }
-
- @Override
- public boolean equals(Object otherObj) {
- return (otherObj instanceof Receiver) && mKey.equals(((Receiver) otherObj).mKey);
- }
-
- @Override
- public int hashCode() {
- return mKey.hashCode();
- }
-
- @Override
- public String toString() {
- StringBuilder s = new StringBuilder();
- s.append("Reciever[");
- s.append(Integer.toHexString(System.identityHashCode(this)));
- if (mListener != null) {
- s.append(" listener");
- } else {
- s.append(" intent");
- }
- for (String p : mUpdateRecords.keySet()) {
- s.append(" ").append(mUpdateRecords.get(p).toString());
- }
- s.append(" monitoring location: ").append(mOpMonitoring);
- s.append("]");
- return s.toString();
- }
-
- /**
- * Update AppOp monitoring for this receiver.
- *
- * @param allow If true receiver is currently active, if false it's been removed.
- */
- public void updateMonitoring(boolean allow) {
- if (mHideFromAppOps) {
- return;
- }
-
- boolean requestingLocation = false;
- boolean requestingHighPowerLocation = false;
- if (allow) {
- // See if receiver has any enabled update records. Also note if any update records
- // are high power (has a high power provider with an interval under a threshold).
- for (UpdateRecord updateRecord : mUpdateRecords.values()) {
- LocationProviderManager manager = getLocationProviderManager(
- updateRecord.mProvider);
- if (manager == null) {
- continue;
- }
- if (!manager.isEnabled(UserHandle.getUserId(mCallerIdentity.getUid()))
- && !isSettingsExempt(updateRecord)) {
- continue;
- }
-
- requestingLocation = true;
- ProviderProperties properties = manager.getProperties();
- if (properties != null
- && properties.mPowerRequirement == Criteria.POWER_HIGH
- && updateRecord.mRequest.getInterval() < HIGH_POWER_INTERVAL_MS) {
- requestingHighPowerLocation = true;
- break;
- }
- }
- }
-
- // First update monitoring of any location request (including high power).
- mOpMonitoring = updateMonitoring(
- requestingLocation,
- mOpMonitoring,
- false);
-
- // Now update monitoring of high power requests only.
- mOpHighPowerMonitoring = updateMonitoring(
- requestingHighPowerLocation,
- mOpHighPowerMonitoring,
- true);
- }
-
- private boolean updateMonitoring(boolean allowMonitoring, boolean currentlyMonitoring,
- boolean highPower) {
- if (!currentlyMonitoring) {
- if (allowMonitoring) {
- if (!highPower) {
- return mAppOpsHelper.startOpNoThrow(OP_MONITOR_LOCATION, mCallerIdentity);
- } else {
- return mAppOpsHelper.startOpNoThrow(OP_MONITOR_HIGH_POWER_LOCATION,
- mCallerIdentity);
- }
- }
- } else {
- int permissionLevel = LocationPermissions.getPermissionLevel(mContext,
- mCallerIdentity.getUid(), mCallerIdentity.getPid());
- if (!allowMonitoring || permissionLevel == PERMISSION_NONE
- || !mAppOpsHelper.checkOpNoThrow(
- LocationPermissions.asAppOp(permissionLevel), mCallerIdentity)) {
- if (!highPower) {
- mAppOpsHelper.finishOp(OP_MONITOR_LOCATION, mCallerIdentity);
- } else {
- mAppOpsHelper.finishOp(OP_MONITOR_HIGH_POWER_LOCATION, mCallerIdentity);
- }
- return false;
- }
- }
-
- return currentlyMonitoring;
- }
-
- public boolean isListener() {
- return mListener != null;
- }
-
- public boolean isPendingIntent() {
- return mPendingIntent != null;
- }
-
- public ILocationListener getListener() {
- if (mListener != null) {
- return mListener;
- }
- throw new IllegalStateException("Request for non-existent listener");
- }
-
- public boolean callLocationChangedLocked(Location location,
- LocationRequest locationRequest) {
- if (mListener != null) {
- try {
- mListener.onLocationChanged(new Location(location), new IRemoteCallback.Stub() {
- @Override
- public void sendResult(Bundle data) {
- synchronized (mLock) {
- decrementPendingBroadcastsLocked();
- }
- }
- });
- // call this after broadcasting so we do not increment
- // if we throw an exception.
- incrementPendingBroadcastsLocked();
- } catch (RemoteException e) {
- return false;
- }
- } else {
- Intent locationChanged = new Intent();
- locationChanged.putExtra(KEY_LOCATION_CHANGED, new Location(location));
- try {
- mPendingIntent.send(mContext, 0, locationChanged, this, mHandler,
- LocationPermissions.asPermission(
- locationRequest.isCoarse() ? PERMISSION_COARSE
- : PERMISSION_FINE),
- PendingIntentUtils.createDontSendToRestrictedAppsBundle(null));
- // call this after broadcasting so we do not increment
- // if we throw an exception.
- incrementPendingBroadcastsLocked();
- } catch (PendingIntent.CanceledException e) {
- return false;
- }
- }
- return true;
- }
-
- private boolean callProviderEnabledLocked(String provider, boolean enabled,
- LocationRequest locationRequest) {
- // First update AppOp monitoring.
- // An app may get/lose location access as providers are enabled/disabled.
- updateMonitoring(true);
-
- if (mListener != null) {
- try {
- mListener.onProviderEnabledChanged(provider, enabled);
- } catch (RemoteException e) {
- return false;
- }
- } else {
- Intent providerIntent = new Intent();
- providerIntent.putExtra(KEY_PROVIDER_ENABLED, enabled);
- try {
- mPendingIntent.send(mContext, 0, providerIntent, null, mHandler,
- LocationPermissions.asPermission(
- locationRequest.isCoarse() ? PERMISSION_COARSE
- : PERMISSION_FINE),
- PendingIntentUtils.createDontSendToRestrictedAppsBundle(null));
- } catch (PendingIntent.CanceledException e) {
- return false;
- }
- }
- return true;
- }
-
- @Override
- public void binderDied() {
- synchronized (mLock) {
- removeUpdatesLocked(this);
- clearPendingBroadcastsLocked();
- }
- }
-
- @Override
- public void onSendFinished(PendingIntent pendingIntent, Intent intent,
- int resultCode, String resultData, Bundle resultExtras) {
- synchronized (mLock) {
- decrementPendingBroadcastsLocked();
- }
- }
-
- // this must be called while synchronized by caller in a synchronized block
- // containing the sending of the broadcaset
- private void incrementPendingBroadcastsLocked() {
- mPendingBroadcasts++;
- // so wakelock calls will succeed
- long identity = Binder.clearCallingIdentity();
- try {
- mWakeLock.acquire(WAKELOCK_TIMEOUT_MILLIS);
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
- }
+ private void onLocationModeChanged(int userId) {
+ boolean enabled = mInjector.getSettingsHelper().isLocationEnabled(userId);
+ LocationManager.invalidateLocalLocationEnabledCaches();
- private void decrementPendingBroadcastsLocked() {
- if (--mPendingBroadcasts == 0) {
- // so wakelock calls will succeed
- long identity = Binder.clearCallingIdentity();
- try {
- if (mWakeLock.isHeld()) {
- mWakeLock.release();
- }
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
- }
+ if (D) {
+ Log.d(TAG, "[u" + userId + "] location enabled = " + enabled);
}
- public void clearPendingBroadcastsLocked() {
- if (mPendingBroadcasts > 0) {
- mPendingBroadcasts = 0;
- // so wakelock calls will succeed
- long identity = Binder.clearCallingIdentity();
- try {
- if (mWakeLock.isHeld()) {
- mWakeLock.release();
- }
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
- }
- }
+ Intent intent = new Intent(LocationManager.MODE_CHANGED_ACTION)
+ .putExtra(LocationManager.EXTRA_LOCATION_ENABLED, enabled)
+ .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY)
+ .addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+ mContext.sendBroadcastAsUser(intent, UserHandle.of(userId));
}
@Override
@@ -1459,17 +478,6 @@ public class LocationManagerService extends ILocationManager.Stub {
}
}
- @Nullable
- LocationProviderManager getLocationProviderManager(String providerName) {
- for (LocationProviderManager manager : mProviderManagers) {
- if (providerName.equals(manager.getName())) {
- return manager;
- }
- }
-
- return null;
- }
-
@Override
public List<String> getAllProviders() {
ArrayList<String> providers = new ArrayList<>(mProviderManagers.size());
@@ -1532,397 +540,16 @@ public class LocationManagerService extends ILocationManager.Stub {
return null;
}
- @GuardedBy("mLock")
- private void updateProviderEnabledLocked(LocationProviderManager manager, boolean enabled) {
- ArrayList<Receiver> deadReceivers = null;
- ArrayList<UpdateRecord> records = mRecordsByProvider.get(manager.getName());
- if (records != null) {
- for (UpdateRecord record : records) {
- if (!mUserInfoHelper.isCurrentUserId(
- UserHandle.getUserId(record.mReceiver.mCallerIdentity.getUid()))) {
- continue;
- }
-
- // requests that ignore location settings will never provide notifications
- if (isSettingsExempt(record)) {
- continue;
- }
-
- // Sends a notification message to the receiver
- if (!record.mReceiver.callProviderEnabledLocked(manager.getName(), enabled,
- record.mRequest)) {
- if (deadReceivers == null) {
- deadReceivers = new ArrayList<>();
- }
- deadReceivers.add(record.mReceiver);
- }
- }
- }
-
- if (deadReceivers != null) {
- for (int i = deadReceivers.size() - 1; i >= 0; i--) {
- removeUpdatesLocked(deadReceivers.get(i));
- }
- }
-
- applyRequirementsLocked(manager);
- }
-
- @GuardedBy("mLock")
- private void applyRequirementsLocked(String providerName) {
- LocationProviderManager manager = getLocationProviderManager(providerName);
- if (manager != null) {
- applyRequirementsLocked(manager);
- }
- }
-
- @GuardedBy("mLock")
- private void applyRequirementsLocked(LocationProviderManager manager) {
- ArrayList<UpdateRecord> records = mRecordsByProvider.get(manager.getName());
- ProviderRequest.Builder providerRequest = new ProviderRequest.Builder();
-
- // if provider is not active, it should not respond to requests
-
- if (mProviderManagers.contains(manager) && records != null && !records.isEmpty()) {
- long backgroundThrottleInterval = mSettingsHelper.getBackgroundThrottleIntervalMs();
-
- ArrayList<LocationRequest> requests = new ArrayList<>(records.size());
-
- final boolean isForegroundOnlyMode =
- mBatterySaverMode == PowerManager.LOCATION_MODE_FOREGROUND_ONLY;
- final boolean shouldThrottleRequests =
- mBatterySaverMode
- == PowerManager.LOCATION_MODE_THROTTLE_REQUESTS_WHEN_SCREEN_OFF
- && !mPowerManager.isInteractive();
- // initialize the low power mode to true and set to false if any of the records requires
- providerRequest.setLowPowerMode(true);
- for (UpdateRecord record : records) {
- CallerIdentity identity = record.mReceiver.mCallerIdentity;
- if (!mUserInfoHelper.isCurrentUserId(identity.getUserId())) {
- continue;
- }
-
- if (!mAppOpsHelper.checkOpNoThrow(LocationPermissions.asAppOp(
- record.mRequest.isCoarse() ? PERMISSION_COARSE : PERMISSION_FINE),
- identity)) {
- continue;
- }
- final boolean isBatterySaverDisablingLocation = shouldThrottleRequests
- || (isForegroundOnlyMode && !record.mIsForegroundUid);
- if (!manager.isEnabled(identity.getUserId()) || isBatterySaverDisablingLocation) {
- if (isSettingsExempt(record)) {
- providerRequest.setLocationSettingsIgnored(true);
- providerRequest.setLowPowerMode(false);
- } else {
- continue;
- }
- }
-
- LocationRequest locationRequest = record.mRealRequest;
- long interval = locationRequest.getInterval();
-
-
- // if we're forcing location, don't apply any throttling
- if (!providerRequest.isLocationSettingsIgnored() && !isThrottlingExempt(
- record.mReceiver.mCallerIdentity)) {
- if (!record.mIsForegroundUid) {
- interval = Math.max(interval, backgroundThrottleInterval);
- }
- if (interval != locationRequest.getInterval()) {
- locationRequest = new LocationRequest(locationRequest);
- locationRequest.setInterval(interval);
- }
- }
-
- record.mRequest = locationRequest;
- requests.add(locationRequest);
- if (!locationRequest.isLowPowerMode()) {
- providerRequest.setLowPowerMode(false);
- }
- if (interval < providerRequest.getInterval()) {
- providerRequest.setInterval(interval);
- }
- }
-
- providerRequest.setLocationRequests(requests);
-
- if (providerRequest.getInterval() < Long.MAX_VALUE) {
- // calculate who to blame for power
- // This is somewhat arbitrary. We pick a threshold interval
- // that is slightly higher that the minimum interval, and
- // spread the blame across all applications with a request
- // under that threshold.
- // TODO: overflow
- long thresholdInterval = (providerRequest.getInterval() + 1000) * 3 / 2;
- for (UpdateRecord record : records) {
- if (mUserInfoHelper.isCurrentUserId(
- UserHandle.getUserId(record.mReceiver.mCallerIdentity.getUid()))) {
- LocationRequest locationRequest = record.mRequest;
-
- // Don't assign battery blame for update records whose
- // client has no permission to receive location data.
- if (!providerRequest.getLocationRequests().contains(locationRequest)) {
- continue;
- }
-
- if (locationRequest.getInterval() <= thresholdInterval) {
- if (record.mReceiver.mWorkSource != null
- && isValidWorkSource(record.mReceiver.mWorkSource)) {
- providerRequest.getWorkSource().add(record.mReceiver.mWorkSource);
- } else {
- // Assign blame to caller if there's no WorkSource associated with
- // the request or if it's invalid.
- providerRequest.getWorkSource().add(
- record.mReceiver.mCallerIdentity.getUid(),
- record.mReceiver.mCallerIdentity.getPackageName());
- }
- }
- }
- }
- }
- }
-
- manager.setRequest(providerRequest.build());
- }
-
- /**
- * Whether a given {@code WorkSource} associated with a Location request is valid.
- */
- private static boolean isValidWorkSource(WorkSource workSource) {
- if (workSource.size() > 0) {
- // If the WorkSource has one or more non-chained UIDs, make sure they're accompanied
- // by tags.
- return workSource.getPackageName(0) != null;
- } else {
- // For now, make sure callers have supplied an attribution tag for use with
- // AppOpsManager. This might be relaxed in the future.
- final List<WorkChain> workChains = workSource.getWorkChains();
- return workChains != null && !workChains.isEmpty()
- && workChains.get(0).getAttributionTag() != null;
- }
- }
-
@Override
public String[] getBackgroundThrottlingWhitelist() {
- return mSettingsHelper.getBackgroundThrottlePackageWhitelist().toArray(new String[0]);
+ return mInjector.getSettingsHelper().getBackgroundThrottlePackageWhitelist().toArray(
+ new String[0]);
}
@Override
public String[] getIgnoreSettingsWhitelist() {
- return mSettingsHelper.getIgnoreSettingsPackageWhitelist().toArray(new String[0]);
- }
-
- private boolean isThrottlingExempt(CallerIdentity callerIdentity) {
- if (callerIdentity.getUid() == Process.SYSTEM_UID) {
- return true;
- }
-
- if (mSettingsHelper.getBackgroundThrottlePackageWhitelist().contains(
- callerIdentity.getPackageName())) {
- return true;
- }
-
- return mLocalService.isProvider(null, callerIdentity);
-
- }
-
- private boolean isSettingsExempt(UpdateRecord record) {
- if (!record.mRealRequest.isLocationSettingsIgnored()) {
- return false;
- }
-
- if (mSettingsHelper.getIgnoreSettingsPackageWhitelist().contains(
- record.mReceiver.mCallerIdentity.getPackageName())) {
- return true;
- }
-
- return mLocalService.isProvider(null, record.mReceiver.mCallerIdentity);
- }
-
- private class UpdateRecord {
- final String mProvider;
- private final LocationRequest mRealRequest; // original request from client
- LocationRequest mRequest; // possibly throttled version of the request
- private final Receiver mReceiver;
- private boolean mIsForegroundUid;
- private Location mLastFixBroadcast;
- private Throwable mStackTrace; // for debugging only
- private long mExpirationRealtimeMs;
-
- /**
- * Note: must be constructed with lock held.
- */
- private UpdateRecord(String provider, LocationRequest request, Receiver receiver) {
- if (Build.IS_DEBUGGABLE) {
- Preconditions.checkState(Thread.holdsLock(mLock));
- }
- mExpirationRealtimeMs = request.getExpirationRealtimeMs(SystemClock.elapsedRealtime());
- mProvider = provider;
- mRealRequest = request;
- mRequest = request;
- mReceiver = receiver;
- mIsForegroundUid = mAppForegroundHelper.isAppForeground(
- mReceiver.mCallerIdentity.getUid());
-
- if (D && receiver.mCallerIdentity.getPid() == Process.myPid()) {
- mStackTrace = new Throwable();
- }
-
- ArrayList<UpdateRecord> records = mRecordsByProvider.computeIfAbsent(provider,
- k -> new ArrayList<>());
- if (!records.contains(this)) {
- records.add(this);
- }
-
- // Update statistics for historical location requests by package/provider
- mRequestStatistics.startRequesting(
- mReceiver.mCallerIdentity.getPackageName(),
- mReceiver.mCallerIdentity.getAttributionTag(),
- provider, request.getInterval(), mIsForegroundUid);
- }
-
- /**
- * Method to be called when record changes foreground/background
- */
- private void updateForeground(boolean isForeground) {
- mIsForegroundUid = isForeground;
- mRequestStatistics.updateForeground(
- mReceiver.mCallerIdentity.getPackageName(),
- mReceiver.mCallerIdentity.getAttributionTag(),
- mProvider, isForeground);
- }
-
- /**
- * Method to be called when a record will no longer be used.
- */
- private void disposeLocked(boolean removeReceiver) {
- if (Build.IS_DEBUGGABLE) {
- Preconditions.checkState(Thread.holdsLock(mLock));
- }
-
- CallerIdentity identity = mReceiver.mCallerIdentity;
- mRequestStatistics.stopRequesting(identity.getPackageName(),
- identity.getAttributionTag(),
- mProvider);
-
- mLocationUsageLogger.logLocationApiUsage(
- LocationStatsEnums.USAGE_ENDED,
- LocationStatsEnums.API_REQUEST_LOCATION_UPDATES,
- identity.getPackageName(),
- mRealRequest,
- mReceiver.isListener(),
- mReceiver.isPendingIntent(),
- /* geofence= */ null,
- mAppForegroundHelper.isAppForeground(mReceiver.mCallerIdentity.getUid()));
-
- // remove from mRecordsByProvider
- ArrayList<UpdateRecord> globalRecords = mRecordsByProvider.get(this.mProvider);
- if (globalRecords != null) {
- globalRecords.remove(this);
- }
-
- if (!removeReceiver) return; // the caller will handle the rest
-
- // remove from Receiver#mUpdateRecords
- HashMap<String, UpdateRecord> receiverRecords = mReceiver.mUpdateRecords;
- receiverRecords.remove(this.mProvider);
-
- // and also remove the Receiver if it has no more update records
- if (receiverRecords.size() == 0) {
- removeUpdatesLocked(mReceiver);
- }
- }
-
- @Override
- public String toString() {
- StringBuilder b = new StringBuilder("UpdateRecord[");
- b.append(mProvider).append(" ");
- b.append(mReceiver.mCallerIdentity).append(" ");
- if (!mIsForegroundUid) {
- b.append("(background) ");
- }
- b.append(mRealRequest).append(" ").append(mReceiver.mWorkSource);
-
- if (mStackTrace != null) {
- ByteArrayOutputStream tmp = new ByteArrayOutputStream();
- mStackTrace.printStackTrace(new PrintStream(tmp));
- b.append("\n\n").append(tmp.toString()).append("\n");
- }
-
- b.append("]");
- return b.toString();
- }
- }
-
- @GuardedBy("mLock")
- private Receiver getReceiverLocked(ILocationListener listener, CallerIdentity identity,
- WorkSource workSource, boolean hideFromAppOps) {
- IBinder binder = listener.asBinder();
- Receiver receiver = mReceivers.get(binder);
- if (receiver == null && identity != null) {
- receiver = new Receiver(listener, null, identity, workSource,
- hideFromAppOps);
- if (!receiver.linkToListenerDeathNotificationLocked(
- receiver.getListener().asBinder())) {
- return null;
- }
- mReceivers.put(binder, receiver);
- }
- return receiver;
- }
-
- @GuardedBy("mLock")
- private Receiver getReceiverLocked(PendingIntent intent, CallerIdentity identity,
- WorkSource workSource, boolean hideFromAppOps) {
- Receiver receiver = mReceivers.get(intent);
- if (receiver == null && identity != null) {
- receiver = new Receiver(null, intent, identity, workSource,
- hideFromAppOps);
- mReceivers.put(intent, receiver);
- }
- return receiver;
- }
-
- /**
- * Creates a LocationRequest based upon the supplied LocationRequest that to meets resolution
- * and consistency requirements.
- *
- * @param request the LocationRequest from which to create a sanitized version
- * @return a version of request that meets the given resolution and consistency requirements
- * @hide
- */
- private LocationRequest createSanitizedRequest(LocationRequest request,
- boolean callerHasLocationHardwarePermission, int permissionLevel) {
- LocationRequest sanitizedRequest = new LocationRequest(request);
- if (!callerHasLocationHardwarePermission) {
- // allow setting low power mode only for callers with location hardware permission
- sanitizedRequest.setLowPowerMode(false);
- }
- if (permissionLevel < PERMISSION_FINE) {
- sanitizedRequest.setCoarse(true);
- switch (sanitizedRequest.getQuality()) {
- case LocationRequest.ACCURACY_FINE:
- sanitizedRequest.setQuality(LocationRequest.ACCURACY_BLOCK);
- break;
- case LocationRequest.POWER_HIGH:
- sanitizedRequest.setQuality(LocationRequest.POWER_LOW);
- break;
- }
- // throttle
- if (sanitizedRequest.getInterval() < FASTEST_COARSE_INTERVAL_MS) {
- sanitizedRequest.setInterval(FASTEST_COARSE_INTERVAL_MS);
- }
- if (sanitizedRequest.getFastestInterval() < FASTEST_COARSE_INTERVAL_MS) {
- sanitizedRequest.setFastestInterval(FASTEST_COARSE_INTERVAL_MS);
- }
- } else {
- sanitizedRequest.setCoarse(false);
- }
- // make getFastestInterval() the minimum of interval and fastest interval
- if (sanitizedRequest.getFastestInterval() > sanitizedRequest.getInterval()) {
- sanitizedRequest.setFastestInterval(request.getInterval());
- }
- return sanitizedRequest;
+ return mInjector.getSettingsHelper().getIgnoreSettingsPackageWhitelist().toArray(
+ new String[0]);
}
@Override
@@ -1930,45 +557,24 @@ public class LocationManagerService extends ILocationManager.Stub {
String packageName, String attributionTag, String listenerId) {
CallerIdentity identity = CallerIdentity.fromBinder(mContext, packageName, attributionTag,
listenerId);
- int permissionLevel = LocationPermissions.getCallingOrSelfPermissionLevel(mContext);
- LocationPermissions.enforceLocationPermission(Binder.getCallingUid(), permissionLevel,
+ int permissionLevel = LocationPermissions.getPermissionLevel(mContext, identity.getUid(),
+ identity.getPid());
+ LocationPermissions.enforceLocationPermission(identity.getUid(), permissionLevel,
PERMISSION_COARSE);
- WorkSource workSource = request.getWorkSource();
- if (workSource != null && !workSource.isEmpty()) {
- mContext.enforceCallingOrSelfPermission(
- permission.UPDATE_DEVICE_STATS, null);
+ // clients in the system process should have an attribution tag set
+ if (identity.getPid() == Process.myPid() && attributionTag == null) {
+ Log.w(TAG, "system location request with no attribution tag",
+ new IllegalArgumentException());
}
- boolean hideFromAppOps = request.getHideFromAppOps();
- if (hideFromAppOps) {
- mContext.enforceCallingOrSelfPermission(
- permission.UPDATE_APP_OPS_STATS, null);
- }
- if (request.isLocationSettingsIgnored()) {
- mContext.enforceCallingOrSelfPermission(
- permission.WRITE_SECURE_SETTINGS, null);
- }
- boolean callerHasLocationHardwarePermission =
- mContext.checkCallingPermission(permission.LOCATION_HARDWARE)
- == PERMISSION_GRANTED;
- LocationRequest sanitizedRequest = createSanitizedRequest(request,
- callerHasLocationHardwarePermission,
- permissionLevel);
- mLocationUsageLogger.logLocationApiUsage(
- LocationStatsEnums.USAGE_STARTED,
- LocationStatsEnums.API_REQUEST_LOCATION_UPDATES,
- packageName, request, true, false,
- /* geofence= */ null,
- mAppForegroundHelper.isAppForeground(identity.getUid()));
+ request = validateAndSanitizeLocationRequest(request, permissionLevel);
- synchronized (mLock) {
- Receiver receiver = getReceiverLocked(Objects.requireNonNull(listener), identity,
- workSource, hideFromAppOps);
- if (receiver != null) {
- requestLocationUpdatesLocked(sanitizedRequest, receiver);
- }
- }
+ LocationProviderManager manager = getLocationProviderManager(request.getProvider());
+ Preconditions.checkArgument(manager != null,
+ "provider \"" + request.getProvider() + "\" does not exist");
+
+ manager.registerLocationRequest(request, identity, permissionLevel, listener);
}
@Override
@@ -1976,248 +582,154 @@ public class LocationManagerService extends ILocationManager.Stub {
String packageName, String attributionTag) {
CallerIdentity identity = CallerIdentity.fromBinder(mContext, packageName, attributionTag,
AppOpsManager.toReceiverId(pendingIntent));
- int permissionLevel = LocationPermissions.getCallingOrSelfPermissionLevel(mContext);
- LocationPermissions.enforceLocationPermission(Binder.getCallingUid(), permissionLevel,
+ int permissionLevel = LocationPermissions.getPermissionLevel(mContext, identity.getUid(),
+ identity.getPid());
+ LocationPermissions.enforceLocationPermission(identity.getUid(), permissionLevel,
PERMISSION_COARSE);
+ // clients in the system process must have an attribution tag set
+ Preconditions.checkArgument(identity.getPid() != Process.myPid() || attributionTag != null);
+
+ request = validateAndSanitizeLocationRequest(request, permissionLevel);
+
+ LocationProviderManager manager = getLocationProviderManager(request.getProvider());
+ Preconditions.checkArgument(manager != null,
+ "provider \"" + request.getProvider() + "\" does not exist");
+
+ manager.registerLocationRequest(request, identity, permissionLevel, pendingIntent);
+ }
+
+ private LocationRequest validateAndSanitizeLocationRequest(LocationRequest request,
+ @PermissionLevel int permissionLevel) {
+ Objects.requireNonNull(request.getProvider());
+
WorkSource workSource = request.getWorkSource();
if (workSource != null && !workSource.isEmpty()) {
mContext.enforceCallingOrSelfPermission(
- permission.UPDATE_DEVICE_STATS, null);
+ permission.UPDATE_DEVICE_STATS,
+ "setting a work source requires " + permission.UPDATE_DEVICE_STATS);
}
- boolean hideFromAppOps = request.getHideFromAppOps();
- if (hideFromAppOps) {
+ if (request.getHideFromAppOps()) {
mContext.enforceCallingOrSelfPermission(
- permission.UPDATE_APP_OPS_STATS, null);
+ permission.UPDATE_APP_OPS_STATS,
+ "hiding from app ops requires " + permission.UPDATE_APP_OPS_STATS);
}
if (request.isLocationSettingsIgnored()) {
mContext.enforceCallingOrSelfPermission(
- permission.WRITE_SECURE_SETTINGS, null);
+ permission.WRITE_SECURE_SETTINGS,
+ "ignoring location settings requires " + permission.WRITE_SECURE_SETTINGS);
}
- boolean callerHasLocationHardwarePermission =
- mContext.checkCallingPermission(permission.LOCATION_HARDWARE)
- == PERMISSION_GRANTED;
- LocationRequest sanitizedRequest = createSanitizedRequest(request,
- callerHasLocationHardwarePermission,
- permissionLevel);
-
- mLocationUsageLogger.logLocationApiUsage(
- LocationStatsEnums.USAGE_STARTED,
- LocationStatsEnums.API_REQUEST_LOCATION_UPDATES,
- packageName, request, true, false,
- /* geofence= */ null,
- mAppForegroundHelper.isAppForeground(identity.getUid()));
- synchronized (mLock) {
- Receiver receiver = getReceiverLocked(Objects.requireNonNull(pendingIntent), identity,
- workSource, hideFromAppOps);
- if (receiver != null) {
- requestLocationUpdatesLocked(sanitizedRequest, receiver);
- }
+ LocationRequest sanitized = new LocationRequest(request);
+ if (mContext.checkCallingPermission(permission.LOCATION_HARDWARE) != PERMISSION_GRANTED) {
+ sanitized.setLowPowerMode(false);
}
- }
-
- @GuardedBy("mLock")
- private void requestLocationUpdatesLocked(LocationRequest request, Receiver receiver) {
- String provider = request.getProvider();
+ if (permissionLevel < PERMISSION_FINE) {
+ switch (sanitized.getQuality()) {
+ case LocationRequest.ACCURACY_FINE:
+ sanitized.setQuality(LocationRequest.ACCURACY_BLOCK);
+ break;
+ case LocationRequest.POWER_HIGH:
+ sanitized.setQuality(LocationRequest.POWER_LOW);
+ break;
+ }
- LocationProviderManager manager = getLocationProviderManager(provider);
- if (manager == null) {
- throw new IllegalArgumentException("provider doesn't exist: " + provider);
+ if (sanitized.getInterval() < FASTEST_COARSE_INTERVAL_MS) {
+ sanitized.setInterval(FASTEST_COARSE_INTERVAL_MS);
+ }
+ if (sanitized.getFastestInterval() < FASTEST_COARSE_INTERVAL_MS) {
+ sanitized.setFastestInterval(FASTEST_COARSE_INTERVAL_MS);
+ }
}
-
- UpdateRecord record = new UpdateRecord(provider, request, receiver);
-
- UpdateRecord oldRecord = receiver.mUpdateRecords.put(provider, record);
- if (oldRecord != null) {
- oldRecord.disposeLocked(false);
+ if (sanitized.getFastestInterval() > sanitized.getInterval()) {
+ sanitized.setFastestInterval(request.getInterval());
}
-
- long identity = Binder.clearCallingIdentity();
- try {
- int userId = UserHandle.getUserId(receiver.mCallerIdentity.getUid());
- if (!manager.isEnabled(userId) && !isSettingsExempt(record)) {
- // Notify the listener that updates are currently disabled - but only if the request
- // does not ignore location settings
- receiver.callProviderEnabledLocked(provider, false, request);
+ if (sanitized.getWorkSource() != null) {
+ if (sanitized.getWorkSource().isEmpty()) {
+ sanitized.setWorkSource(null);
+ } else if (sanitized.getWorkSource().getPackageName(0) == null) {
+ Log.w(TAG, "received (and ignoring) illegal worksource with no package name");
+ sanitized.setWorkSource(null);
+ } else {
+ List<WorkChain> workChains = sanitized.getWorkSource().getWorkChains();
+ if (workChains != null && !workChains.isEmpty() && workChains.get(
+ 0).getAttributionTag() == null) {
+ Log.w(TAG,
+ "received (and ignoring) illegal worksource with no attribution tag");
+ sanitized.setWorkSource(null);
+ }
}
-
- applyRequirementsLocked(provider);
-
- // Update the monitoring here just in case multiple location requests were added to the
- // same receiver (this request may be high power and the initial might not have been).
- receiver.updateMonitoring(true);
- } finally {
- Binder.restoreCallingIdentity(identity);
}
+
+ return sanitized;
}
@Override
public void unregisterLocationListener(ILocationListener listener) {
- synchronized (mLock) {
- Receiver receiver = getReceiverLocked(Objects.requireNonNull(listener), null, null,
- false);
- if (receiver != null) {
- removeUpdatesLocked(receiver);
- }
+ for (LocationProviderManager manager : mProviderManagers) {
+ manager.unregisterLocationRequest(listener);
}
}
@Override
public void unregisterLocationPendingIntent(PendingIntent pendingIntent) {
- synchronized (mLock) {
- Receiver receiver = getReceiverLocked(Objects.requireNonNull(pendingIntent), null, null,
- false);
- if (receiver != null) {
- removeUpdatesLocked(receiver);
- }
- }
- }
-
- @GuardedBy("mLock")
- private void removeUpdatesLocked(Receiver receiver) {
- if (D) Log.i(TAG, "remove " + Integer.toHexString(System.identityHashCode(receiver)));
-
- if (mReceivers.remove(receiver.mKey) != null && receiver.isListener()) {
- receiver.unlinkFromListenerDeathNotificationLocked(
- receiver.getListener().asBinder());
- receiver.clearPendingBroadcastsLocked();
- }
-
- receiver.updateMonitoring(false);
-
- // Record which providers were associated with this listener
- HashSet<String> providers = new HashSet<>();
- HashMap<String, UpdateRecord> oldRecords = receiver.mUpdateRecords;
- if (oldRecords != null) {
- // Call dispose() on the obsolete update records.
- for (UpdateRecord record : oldRecords.values()) {
- // Update statistics for historical location requests by package/provider
- record.disposeLocked(false);
- }
- // Accumulate providers
- providers.addAll(oldRecords.keySet());
- }
-
- // update provider
- for (String provider : providers) {
- applyRequirementsLocked(provider);
+ for (LocationProviderManager manager : mProviderManagers) {
+ manager.unregisterLocationRequest(pendingIntent);
}
}
@Override
public Location getLastLocation(LocationRequest request, String packageName,
String attributionTag) {
- // unsafe is ok because app ops will verify the package name
- CallerIdentity identity = CallerIdentity.fromBinderUnsafe(packageName, attributionTag);
- int permissionLevel = LocationPermissions.getCallingOrSelfPermissionLevel(mContext);
- LocationPermissions.enforceLocationPermission(Binder.getCallingUid(), permissionLevel,
+ CallerIdentity identity = CallerIdentity.fromBinder(mContext, packageName, attributionTag);
+ int permissionLevel = LocationPermissions.getPermissionLevel(mContext, identity.getUid(),
+ identity.getPid());
+ LocationPermissions.enforceLocationPermission(identity.getUid(), permissionLevel,
PERMISSION_COARSE);
- if (mSettingsHelper.isLocationPackageBlacklisted(identity.getUserId(),
- identity.getPackageName())) {
- return null;
- }
- if (!mUserInfoHelper.isCurrentUserId(identity.getUserId())) {
- return null;
- }
+ // clients in the system process must have an attribution tag set
+ Preconditions.checkArgument(identity.getPid() != Process.myPid() || attributionTag != null);
- synchronized (mLock) {
- LocationProviderManager manager = getLocationProviderManager(request.getProvider());
- if (manager == null) {
- return null;
- }
- if (!manager.isEnabled(identity.getUserId()) && !request.isLocationSettingsIgnored()) {
- return null;
- }
+ request = validateAndSanitizeLocationRequest(request, permissionLevel);
- // appops check should always be right before delivery
- if (!mAppOpsHelper.noteOpNoThrow(LocationPermissions.asAppOp(permissionLevel),
- identity)) {
- return null;
- }
+ LocationProviderManager manager = getLocationProviderManager(request.getProvider());
+ if (manager == null) {
+ return null;
+ }
- Location location = manager.getLastLocation(identity.getUserId(), permissionLevel);
+ Location location = manager.getLastLocation(request, identity, permissionLevel);
- // make a defensive copy - the client could be in the same process as us
- return location != null ? new Location(location) : null;
+ // lastly - note app ops
+ if (!mInjector.getAppOpsHelper().noteOpNoThrow(LocationPermissions.asAppOp(permissionLevel),
+ identity)) {
+ return null;
}
+
+ return location;
}
@Override
public void getCurrentLocation(LocationRequest request,
- ICancellationSignal remoteCancellationSignal, ILocationCallback callback,
+ ICancellationSignal cancellationTransport, ILocationCallback consumer,
String packageName, String attributionTag, String listenerId) {
- // unsafe is ok because app ops will verify the package name
- CallerIdentity identity = CallerIdentity.fromBinderUnsafe(packageName, attributionTag,
+ CallerIdentity identity = CallerIdentity.fromBinder(mContext, packageName, attributionTag,
listenerId);
- int permissionLevel = LocationPermissions.getCallingOrSelfPermissionLevel(mContext);
- LocationPermissions.enforceLocationPermission(Binder.getCallingUid(), permissionLevel,
+ int permissionLevel = LocationPermissions.getPermissionLevel(mContext, identity.getUid(),
+ identity.getPid());
+ LocationPermissions.enforceLocationPermission(identity.getUid(), permissionLevel,
PERMISSION_COARSE);
- request = createSanitizedRequest(request, false, permissionLevel);
- request.setNumUpdates(1);
- if (request.getExpireIn() > GET_CURRENT_LOCATION_MAX_TIMEOUT_MS) {
- request.setExpireIn(GET_CURRENT_LOCATION_MAX_TIMEOUT_MS);
- }
-
- GetCurrentLocationTransport transport = new GetCurrentLocationTransport(callback);
-
- if (mSettingsHelper.isLocationPackageBlacklisted(identity.getUserId(),
- identity.getPackageName())) {
- transport.deliverResult(null);
- return;
- }
- if (!mUserInfoHelper.isCurrentUserId(identity.getUserId())) {
- transport.deliverResult(null);
- return;
- }
-
- Location lastLocation;
- synchronized (mLock) {
- LocationProviderManager manager = getLocationProviderManager(request.getProvider());
- if (manager == null) {
- transport.deliverResult(null);
- return;
- }
- if (!manager.isEnabled(identity.getUserId()) && !request.isLocationSettingsIgnored()) {
- transport.deliverResult(null);
- return;
- }
-
- lastLocation = manager.getLastLocation(identity.getUserId(), permissionLevel);
- }
-
- if (lastLocation != null) {
- long locationAgeMs = NANOSECONDS.toMillis(
- SystemClock.elapsedRealtimeNanos() - lastLocation.getElapsedRealtimeNanos());
+ // clients in the system process must have an attribution tag set
+ Preconditions.checkState(identity.getPid() != Process.myPid() || attributionTag != null);
- if (locationAgeMs < MAX_CURRENT_LOCATION_AGE_MS) {
- // appops check should always be right before delivery
- if (mAppOpsHelper.noteOpNoThrow(LocationPermissions.asAppOp(permissionLevel),
- identity)) {
- transport.deliverResult(lastLocation);
- } else {
- transport.deliverResult(null);
- }
- return;
- }
+ request = validateAndSanitizeLocationRequest(request, permissionLevel);
- if (!mAppForegroundHelper.isAppForeground(Binder.getCallingUid())) {
- if (locationAgeMs < mSettingsHelper.getBackgroundThrottleIntervalMs()) {
- // not allowed to request new locations, so we can't return anything
- transport.deliverResult(null);
- return;
- }
- }
- }
+ LocationProviderManager manager = getLocationProviderManager(request.getProvider());
+ Preconditions.checkArgument(manager != null,
+ "provider \"" + request.getProvider() + "\" does not exist");
- registerLocationListener(request, transport, packageName, attributionTag, listenerId);
- CancellationSignal cancellationSignal = CancellationSignal.fromTransport(
- remoteCancellationSignal);
- if (cancellationSignal != null) {
- cancellationSignal.setOnCancelListener(() -> unregisterLocationListener(transport));
- }
+ manager.getCurrentLocation(request, identity, permissionLevel, cancellationTransport,
+ consumer);
}
@Override
@@ -2228,8 +740,13 @@ public class LocationManagerService extends ILocationManager.Stub {
return null;
}
- Location location = gpsManager.getLastLocation(UserHandle.getCallingUserId(),
- PERMISSION_FINE);
+ // create a location request that works in almost all circumstances
+ LocationRequest request = LocationRequest.createFromDeprecatedProvider(GPS_PROVIDER, 0,
+ 0, true);
+
+ // use our own identity rather than the caller
+ CallerIdentity identity = CallerIdentity.fromContext(mContext);
+ Location location = gpsManager.getLastLocation(request, identity, PERMISSION_FINE);
if (location == null) {
return null;
}
@@ -2248,11 +765,9 @@ public class LocationManagerService extends ILocationManager.Stub {
Preconditions.checkArgument(location.isComplete());
int userId = UserHandle.getCallingUserId();
- synchronized (mLock) {
- LocationProviderManager manager = getLocationProviderManager(location.getProvider());
- if (manager != null && manager.isEnabled(userId)) {
- manager.injectLastLocation(Objects.requireNonNull(location), userId);
- }
+ LocationProviderManager manager = getLocationProviderManager(location.getProvider());
+ if (manager != null && manager.isEnabled(userId)) {
+ manager.injectLastLocation(Objects.requireNonNull(location), userId);
}
}
@@ -2357,12 +872,11 @@ public class LocationManagerService extends ILocationManager.Stub {
Objects.requireNonNull(command), extras);
}
- mLocationUsageLogger.logLocationApiUsage(
+ mInjector.getLocationUsageLogger().logLocationApiUsage(
LocationStatsEnums.USAGE_STARTED,
LocationStatsEnums.API_SEND_EXTRA_COMMAND,
provider);
-
- mLocationUsageLogger.logLocationApiUsage(
+ mInjector.getLocationUsageLogger().logLocationApiUsage(
LocationStatsEnums.USAGE_ENDED,
LocationStatsEnums.API_SEND_EXTRA_COMMAND,
provider);
@@ -2385,7 +899,7 @@ public class LocationManagerService extends ILocationManager.Stub {
if (provider != null && !provider.equals(manager.getName())) {
continue;
}
- CallerIdentity identity = manager.getProviderIdentity();
+ CallerIdentity identity = manager.getIdentity();
if (identity == null) {
continue;
}
@@ -2406,7 +920,7 @@ public class LocationManagerService extends ILocationManager.Stub {
return Collections.emptyList();
}
- CallerIdentity identity = manager.getProviderIdentity();
+ CallerIdentity identity = manager.getIdentity();
if (identity == null) {
return Collections.emptyList();
}
@@ -2454,164 +968,26 @@ public class LocationManagerService extends ILocationManager.Stub {
mContext.enforceCallingOrSelfPermission(permission.WRITE_SECURE_SETTINGS, null);
- invalidateLocalLocationEnabledCaches();
- mSettingsHelper.setLocationEnabled(enabled, userId);
+ LocationManager.invalidateLocalLocationEnabledCaches();
+ mInjector.getSettingsHelper().setLocationEnabled(enabled, userId);
}
@Override
public boolean isLocationEnabledForUser(int userId) {
userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
userId, false, false, "isLocationEnabledForUser", null);
- return mSettingsHelper.isLocationEnabled(userId);
+ return mInjector.getSettingsHelper().isLocationEnabled(userId);
}
@Override
public boolean isProviderEnabledForUser(String provider, int userId) {
- // Fused provider is accessed indirectly via criteria rather than the provider-based APIs,
+ // fused provider is accessed indirectly via criteria rather than the provider-based APIs,
// so we discourage its use
if (FUSED_PROVIDER.equals(provider)) return false;
return mLocalService.isProviderEnabledForUser(provider, userId);
}
- @GuardedBy("mLock")
- private static boolean shouldBroadcastSafeLocked(
- Location loc, Location lastLoc, UpdateRecord record, long now) {
- // Always broadcast the first update
- if (lastLoc == null) {
- return true;
- }
-
- // Check whether sufficient time has passed
- long minTime = record.mRealRequest.getFastestInterval();
- long deltaMs = NANOSECONDS.toMillis(
- loc.getElapsedRealtimeNanos() - lastLoc.getElapsedRealtimeNanos());
- if (deltaMs < minTime - MAX_PROVIDER_SCHEDULING_JITTER_MS) {
- return false;
- }
-
- // Check whether sufficient distance has been traveled
- double minDistance = record.mRealRequest.getSmallestDisplacement();
- if (minDistance > 0.0) {
- if (loc.distanceTo(lastLoc) <= minDistance) {
- return false;
- }
- }
-
- // Check whether sufficient number of udpates is left
- if (record.mRealRequest.getNumUpdates() <= 0) {
- return false;
- }
-
- // Check whether the expiry date has passed
- return record.mExpirationRealtimeMs >= now;
- }
-
- @GuardedBy("mLock")
- private void handleLocationChangedLocked(LocationProviderManager manager, Location fineLocation,
- Location coarseLocation) {
- if (!mProviderManagers.contains(manager)) {
- Log.w(TAG, "received location from unknown provider: " + manager.getName());
- return;
- }
-
- // notify passive provider
- if (manager != mPassiveManager) {
- mPassiveManager.updateLocation(fineLocation);
- }
-
- long now = SystemClock.elapsedRealtime();
-
- ArrayList<UpdateRecord> records = mRecordsByProvider.get(manager.getName());
- if (records == null || records.size() == 0) return;
-
- ArrayList<Receiver> deadReceivers = null;
- ArrayList<UpdateRecord> deadUpdateRecords = null;
-
- // Broadcast location to all listeners
- for (UpdateRecord r : records) {
- Receiver receiver = r.mReceiver;
- CallerIdentity identity = receiver.mCallerIdentity;
- boolean receiverDead = false;
-
-
- if (!manager.isEnabled(identity.getUserId()) && !isSettingsExempt(r)) {
- continue;
- }
-
- if (!mUserInfoHelper.isCurrentUserId(identity.getUserId())
- && !mLocalService.isProvider(null, identity)) {
- continue;
- }
-
- if (mSettingsHelper.isLocationPackageBlacklisted(identity.getUserId(),
- identity.getPackageName())) {
- continue;
- }
-
- int permissionLevel = r.mRequest.isCoarse() ? PERMISSION_COARSE : PERMISSION_FINE;
-
- Location location;
- switch (permissionLevel) {
- case PERMISSION_COARSE:
- location = coarseLocation;
- break;
- case PERMISSION_FINE:
- location = fineLocation;
- break;
- default:
- throw new AssertionError();
- }
-
- if (shouldBroadcastSafeLocked(location, r.mLastFixBroadcast, r, now)) {
- r.mLastFixBroadcast = location;
-
- // appops check should always be right before delivery
- if (!mAppOpsHelper.noteOpNoThrow(LocationPermissions.asAppOp(permissionLevel),
- receiver.mCallerIdentity)) {
- continue;
- }
-
- if (!receiver.callLocationChangedLocked(location, r.mRequest)) {
- receiverDead = true;
- }
- r.mRealRequest.decrementNumUpdates();
- }
-
- // track expired records
- if (r.mRealRequest.getNumUpdates() <= 0 || r.mExpirationRealtimeMs < now) {
- if (deadUpdateRecords == null) {
- deadUpdateRecords = new ArrayList<>();
- }
- deadUpdateRecords.add(r);
- }
- // track dead receivers
- if (receiverDead) {
- if (deadReceivers == null) {
- deadReceivers = new ArrayList<>();
- }
- if (!deadReceivers.contains(receiver)) {
- deadReceivers.add(receiver);
- }
- }
- }
-
- // remove dead records and receivers outside the loop
- if (deadReceivers != null) {
- for (Receiver receiver : deadReceivers) {
- removeUpdatesLocked(receiver);
- }
- }
- if (deadUpdateRecords != null) {
- for (UpdateRecord r : deadUpdateRecords) {
- r.disposeLocked(true);
- }
- applyRequirementsLocked(manager);
- }
- }
-
- // Geocoder
-
@Override
public boolean geocoderIsPresent() {
return mGeocodeProvider != null;
@@ -2637,7 +1013,6 @@ public class LocationManagerService extends ILocationManager.Stub {
double lowerLeftLatitude, double lowerLeftLongitude,
double upperRightLatitude, double upperRightLongitude, int maxResults,
GeocoderParams params, IGeocodeListener listener) {
-
if (mGeocodeProvider != null) {
mGeocodeProvider.getFromLocationName(locationName, lowerLeftLatitude,
lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
@@ -2651,35 +1026,24 @@ public class LocationManagerService extends ILocationManager.Stub {
}
}
- // Mock Providers
-
@Override
public void addTestProvider(String provider, ProviderProperties properties,
String packageName, String attributionTag) {
// unsafe is ok because app ops will verify the package name
- CallerIdentity identity = CallerIdentity.fromBinderUnsafe(packageName,
- attributionTag);
- if (!mAppOpsHelper.noteOp(OP_MOCK_LOCATION, identity)) {
+ CallerIdentity identity = CallerIdentity.fromBinderUnsafe(packageName, attributionTag);
+ if (!mInjector.getAppOpsHelper().noteOp(AppOpsManager.OP_MOCK_LOCATION, identity)) {
return;
}
- synchronized (mLock) {
- LocationProviderManager manager = getLocationProviderManager(provider);
- if (manager == null) {
- manager = new LocationProviderManager(provider);
- mProviderManagers.add(manager);
- }
-
- manager.setMockProvider(new MockProvider(properties, identity));
- }
+ getOrAddLocationProviderManager(provider).setMockProvider(
+ new MockProvider(properties, identity));
}
@Override
public void removeTestProvider(String provider, String packageName, String attributionTag) {
// unsafe is ok because app ops will verify the package name
- CallerIdentity identity = CallerIdentity.fromBinderUnsafe(packageName,
- attributionTag);
- if (!mAppOpsHelper.noteOp(OP_MOCK_LOCATION, identity)) {
+ CallerIdentity identity = CallerIdentity.fromBinderUnsafe(packageName, attributionTag);
+ if (!mInjector.getAppOpsHelper().noteOp(AppOpsManager.OP_MOCK_LOCATION, identity)) {
return;
}
@@ -2691,7 +1055,7 @@ public class LocationManagerService extends ILocationManager.Stub {
manager.setMockProvider(null);
if (!manager.hasProvider()) {
- mProviderManagers.remove(manager);
+ removeLocationProviderManager(manager);
}
}
}
@@ -2702,7 +1066,7 @@ public class LocationManagerService extends ILocationManager.Stub {
// unsafe is ok because app ops will verify the package name
CallerIdentity identity = CallerIdentity.fromBinderUnsafe(packageName,
attributionTag);
- if (!mAppOpsHelper.noteOp(OP_MOCK_LOCATION, identity)) {
+ if (!mInjector.getAppOpsHelper().noteOp(AppOpsManager.OP_MOCK_LOCATION, identity)) {
return;
}
@@ -2723,7 +1087,7 @@ public class LocationManagerService extends ILocationManager.Stub {
// unsafe is ok because app ops will verify the package name
CallerIdentity identity = CallerIdentity.fromBinderUnsafe(packageName,
attributionTag);
- if (!mAppOpsHelper.noteOp(OP_MOCK_LOCATION, identity)) {
+ if (!mInjector.getAppOpsHelper().noteOp(AppOpsManager.OP_MOCK_LOCATION, identity)) {
return;
}
@@ -2777,57 +1141,32 @@ public class LocationManagerService extends ILocationManager.Stub {
ipw.println("User Info:");
ipw.increaseIndent();
- mUserInfoHelper.dump(fd, ipw, args);
+ mInjector.getUserInfoHelper().dump(fd, ipw, args);
ipw.decreaseIndent();
ipw.println("Location Settings:");
ipw.increaseIndent();
- mSettingsHelper.dump(fd, ipw, args);
+ mInjector.getSettingsHelper().dump(fd, ipw, args);
ipw.decreaseIndent();
- synchronized (mLock) {
- ipw.println("Battery Saver Location Mode: "
- + locationPowerSaveModeToString(mBatterySaverMode));
-
- if (dumpFilter == null) {
- ipw.println("Location Listeners:");
- ipw.increaseIndent();
- for (Receiver receiver : mReceivers.values()) {
- ipw.println(receiver);
- }
- ipw.decreaseIndent();
-
- ipw.println("Active Records by Provider:");
- ipw.increaseIndent();
- for (Map.Entry<String, ArrayList<UpdateRecord>> entry :
- mRecordsByProvider.entrySet()) {
- ipw.println(entry.getKey() + ":");
- ipw.increaseIndent();
- for (UpdateRecord record : entry.getValue()) {
- ipw.println(record);
- }
- ipw.decreaseIndent();
- }
- ipw.decreaseIndent();
-
- ipw.println("Historical Records by Provider:");
- ipw.increaseIndent();
- TreeMap<PackageProviderKey, PackageStatistics> sorted = new TreeMap<>(
- mRequestStatistics.statistics);
- for (Map.Entry<PackageProviderKey, PackageStatistics> entry
- : sorted.entrySet()) {
- ipw.println(entry.getKey() + ": " + entry.getValue());
- }
- ipw.decreaseIndent();
+ ipw.println("Historical Records by Provider:");
+ ipw.increaseIndent();
+ TreeMap<PackageProviderKey, PackageStatistics> sorted = new TreeMap<>(
+ mInjector.getLocationRequestStatistics().statistics);
+ for (Map.Entry<PackageProviderKey, PackageStatistics> entry
+ : sorted.entrySet()) {
+ ipw.println(entry.getKey() + ": " + entry.getValue());
+ }
+ ipw.decreaseIndent();
- mRequestStatistics.history.dump(ipw);
+ mInjector.getLocationRequestStatistics().history.dump(ipw);
- if (mExtraLocationControllerPackage != null) {
- ipw.println(
- "Location Controller Extra Package: " + mExtraLocationControllerPackage
- + (mExtraLocationControllerPackageEnabled ? " [enabled]"
- : "[disabled]"));
- }
+ synchronized (mLock) {
+ if (mExtraLocationControllerPackage != null) {
+ ipw.println(
+ "Location Controller Extra Package: " + mExtraLocationControllerPackage
+ + (mExtraLocationControllerPackageEnabled ? " [enabled]"
+ : "[disabled]"));
}
}
@@ -2857,47 +1196,6 @@ public class LocationManagerService extends ILocationManager.Stub {
}
}
- private class GetCurrentLocationTransport extends ILocationListener.Stub {
-
- private final Executor mExecutor;
- private final ILocationCallback mCallback;
-
- GetCurrentLocationTransport(ILocationCallback callback) {
- mExecutor = FgThread.getExecutor();
- mCallback = callback;
- }
-
- @Override
- public void onLocationChanged(Location location, IRemoteCallback onCompleteCallback) {
- mExecutor.execute(() -> {
- deliverResult(location);
- try {
- onCompleteCallback.sendResult(null);
- } catch (RemoteException e) {
- e.rethrowFromSystemServer();
- }
- });
- unregisterLocationListener(this);
- }
-
- @Override
- public void onProviderEnabledChanged(String provider, boolean enabled)
- throws RemoteException {
- if (!enabled) {
- deliverResult(null);
- unregisterLocationListener(this);
- }
- }
-
- public void deliverResult(@Nullable Location location) {
- try {
- mCallback.onLocation(location);
- } catch (RemoteException e) {
- // do nothing
- }
- }
- }
-
private class LocalService extends LocationManagerInternal {
LocalService() {}
@@ -2916,17 +1214,28 @@ public class LocationManagerService extends ILocationManager.Stub {
}
@Override
+ public void addProviderEnabledListener(String provider, ProviderEnabledListener listener) {
+ LocationProviderManager manager = Objects.requireNonNull(
+ getLocationProviderManager(provider));
+ manager.addEnabledListener(listener);
+ }
+
+ @Override
+ public void removeProviderEnabledListener(String provider,
+ ProviderEnabledListener listener) {
+ LocationProviderManager manager = Objects.requireNonNull(
+ getLocationProviderManager(provider));
+ manager.removeEnabledListener(listener);
+ }
+
+ @Override
public boolean isProvider(String provider, CallerIdentity identity) {
- for (LocationProviderManager manager : mProviderManagers) {
- if (provider != null && !provider.equals(manager.getName())) {
- continue;
- }
- if (identity.equals(manager.getProviderIdentity())) {
- return true;
- }
+ LocationProviderManager manager = getLocationProviderManager(provider);
+ if (manager == null) {
+ return false;
+ } else {
+ return identity.equals(manager.getIdentity());
}
-
- return false;
}
@Override
@@ -2935,6 +1244,13 @@ public class LocationManagerService extends ILocationManager.Stub {
mGnssManagerService.sendNiResponse(notifId, userResponse);
}
}
+
+ @Override
+ public void reportGnssBatchLocations(List<Location> locations) {
+ if (mGnssManagerService != null) {
+ mGnssManagerService.onReportLocation(locations);
+ }
+ }
}
private static class SystemInjector implements Injector {
diff --git a/services/core/java/com/android/server/location/LocationManagerServiceUtils.java b/services/core/java/com/android/server/location/LocationManagerServiceUtils.java
deleted file mode 100644
index b9d86c84508f..000000000000
--- a/services/core/java/com/android/server/location/LocationManagerServiceUtils.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES 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.location;
-
-import android.annotation.NonNull;
-import android.location.util.identity.CallerIdentity;
-import android.os.IBinder;
-import android.os.RemoteException;
-
-import java.util.NoSuchElementException;
-
-/**
- * Shared utilities for LocationManagerService and GnssManager.
- */
-public class LocationManagerServiceUtils {
-
- /**
- * Skeleton class of listener that can be linked to a binder.
- */
- public abstract static class LinkedListenerBase implements IBinder.DeathRecipient {
- protected final CallerIdentity mCallerIdentity;
-
- LinkedListenerBase(@NonNull CallerIdentity callerIdentity) {
- mCallerIdentity = callerIdentity;
- }
-
- @Override
- public String toString() {
- return mCallerIdentity.toString();
- }
-
- public CallerIdentity getCallerIdentity() {
- return mCallerIdentity;
- }
-
- /**
- * Link listener (i.e. callback) to a binder, so that it will be called upon binder's death.
- */
- public boolean linkToListenerDeathNotificationLocked(IBinder binder) {
- try {
- binder.linkToDeath(this, 0 /* flags */);
- return true;
- } catch (RemoteException e) {
- return false;
- }
- }
-
- /**
- * Unlink death listener (i.e. callback) from binder.
- */
- public void unlinkFromListenerDeathNotificationLocked(IBinder binder) {
- try {
- binder.unlinkToDeath(this, 0 /* flags */);
- } catch (NoSuchElementException e) {
- // ignore
- }
- }
- }
-}
diff --git a/services/core/java/com/android/server/location/LocationProviderManager.java b/services/core/java/com/android/server/location/LocationProviderManager.java
new file mode 100644
index 000000000000..d4f8c7e855b9
--- /dev/null
+++ b/services/core/java/com/android/server/location/LocationProviderManager.java
@@ -0,0 +1,1951 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.location;
+
+import static android.app.AlarmManager.ELAPSED_REALTIME_WAKEUP;
+import static android.app.AlarmManager.WINDOW_EXACT;
+import static android.location.LocationManager.FUSED_PROVIDER;
+import static android.location.LocationManager.GPS_PROVIDER;
+import static android.location.LocationManager.KEY_LOCATION_CHANGED;
+import static android.location.LocationManager.KEY_PROVIDER_ENABLED;
+import static android.location.LocationManager.PASSIVE_PROVIDER;
+import static android.os.IPowerManager.LOCATION_MODE_NO_CHANGE;
+import static android.os.PowerManager.LOCATION_MODE_ALL_DISABLED_WHEN_SCREEN_OFF;
+import static android.os.PowerManager.LOCATION_MODE_FOREGROUND_ONLY;
+import static android.os.PowerManager.LOCATION_MODE_GPS_DISABLED_WHEN_SCREEN_OFF;
+import static android.os.PowerManager.LOCATION_MODE_THROTTLE_REQUESTS_WHEN_SCREEN_OFF;
+
+import static com.android.server.location.LocationManagerService.D;
+import static com.android.server.location.LocationManagerService.TAG;
+import static com.android.server.location.LocationPermissions.PERMISSION_COARSE;
+import static com.android.server.location.LocationPermissions.PERMISSION_FINE;
+import static com.android.server.location.LocationPermissions.PERMISSION_NONE;
+
+import static java.util.concurrent.TimeUnit.NANOSECONDS;
+
+import android.annotation.Nullable;
+import android.app.AlarmManager;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
+import android.location.Criteria;
+import android.location.ILocationCallback;
+import android.location.ILocationListener;
+import android.location.Location;
+import android.location.LocationManager;
+import android.location.LocationManagerInternal;
+import android.location.LocationManagerInternal.ProviderEnabledListener;
+import android.location.LocationRequest;
+import android.location.util.identity.CallerIdentity;
+import android.os.Binder;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.CancellationSignal;
+import android.os.IBinder;
+import android.os.ICancellationSignal;
+import android.os.IRemoteCallback;
+import android.os.PowerManager;
+import android.os.PowerManager.LocationPowerSaveMode;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.os.UserHandle;
+import android.os.WorkSource;
+import android.stats.location.LocationStatsEnums;
+import android.text.TextUtils;
+import android.util.ArraySet;
+import android.util.EventLog;
+import android.util.IndentingPrintWriter;
+import android.util.Log;
+import android.util.SparseArray;
+import android.util.SparseBooleanArray;
+import android.util.TimeUtils;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.location.ProviderProperties;
+import com.android.internal.location.ProviderRequest;
+import com.android.internal.util.Preconditions;
+import com.android.server.FgThread;
+import com.android.server.LocalServices;
+import com.android.server.PendingIntentUtils;
+import com.android.server.location.LocationPermissions.PermissionLevel;
+import com.android.server.location.listeners.ListenerMultiplexer;
+import com.android.server.location.listeners.RemovableListenerRegistration;
+import com.android.server.location.util.AppForegroundHelper;
+import com.android.server.location.util.AppForegroundHelper.AppForegroundListener;
+import com.android.server.location.util.AppOpsHelper;
+import com.android.server.location.util.Injector;
+import com.android.server.location.util.LocationAttributionHelper;
+import com.android.server.location.util.LocationPermissionsHelper;
+import com.android.server.location.util.LocationPermissionsHelper.LocationPermissionsListener;
+import com.android.server.location.util.LocationPowerSaveModeHelper;
+import com.android.server.location.util.LocationPowerSaveModeHelper.LocationPowerSaveModeChangedListener;
+import com.android.server.location.util.LocationUsageLogger;
+import com.android.server.location.util.ScreenInteractiveHelper;
+import com.android.server.location.util.ScreenInteractiveHelper.ScreenInteractiveChangedListener;
+import com.android.server.location.util.SettingsHelper;
+import com.android.server.location.util.SettingsHelper.GlobalSettingChangedListener;
+import com.android.server.location.util.SettingsHelper.UserSettingChangedListener;
+import com.android.server.location.util.UserInfoHelper;
+import com.android.server.location.util.UserInfoHelper.UserListener;
+
+import java.io.FileDescriptor;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Objects;
+
+class LocationProviderManager extends
+ ListenerMultiplexer<Object, LocationRequest, LocationProviderManager.LocationTransport,
+ LocationProviderManager.Registration, ProviderRequest> implements
+ AbstractLocationProvider.Listener {
+
+ // fastest interval at which clients may receive coarse locations
+ public static final long FASTEST_COARSE_INTERVAL_MS = 10 * 60 * 1000;
+
+ private static final String WAKELOCK_TAG = "*location*";
+ private static final long WAKELOCK_TIMEOUT_MS = 30 * 1000;
+
+ // maximum interval to be considered "high power" request
+ private static final long MAX_HIGH_POWER_INTERVAL_MS = 5 * 60 * 1000;
+
+ // maximum age of a location before it is no longer considered "current"
+ private static final long MAX_CURRENT_LOCATION_AGE_MS = 10 * 1000;
+
+ // max timeout allowed for getting the current location
+ private static final long GET_CURRENT_LOCATION_MAX_TIMEOUT_MS = 30 * 1000;
+
+ // maximum jitter allowed for fastest interval evaluation
+ private static final int MAX_FASTEST_INTERVAL_JITTER_MS = 100;
+
+ protected interface LocationTransport {
+
+ void deliverOnLocationChanged(Location location, @Nullable Runnable onCompleteCallback)
+ throws Exception;
+ }
+
+ protected interface ProviderTransport {
+
+ void deliverOnProviderEnabledChanged(String provider, boolean enabled) throws Exception;
+ }
+
+ protected static final class LocationListenerTransport implements LocationTransport,
+ ProviderTransport {
+
+ private final ILocationListener mListener;
+
+ protected LocationListenerTransport(ILocationListener listener) {
+ mListener = Objects.requireNonNull(listener);
+ }
+
+ @Override
+ public void deliverOnLocationChanged(Location location,
+ @Nullable Runnable onCompleteCallback)
+ throws RemoteException {
+ mListener.onLocationChanged(location,
+ onCompleteCallback == null ? null : new IRemoteCallback.Stub() {
+ @Override
+ public void sendResult(Bundle data) {
+ onCompleteCallback.run();
+ }
+ });
+ }
+
+ @Override
+ public void deliverOnProviderEnabledChanged(String provider, boolean enabled)
+ throws RemoteException {
+ mListener.onProviderEnabledChanged(provider, enabled);
+ }
+ }
+
+ protected static final class LocationPendingIntentTransport implements LocationTransport,
+ ProviderTransport {
+
+ private final Context mContext;
+ private final PendingIntent mPendingIntent;
+
+ public LocationPendingIntentTransport(Context context, PendingIntent pendingIntent) {
+ mContext = context;
+ mPendingIntent = pendingIntent;
+ }
+
+ @Override
+ public void deliverOnLocationChanged(Location location,
+ @Nullable Runnable onCompleteCallback)
+ throws PendingIntent.CanceledException {
+ mPendingIntent.send(mContext, 0, new Intent().putExtra(KEY_LOCATION_CHANGED, location),
+ onCompleteCallback != null ? (pI, i, rC, rD, rE) -> onCompleteCallback.run()
+ : null, null, null,
+ PendingIntentUtils.createDontSendToRestrictedAppsBundle(null));
+ }
+
+ @Override
+ public void deliverOnProviderEnabledChanged(String provider, boolean enabled)
+ throws PendingIntent.CanceledException {
+ mPendingIntent.send(mContext, 0, new Intent().putExtra(KEY_PROVIDER_ENABLED, enabled),
+ null, null, null,
+ PendingIntentUtils.createDontSendToRestrictedAppsBundle(null));
+ }
+ }
+
+ protected static final class GetCurrentLocationTransport implements LocationTransport {
+
+ private final ILocationCallback mCallback;
+
+ protected GetCurrentLocationTransport(ILocationCallback callback) {
+ mCallback = Objects.requireNonNull(callback);
+ }
+
+ @Override
+ public void deliverOnLocationChanged(Location location,
+ @Nullable Runnable onCompleteCallback)
+ throws RemoteException {
+ // ILocationCallback doesn't currently support completion callbacks
+ Preconditions.checkState(onCompleteCallback == null);
+ mCallback.onLocation(location);
+ }
+ }
+
+ protected abstract class Registration extends
+ RemovableListenerRegistration<LocationRequest, LocationTransport> {
+
+ @PermissionLevel protected final int mPermissionLevel;
+ private final WorkSource mWorkSource;
+
+ // we cache these values because checking/calculating on the fly is more expensive
+ private boolean mPermitted;
+ private boolean mForeground;
+ @Nullable private LocationRequest mProviderLocationRequest;
+ private boolean mIsUsingHighPower;
+
+ protected Registration(LocationRequest request, CallerIdentity identity,
+ LocationTransport transport, @PermissionLevel int permissionLevel) {
+ super(TAG, Objects.requireNonNull(request), identity, transport);
+
+ Preconditions.checkArgument(permissionLevel > PERMISSION_NONE);
+ mPermissionLevel = permissionLevel;
+
+ if (request.getWorkSource() != null && !request.getWorkSource().isEmpty()) {
+ mWorkSource = request.getWorkSource();
+ } else {
+ mWorkSource = identity.addToWorkSource(null);
+ }
+ }
+
+ @GuardedBy("mLock")
+ @Override
+ protected final void onRemovableListenerRegister() {
+ if (Build.IS_DEBUGGABLE) {
+ Preconditions.checkState(Thread.holdsLock(mLock));
+ }
+
+ if (D) {
+ Log.d(TAG, mName + " provider added registration from " + getIdentity() + " -> "
+ + getRequest());
+ }
+
+ // initialization order is important as there are ordering dependencies
+ mPermitted = mLocationPermissionsHelper.hasLocationPermissions(mPermissionLevel,
+ getIdentity());
+ mForeground = mAppForegroundHelper.isAppForeground(getIdentity().getUid());
+ mProviderLocationRequest = calculateProviderLocationRequest();
+ mIsUsingHighPower = isUsingHighPower();
+
+ onProviderListenerRegister();
+ }
+
+ @GuardedBy("mLock")
+ @Override
+ protected final void onRemovableListenerUnregister() {
+ if (Build.IS_DEBUGGABLE) {
+ Preconditions.checkState(Thread.holdsLock(mLock));
+ }
+
+ onProviderListenerUnregister();
+
+ if (D) {
+ Log.d(TAG, mName + " provider removed registration from " + getIdentity());
+ }
+ }
+
+ /**
+ * Subclasses may override this instead of {@link #onRemovableListenerRegister()}.
+ */
+ @GuardedBy("mLock")
+ protected void onProviderListenerRegister() {}
+
+ /**
+ * Subclasses may override this instead of {@link #onRemovableListenerUnregister()}.
+ */
+ @GuardedBy("mLock")
+ protected void onProviderListenerUnregister() {}
+
+ @Override
+ protected final ListenerOperation<LocationTransport> onActive() {
+ if (!getRequest().getHideFromAppOps()) {
+ mLocationAttributionHelper.reportLocationStart(getIdentity(), getName(), getKey());
+ }
+ onHighPowerUsageChanged();
+ return null;
+ }
+
+ @Override
+ protected final void onInactive() {
+ onHighPowerUsageChanged();
+ if (!getRequest().getHideFromAppOps()) {
+ mLocationAttributionHelper.reportLocationStop(getIdentity(), getName(), getKey());
+ }
+ }
+
+ @Override
+ public final LocationRequest getRequest() {
+ return Objects.requireNonNull(mProviderLocationRequest);
+ }
+
+ public final boolean isForeground() {
+ return mForeground;
+ }
+
+ public final boolean isPermitted() {
+ return mPermitted;
+ }
+
+ @Override
+ protected final LocationProviderManager getOwner() {
+ return LocationProviderManager.this;
+ }
+
+ protected final WorkSource getWorkSource() {
+ return mWorkSource;
+ }
+
+ @GuardedBy("mLock")
+ private void onHighPowerUsageChanged() {
+ boolean isUsingHighPower = isUsingHighPower();
+ if (isUsingHighPower != mIsUsingHighPower) {
+ mIsUsingHighPower = isUsingHighPower;
+
+ if (!getRequest().getHideFromAppOps()) {
+ if (mIsUsingHighPower) {
+ mLocationAttributionHelper.reportHighPowerLocationStart(
+ getIdentity(), getName(), getKey());
+ } else {
+ mLocationAttributionHelper.reportHighPowerLocationStop(
+ getIdentity(), getName(), getKey());
+ }
+ }
+ }
+ }
+
+ @GuardedBy("mLock")
+ private boolean isUsingHighPower() {
+ if (Build.IS_DEBUGGABLE) {
+ Preconditions.checkState(Thread.holdsLock(mLock));
+ }
+
+ return isActive()
+ && getRequest().getInterval() < MAX_HIGH_POWER_INTERVAL_MS
+ && getProperties().mPowerRequirement == Criteria.POWER_HIGH;
+ }
+
+ @GuardedBy("mLock")
+ final boolean onLocationPermissionsChanged(String packageName) {
+ if (getIdentity().getPackageName().equals(packageName)) {
+ return onLocationPermissionsChanged();
+ }
+
+ return false;
+ }
+
+ @GuardedBy("mLock")
+ final boolean onLocationPermissionsChanged(int uid) {
+ if (getIdentity().getUid() == uid) {
+ return onLocationPermissionsChanged();
+ }
+
+ return false;
+ }
+
+ @GuardedBy("mLock")
+ private boolean onLocationPermissionsChanged() {
+ if (Build.IS_DEBUGGABLE) {
+ Preconditions.checkState(Thread.holdsLock(mLock));
+ }
+
+ boolean permitted = mLocationPermissionsHelper.hasLocationPermissions(mPermissionLevel,
+ getIdentity());
+ if (permitted != mPermitted) {
+ if (D) {
+ Log.v(TAG, mName + " provider package " + getIdentity().getPackageName()
+ + " permitted = " + permitted);
+ }
+
+ mPermitted = permitted;
+ return true;
+ }
+
+ return false;
+ }
+
+ @GuardedBy("mLock")
+ final boolean onForegroundChanged(int uid, boolean foreground) {
+ if (Build.IS_DEBUGGABLE) {
+ Preconditions.checkState(Thread.holdsLock(mLock));
+ }
+
+ if (getIdentity().getUid() == uid && foreground != mForeground) {
+ if (D) {
+ Log.v(TAG, mName + " provider uid " + uid + " foreground = " + foreground);
+ }
+
+ mForeground = foreground;
+
+ // note that onProviderLocationRequestChanged() is always called
+ return onProviderLocationRequestChanged()
+ || mLocationPowerSaveModeHelper.getLocationPowerSaveMode()
+ == LOCATION_MODE_FOREGROUND_ONLY;
+ }
+
+ return false;
+ }
+
+ @GuardedBy("mLock")
+ final boolean onProviderLocationRequestChanged() {
+ if (Build.IS_DEBUGGABLE) {
+ Preconditions.checkState(Thread.holdsLock(mLock));
+ }
+
+ LocationRequest newRequest = calculateProviderLocationRequest();
+ if (!mProviderLocationRequest.equals(newRequest)) {
+ LocationRequest oldRequest = mProviderLocationRequest;
+ mProviderLocationRequest = newRequest;
+ onHighPowerUsageChanged();
+ updateService();
+
+ // if location settings ignored has changed then the active state may have changed
+ return oldRequest.isLocationSettingsIgnored()
+ != newRequest.isLocationSettingsIgnored();
+ }
+
+ return false;
+ }
+
+ private LocationRequest calculateProviderLocationRequest() {
+ LocationRequest newRequest = new LocationRequest(super.getRequest());
+
+ if (newRequest.isLocationSettingsIgnored()) {
+ // if we are not currently allowed use location settings ignored, disable it
+ if (!mSettingsHelper.getIgnoreSettingsPackageWhitelist().contains(
+ getIdentity().getPackageName()) && !mLocationManagerInternal.isProvider(
+ null, getIdentity())) {
+ newRequest.setLocationSettingsIgnored(false);
+ }
+ }
+
+ if (!newRequest.isLocationSettingsIgnored() && !isThrottlingExempt()) {
+ // throttle in the background
+ if (!mForeground) {
+ newRequest.setInterval(Math.max(newRequest.getInterval(),
+ mSettingsHelper.getBackgroundThrottleIntervalMs()));
+ }
+ }
+
+ return newRequest;
+ }
+
+ private boolean isThrottlingExempt() {
+ if (mSettingsHelper.getBackgroundThrottlePackageWhitelist().contains(
+ getIdentity().getPackageName())) {
+ return true;
+ }
+
+ return mLocationManagerInternal.isProvider(null, getIdentity());
+ }
+
+ @Nullable
+ abstract ListenerOperation<LocationTransport> acceptLocationChange(Location fineLocation);
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ builder.append(getIdentity());
+
+ ArraySet<String> flags = new ArraySet<>(2);
+ if (!isForeground()) {
+ flags.add("bg");
+ }
+ if (!isPermitted()) {
+ flags.add("na");
+ }
+ if (!flags.isEmpty()) {
+ builder.append(" ").append(flags);
+ }
+
+ if (mPermissionLevel == PERMISSION_COARSE) {
+ builder.append(" (COARSE)");
+ }
+
+ builder.append(" ").append(getRequest());
+ return builder.toString();
+ }
+ }
+
+ protected abstract class LocationRegistration extends Registration implements
+ AlarmManager.OnAlarmListener, ProviderEnabledListener {
+
+ private final PowerManager.WakeLock mWakeLock;
+
+ private volatile ProviderTransport mProviderTransport;
+ @Nullable private Location mLastLocation = null;
+ private int mNumLocationsDelivered = 0;
+ private long mExpirationRealtimeMs = Long.MAX_VALUE;
+
+ protected <TTransport extends LocationTransport & ProviderTransport> LocationRegistration(
+ LocationRequest request, CallerIdentity identity, TTransport transport,
+ @PermissionLevel int permissionLevel) {
+ super(request, identity, transport, permissionLevel);
+ mProviderTransport = transport;
+ mWakeLock = Objects.requireNonNull(mContext.getSystemService(PowerManager.class))
+ .newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_TAG);
+ mWakeLock.setReferenceCounted(true);
+ mWakeLock.setWorkSource(getWorkSource());
+ }
+
+ @Override
+ protected void onListenerUnregister() {
+ mProviderTransport = null;
+ }
+
+ @GuardedBy("mLock")
+ @Override
+ protected final void onProviderListenerRegister() {
+ mExpirationRealtimeMs = getRequest().getExpirationRealtimeMs(
+ SystemClock.elapsedRealtime());
+
+ // add alarm for expiration
+ if (mExpirationRealtimeMs < SystemClock.elapsedRealtime()) {
+ remove();
+ } else if (mExpirationRealtimeMs < Long.MAX_VALUE) {
+ AlarmManager alarmManager = Objects.requireNonNull(
+ mContext.getSystemService(AlarmManager.class));
+ alarmManager.set(ELAPSED_REALTIME_WAKEUP, mExpirationRealtimeMs, WINDOW_EXACT,
+ 0, this, FgThread.getHandler(), getWorkSource());
+ }
+
+ // start listening for provider enabled/disabled events
+ addEnabledListener(this);
+
+ onLocationListenerRegister();
+
+ // if the provider is currently disabled, let the client know immediately
+ int userId = getIdentity().getUserId();
+ if (!isEnabled(userId)) {
+ onProviderEnabledChanged(mName, userId, false);
+ }
+ }
+
+ @GuardedBy("mLock")
+ @Override
+ protected final void onProviderListenerUnregister() {
+ // stop listening for provider enabled/disabled events
+ removeEnabledListener(this);
+
+ // remove alarm for expiration
+ if (mExpirationRealtimeMs < Long.MAX_VALUE) {
+ AlarmManager alarmManager = Objects.requireNonNull(
+ mContext.getSystemService(AlarmManager.class));
+ alarmManager.cancel(this);
+ }
+
+ onLocationListenerUnregister();
+ }
+
+ /**
+ * Subclasses may override this instead of {@link #onRemovableListenerRegister()}.
+ */
+ @GuardedBy("mLock")
+ protected void onLocationListenerRegister() {}
+
+ /**
+ * Subclasses may override this instead of {@link #onRemovableListenerUnregister()}.
+ */
+ @GuardedBy("mLock")
+ protected void onLocationListenerUnregister() {}
+
+ @Override
+ public void onAlarm() {
+ if (D) {
+ Log.d(TAG, "removing " + getIdentity() + " from " + mName
+ + " provider due to expiration at " + TimeUtils.formatRealtime(
+ mExpirationRealtimeMs));
+ }
+
+ synchronized (mLock) {
+ remove();
+ }
+ }
+
+ @GuardedBy("mLock")
+ @Nullable
+ @Override
+ ListenerOperation<LocationTransport> acceptLocationChange(Location fineLocation) {
+ if (Build.IS_DEBUGGABLE) {
+ Preconditions.checkState(Thread.holdsLock(mLock));
+ }
+
+ // check expiration time - alarm is not guaranteed to go off at the right time,
+ // especially for short intervals
+ if (SystemClock.elapsedRealtime() >= mExpirationRealtimeMs) {
+ remove();
+ return null;
+ }
+
+ Location location;
+ switch (mPermissionLevel) {
+ case PERMISSION_FINE:
+ location = fineLocation;
+ break;
+ case PERMISSION_COARSE:
+ location = mLocationFudger.createCoarse(fineLocation);
+ break;
+ default:
+ // shouldn't be possible to have a client added without location permissions
+ throw new AssertionError();
+ }
+
+ if (mLastLocation != null) {
+ // check fastest interval
+ long deltaMs = NANOSECONDS.toMillis(
+ location.getElapsedRealtimeNanos()
+ - mLastLocation.getElapsedRealtimeNanos());
+ if (deltaMs < getRequest().getFastestInterval() - MAX_FASTEST_INTERVAL_JITTER_MS) {
+ return null;
+ }
+
+ // check smallest displacement
+ double smallestDisplacement = getRequest().getSmallestDisplacement();
+ if (smallestDisplacement > 0.0 && location.distanceTo(mLastLocation)
+ <= smallestDisplacement) {
+ return null;
+ }
+ }
+
+ // note app ops
+ if (!mAppOpsHelper.noteOpNoThrow(LocationPermissions.asAppOp(mPermissionLevel),
+ getIdentity())) {
+ if (D) {
+ Log.w(TAG, "noteOp denied for " + getIdentity());
+ }
+ return null;
+ }
+
+ // update last location
+ mLastLocation = location;
+
+ return new ListenerOperation<LocationTransport>() {
+ @Override
+ public void onPreExecute() {
+ // don't acquire a wakelock for mock locations to prevent abuse
+ if (!location.isFromMockProvider()) {
+ mWakeLock.acquire(WAKELOCK_TIMEOUT_MS);
+ }
+ }
+
+ @Override
+ public void operate(LocationTransport listener) throws Exception {
+ // if delivering to the same process, make a copy of the location first (since
+ // location is mutable)
+ Location deliveryLocation;
+ if (getIdentity().getPid() == Process.myPid()) {
+ deliveryLocation = new Location(location);
+ } else {
+ deliveryLocation = location;
+ }
+
+ listener.deliverOnLocationChanged(deliveryLocation,
+ location.isFromMockProvider() ? null : mWakeLock::release);
+ }
+
+ @Override
+ public void onPostExecute(boolean success) {
+ if (!success && !location.isFromMockProvider()) {
+ mWakeLock.release();
+ }
+
+ if (success) {
+ // check num updates - if successful then this function will always be run
+ // from the same thread, and no additional synchronization is necessary
+ boolean remove = ++mNumLocationsDelivered >= getRequest().getNumUpdates();
+ if (remove) {
+ if (D) {
+ Log.d(TAG, "removing " + getIdentity() + " from " + mName
+ + " provider due to number of updates");
+ }
+
+ synchronized (mLock) {
+ remove();
+ }
+ }
+ }
+ }
+ };
+ }
+
+ @Override
+ public void onProviderEnabledChanged(String provider, int userId, boolean enabled) {
+ Preconditions.checkState(mName.equals(provider));
+
+ if (userId != getIdentity().getUserId()) {
+ return;
+ }
+
+ // we choose not to hold a wakelock for provider enabled changed events
+ executeSafely(getExecutor(), () -> mProviderTransport,
+ listener -> listener.deliverOnProviderEnabledChanged(mName, enabled));
+ }
+ }
+
+ protected final class LocationListenerRegistration extends LocationRegistration implements
+ IBinder.DeathRecipient {
+
+ protected LocationListenerRegistration(LocationRequest request, CallerIdentity identity,
+ LocationListenerTransport transport, @PermissionLevel int permissionLevel) {
+ super(request, identity, transport, permissionLevel);
+ }
+
+ @GuardedBy("mLock")
+ @Override
+ protected void onLocationListenerRegister() {
+ try {
+ ((IBinder) getKey()).linkToDeath(this, 0);
+ } catch (RemoteException e) {
+ remove();
+ }
+ }
+
+ @GuardedBy("mLock")
+ @Override
+ protected void onLocationListenerUnregister() {
+ ((IBinder) getKey()).unlinkToDeath(this, 0);
+ }
+
+ @Override
+ public void binderDied() {
+ try {
+ if (D) {
+ Log.d(TAG, mName + " provider client died: " + getIdentity());
+ }
+
+ synchronized (mLock) {
+ remove();
+ }
+ } catch (RuntimeException e) {
+ // the caller may swallow runtime exceptions, so we rethrow as assertion errors to
+ // ensure the crash is seen
+ throw new AssertionError(e);
+ }
+ }
+ }
+
+ protected final class LocationPendingIntentRegistration extends LocationRegistration implements
+ PendingIntent.CancelListener {
+
+ protected LocationPendingIntentRegistration(LocationRequest request,
+ CallerIdentity identity, LocationPendingIntentTransport transport,
+ @PermissionLevel int permissionLevel) {
+ super(request, identity, transport, permissionLevel);
+ }
+
+ @GuardedBy("mLock")
+ @Override
+ protected void onLocationListenerRegister() {
+ ((PendingIntent) getKey()).registerCancelListener(this);
+ }
+
+ @GuardedBy("mLock")
+ @Override
+ protected void onLocationListenerUnregister() {
+ ((PendingIntent) getKey()).unregisterCancelListener(this);
+ }
+
+ @Override
+ public void onCancelled(PendingIntent intent) {
+ synchronized (mLock) {
+ remove();
+ }
+ }
+ }
+
+ protected final class GetCurrentLocationListenerRegistration extends Registration implements
+ IBinder.DeathRecipient, ProviderEnabledListener, AlarmManager.OnAlarmListener {
+
+ private volatile LocationTransport mTransport;
+
+ private long mExpirationRealtimeMs = Long.MAX_VALUE;
+
+ protected GetCurrentLocationListenerRegistration(LocationRequest request,
+ CallerIdentity identity, LocationTransport transport, int permissionLevel) {
+ super(request, identity, transport, permissionLevel);
+ mTransport = transport;
+ }
+
+ @GuardedBy("mLock")
+ void deliverLocation(@Nullable Location location) {
+ executeSafely(getExecutor(), () -> mTransport, acceptLocationChange(location));
+ }
+
+ @Override
+ protected void onListenerUnregister() {
+ mTransport = null;
+ }
+
+ @GuardedBy("mLock")
+ @Override
+ protected void onProviderListenerRegister() {
+ mExpirationRealtimeMs = getRequest().getExpirationRealtimeMs(
+ SystemClock.elapsedRealtime());
+
+ // add alarm for expiration
+ if (mExpirationRealtimeMs < Long.MAX_VALUE) {
+ AlarmManager alarmManager = Objects.requireNonNull(
+ mContext.getSystemService(AlarmManager.class));
+ alarmManager.set(ELAPSED_REALTIME_WAKEUP, mExpirationRealtimeMs, WINDOW_EXACT,
+ 0, this, FgThread.getHandler(), getWorkSource());
+ }
+
+ try {
+ ((IBinder) getKey()).linkToDeath(this, 0);
+ } catch (RemoteException e) {
+ remove();
+ }
+
+ // start listening for provider enabled/disabled events
+ addEnabledListener(this);
+
+ // if the provider is currently disabled fail immediately
+ int userId = getIdentity().getUserId();
+ if (!getRequest().isLocationSettingsIgnored() && !isEnabled(userId)) {
+ deliverLocation(null);
+ }
+ }
+
+ @GuardedBy("mLock")
+ @Override
+ protected void onProviderListenerUnregister() {
+ // stop listening for provider enabled/disabled events
+ removeEnabledListener(this);
+
+ // remove alarm for expiration
+ if (mExpirationRealtimeMs < Long.MAX_VALUE) {
+ AlarmManager alarmManager = Objects.requireNonNull(
+ mContext.getSystemService(AlarmManager.class));
+ alarmManager.cancel(this);
+ }
+
+ ((IBinder) getKey()).unlinkToDeath(this, 0);
+ }
+
+ @Override
+ public void onAlarm() {
+ if (D) {
+ Log.d(TAG, "removing " + getIdentity() + " from " + mName
+ + " provider due to expiration at " + TimeUtils.formatRealtime(
+ mExpirationRealtimeMs));
+ }
+
+ synchronized (mLock) {
+ deliverLocation(null);
+ }
+ }
+
+ @GuardedBy("mLock")
+ @Nullable
+ @Override
+ ListenerOperation<LocationTransport> acceptLocationChange(@Nullable Location fineLocation) {
+ if (Build.IS_DEBUGGABLE) {
+ Preconditions.checkState(Thread.holdsLock(mLock));
+ }
+
+ // lastly - note app ops
+ Location location;
+ if (fineLocation == null) {
+ location = null;
+ } else if (!mAppOpsHelper.noteOpNoThrow(LocationPermissions.asAppOp(mPermissionLevel),
+ getIdentity())) {
+ if (D) {
+ Log.w(TAG, "noteOp denied for " + getIdentity());
+ }
+ location = null;
+ } else {
+ switch (mPermissionLevel) {
+ case PERMISSION_FINE:
+ location = fineLocation;
+ break;
+ case PERMISSION_COARSE:
+ location = mLocationFudger.createCoarse(fineLocation);
+ break;
+ default:
+ // shouldn't be possible to have a client added without location permissions
+ throw new AssertionError();
+ }
+ }
+
+ return listener -> {
+ // if delivering to the same process, make a copy of the location first (since
+ // location is mutable)
+ Location deliveryLocation = location;
+ if (getIdentity().getPid() == Process.myPid() && location != null) {
+ deliveryLocation = new Location(location);
+ }
+
+ // we currently don't hold a wakelock for getCurrentLocation deliveries
+ listener.deliverOnLocationChanged(deliveryLocation, null);
+
+ synchronized (mLock) {
+ remove();
+ }
+ };
+ }
+
+ @Override
+ public void onProviderEnabledChanged(String provider, int userId, boolean enabled) {
+ Preconditions.checkState(mName.equals(provider));
+
+ if (userId != getIdentity().getUserId()) {
+ return;
+ }
+
+ // if the provider is disabled we give up on current location immediately
+ if (!getRequest().isLocationSettingsIgnored() && !enabled) {
+ synchronized (mLock) {
+ deliverLocation(null);
+ }
+ }
+ }
+
+ @Override
+ public void binderDied() {
+ try {
+ if (D) {
+ Log.d(TAG, mName + " provider client died: " + getIdentity());
+ }
+
+ synchronized (mLock) {
+ remove();
+ }
+ } catch (RuntimeException e) {
+ // the caller may swallow runtime exceptions, so we rethrow as assertion errors to
+ // ensure the crash is seen
+ throw new AssertionError(e);
+ }
+ }
+ }
+
+ protected final Object mLock = new Object();
+
+ protected final String mName;
+ @Nullable private final PassiveLocationProviderManager mPassiveManager;
+
+ protected final Context mContext;
+
+ @GuardedBy("mLock")
+ private boolean mStarted;
+
+ // maps of user id to value
+ @GuardedBy("mLock")
+ private final SparseBooleanArray mEnabled; // null or not present means unknown
+ @GuardedBy("mLock")
+ private final SparseArray<LastLocation> mLastLocations;
+
+ @GuardedBy("mLock")
+ private final ArrayList<ProviderEnabledListener> mEnabledListeners;
+
+ protected final LocationManagerInternal mLocationManagerInternal;
+ protected final SettingsHelper mSettingsHelper;
+ protected final UserInfoHelper mUserInfoHelper;
+ protected final AppOpsHelper mAppOpsHelper;
+ protected final LocationPermissionsHelper mLocationPermissionsHelper;
+ protected final AppForegroundHelper mAppForegroundHelper;
+ protected final LocationPowerSaveModeHelper mLocationPowerSaveModeHelper;
+ protected final ScreenInteractiveHelper mScreenInteractiveHelper;
+ protected final LocationAttributionHelper mLocationAttributionHelper;
+ protected final LocationUsageLogger mLocationUsageLogger;
+ protected final LocationFudger mLocationFudger;
+ protected final LocationRequestStatistics mLocationRequestStatistics;
+
+ private final UserListener mUserChangedListener = this::onUserChanged;
+ private final UserSettingChangedListener mLocationEnabledChangedListener =
+ this::onLocationEnabledChanged;
+ private final GlobalSettingChangedListener mBackgroundThrottlePackageWhitelistChangedListener =
+ this::onBackgroundThrottlePackageWhitelistChanged;
+ private final UserSettingChangedListener mLocationPackageBlacklistChangedListener =
+ this::onLocationPackageBlacklistChanged;
+ private final LocationPermissionsListener mLocationPermissionsListener =
+ new LocationPermissionsListener() {
+ @Override
+ public void onLocationPermissionsChanged(String packageName) {
+ LocationProviderManager.this.onLocationPermissionsChanged(packageName);
+ }
+
+ @Override
+ public void onLocationPermissionsChanged(int uid) {
+ LocationProviderManager.this.onLocationPermissionsChanged(uid);
+ }
+ };
+ private final AppForegroundListener mAppForegroundChangedListener =
+ this::onAppForegroundChanged;
+ private final GlobalSettingChangedListener mBackgroundThrottleIntervalChangedListener =
+ this::onBackgroundThrottleIntervalChanged;
+ private final GlobalSettingChangedListener mIgnoreSettingsPackageWhitelistChangedListener =
+ this::onIgnoreSettingsWhitelistChanged;
+ private final LocationPowerSaveModeChangedListener mLocationPowerSaveModeChangedListener =
+ this::onLocationPowerSaveModeChanged;
+ private final ScreenInteractiveChangedListener mScreenInteractiveChangedListener =
+ this::onScreenInteractiveChanged;
+
+ // acquiring mLock makes operations on mProvider atomic, but is otherwise unnecessary
+ protected final MockableLocationProvider mProvider;
+
+ LocationProviderManager(Context context, Injector injector, String name,
+ @Nullable PassiveLocationProviderManager passiveManager) {
+ mContext = context;
+ mName = Objects.requireNonNull(name);
+ mPassiveManager = passiveManager;
+ mStarted = false;
+ mEnabled = new SparseBooleanArray(2);
+ mLastLocations = new SparseArray<>(2);
+
+ mEnabledListeners = new ArrayList<>();
+
+ mLocationManagerInternal = Objects.requireNonNull(
+ LocalServices.getService(LocationManagerInternal.class));
+ mSettingsHelper = injector.getSettingsHelper();
+ mUserInfoHelper = injector.getUserInfoHelper();
+ mAppOpsHelper = injector.getAppOpsHelper();
+ mLocationPermissionsHelper = injector.getLocationPermissionsHelper();
+ mAppForegroundHelper = injector.getAppForegroundHelper();
+ mLocationPowerSaveModeHelper = injector.getLocationPowerSaveModeHelper();
+ mScreenInteractiveHelper = injector.getScreenInteractiveHelper();
+ mLocationAttributionHelper = injector.getLocationAttributionHelper();
+ mLocationUsageLogger = injector.getLocationUsageLogger();
+ mLocationRequestStatistics = injector.getLocationRequestStatistics();
+ mLocationFudger = new LocationFudger(mSettingsHelper.getCoarseLocationAccuracyM());
+
+ // initialize last since this lets our reference escape
+ mProvider = new MockableLocationProvider(mLock, this);
+ }
+
+ public void startManager() {
+ synchronized (mLock) {
+ mStarted = true;
+
+ mUserInfoHelper.addListener(mUserChangedListener);
+ mSettingsHelper.addOnLocationEnabledChangedListener(mLocationEnabledChangedListener);
+
+ // initialize enabled state
+ onUserStarted(UserHandle.USER_ALL);
+ }
+ }
+
+ public void stopManager() {
+ synchronized (mLock) {
+ mUserInfoHelper.removeListener(mUserChangedListener);
+ mSettingsHelper.removeOnLocationEnabledChangedListener(mLocationEnabledChangedListener);
+
+ // notify and remove all listeners
+ onUserStopped(UserHandle.USER_ALL);
+ removeRegistrationIf(key -> true);
+ mEnabledListeners.clear();
+
+ mStarted = false;
+ }
+ }
+
+ public String getName() {
+ return mName;
+ }
+
+ @Nullable
+ public CallerIdentity getIdentity() {
+ return mProvider.getState().identity;
+ }
+
+ @Nullable
+ public ProviderProperties getProperties() {
+ return mProvider.getState().properties;
+ }
+
+ public boolean hasProvider() {
+ return mProvider.getProvider() != null;
+ }
+
+ public boolean isEnabled(int userId) {
+ if (userId == UserHandle.USER_NULL) {
+ return false;
+ }
+
+ Preconditions.checkArgument(userId >= 0);
+
+ synchronized (mLock) {
+ int index = mEnabled.indexOfKey(userId);
+ if (index < 0) {
+ // this generally shouldn't occur, but might be possible due to race conditions
+ // on when we are notified of new users
+ Log.w(TAG, mName + " provider saw user " + userId + " unexpectedly");
+ onEnabledChanged(userId);
+ index = mEnabled.indexOfKey(userId);
+ }
+
+ return mEnabled.valueAt(index);
+ }
+ }
+
+ public void addEnabledListener(ProviderEnabledListener listener) {
+ synchronized (mLock) {
+ Preconditions.checkState(mStarted);
+ mEnabledListeners.add(listener);
+ }
+ }
+
+ public void removeEnabledListener(ProviderEnabledListener listener) {
+ synchronized (mLock) {
+ Preconditions.checkState(mStarted);
+ mEnabledListeners.remove(listener);
+ }
+ }
+
+ public void setRealProvider(AbstractLocationProvider provider) {
+ synchronized (mLock) {
+ Preconditions.checkState(mStarted);
+ mProvider.setRealProvider(provider);
+ }
+ }
+
+ public void setMockProvider(@Nullable MockProvider provider) {
+ synchronized (mLock) {
+ Preconditions.checkState(mStarted);
+ mProvider.setMockProvider(provider);
+
+ // when removing a mock provider, also clear any mock last locations and reset the
+ // location fudger. the mock provider could have been used to infer the current
+ // location fudger offsets.
+ if (provider == null) {
+ final int lastLocationSize = mLastLocations.size();
+ for (int i = 0; i < lastLocationSize; i++) {
+ mLastLocations.valueAt(i).clearMock();
+ }
+
+ mLocationFudger.resetOffsets();
+ }
+ }
+ }
+
+ public void setMockProviderAllowed(boolean enabled) {
+ synchronized (mLock) {
+ if (!mProvider.isMock()) {
+ throw new IllegalArgumentException(mName + " provider is not a test provider");
+ }
+
+ mProvider.setMockProviderAllowed(enabled);
+ }
+ }
+
+ public void setMockProviderLocation(Location location) {
+ synchronized (mLock) {
+ if (!mProvider.isMock()) {
+ throw new IllegalArgumentException(mName + " provider is not a test provider");
+ }
+
+ String locationProvider = location.getProvider();
+ if (!TextUtils.isEmpty(locationProvider) && !mName.equals(locationProvider)) {
+ // The location has an explicit provider that is different from the mock
+ // provider name. The caller may be trying to fool us via b/33091107.
+ EventLog.writeEvent(0x534e4554, "33091107", Binder.getCallingUid(),
+ mName + "!=" + locationProvider);
+ }
+
+ mProvider.setMockProviderLocation(location);
+ }
+ }
+
+ public List<LocationRequest> getMockProviderRequests() {
+ synchronized (mLock) {
+ if (!mProvider.isMock()) {
+ throw new IllegalArgumentException(mName + " provider is not a test provider");
+ }
+
+ return mProvider.getCurrentRequest().locationRequests;
+ }
+ }
+
+ @Nullable
+ public Location getLastLocation(LocationRequest request, CallerIdentity identity,
+ @PermissionLevel int permissionLevel) {
+ Preconditions.checkArgument(mName.equals(request.getProvider()));
+
+ if (mSettingsHelper.isLocationPackageBlacklisted(identity.getUserId(),
+ identity.getPackageName())) {
+ return null;
+ }
+ if (!mUserInfoHelper.isCurrentUserId(identity.getUserId())) {
+ return null;
+ }
+ if (!request.isLocationSettingsIgnored() && !isEnabled(identity.getUserId())) {
+ return null;
+ }
+
+ Location location = getLastLocation(identity.getUserId(), permissionLevel,
+ request.isLocationSettingsIgnored());
+
+ // we don't note op here because we don't know what the client intends to do with the
+ // location, the client is responsible for noting if necessary
+
+ if (identity.getPid() == Process.myPid() && location != null) {
+ // if delivering to the same process, make a copy of the location first (since
+ // location is mutable)
+ return new Location(location);
+ } else {
+ return location;
+ }
+ }
+
+ @Nullable
+ private Location getLastLocation(int userId, @PermissionLevel int permissionLevel,
+ boolean ignoreLocationSettings) {
+ synchronized (mLock) {
+ LastLocation lastLocation = mLastLocations.get(userId);
+ if (lastLocation == null) {
+ return null;
+ }
+ return lastLocation.get(permissionLevel, ignoreLocationSettings);
+ }
+ }
+
+ public void injectLastLocation(Location location, int userId) {
+ synchronized (mLock) {
+ if (getLastLocation(userId, PERMISSION_FINE, false) == null) {
+ setLastLocation(location, userId);
+ }
+ }
+ }
+
+ private void setLastLocation(Location location, int userId) {
+ if (userId == UserHandle.USER_ALL) {
+ final int[] runningUserIds = mUserInfoHelper.getRunningUserIds();
+ for (int i = 0; i < runningUserIds.length; i++) {
+ setLastLocation(location, runningUserIds[i]);
+ }
+ return;
+ }
+
+ Preconditions.checkArgument(userId >= 0);
+
+ synchronized (mLock) {
+ LastLocation lastLocation = mLastLocations.get(userId);
+ if (lastLocation == null) {
+ lastLocation = new LastLocation();
+ mLastLocations.put(userId, lastLocation);
+ }
+
+ Location coarseLocation = mLocationFudger.createCoarse(location);
+ if (isEnabled(userId)) {
+ lastLocation.set(location, coarseLocation);
+ }
+ lastLocation.setBypass(location, coarseLocation);
+ }
+ }
+
+ public void getCurrentLocation(LocationRequest request, CallerIdentity identity,
+ int permissionLevel, ICancellationSignal cancellationTransport,
+ ILocationCallback callback) {
+ Preconditions.checkArgument(mName.equals(request.getProvider()));
+
+ if (request.getExpireIn() > GET_CURRENT_LOCATION_MAX_TIMEOUT_MS) {
+ request.setExpireIn(GET_CURRENT_LOCATION_MAX_TIMEOUT_MS);
+ }
+
+ GetCurrentLocationListenerRegistration registration =
+ new GetCurrentLocationListenerRegistration(
+ request,
+ identity,
+ new GetCurrentLocationTransport(callback),
+ permissionLevel);
+
+ synchronized (mLock) {
+ Location lastLocation = getLastLocation(request, identity, permissionLevel);
+ if (lastLocation != null) {
+ long locationAgeMs = NANOSECONDS.toMillis(
+ SystemClock.elapsedRealtimeNanos()
+ - lastLocation.getElapsedRealtimeNanos());
+ if (locationAgeMs < MAX_CURRENT_LOCATION_AGE_MS) {
+ registration.deliverLocation(lastLocation);
+ return;
+ }
+
+ if (!mAppForegroundHelper.isAppForeground(Binder.getCallingUid())
+ && locationAgeMs < mSettingsHelper.getBackgroundThrottleIntervalMs()) {
+ registration.deliverLocation(null);
+ return;
+ }
+ }
+
+ // if last location isn't good enough then we add a location request
+ addRegistration(callback.asBinder(), registration);
+ CancellationSignal cancellationSignal = CancellationSignal.fromTransport(
+ cancellationTransport);
+ if (cancellationSignal != null) {
+ cancellationSignal.setOnCancelListener(
+ () -> {
+ synchronized (mLock) {
+ removeRegistration(callback.asBinder(), registration);
+ }
+ });
+ }
+ }
+ }
+
+ public void sendExtraCommand(int uid, int pid, String command, Bundle extras) {
+ mProvider.sendExtraCommand(uid, pid, command, extras);
+ }
+
+ public void registerLocationRequest(LocationRequest request, CallerIdentity identity,
+ @PermissionLevel int permissionLevel, ILocationListener listener) {
+ Preconditions.checkArgument(mName.equals(request.getProvider()));
+
+ synchronized (mLock) {
+ addRegistration(
+ listener.asBinder(),
+ new LocationListenerRegistration(
+ request,
+ identity,
+ new LocationListenerTransport(listener),
+ permissionLevel));
+ }
+ }
+
+ public void registerLocationRequest(LocationRequest request, CallerIdentity identity,
+ @PermissionLevel int permissionLevel, PendingIntent pendingIntent) {
+ Preconditions.checkArgument(mName.equals(request.getProvider()));
+
+ synchronized (mLock) {
+ addRegistration(
+ pendingIntent,
+ new LocationPendingIntentRegistration(
+ request,
+ identity,
+ new LocationPendingIntentTransport(mContext, pendingIntent),
+ permissionLevel));
+ }
+ }
+
+ public void unregisterLocationRequest(ILocationListener listener) {
+ synchronized (mLock) {
+ removeRegistration(listener.asBinder());
+ }
+ }
+
+ public void unregisterLocationRequest(PendingIntent pendingIntent) {
+ synchronized (mLock) {
+ removeRegistration(pendingIntent);
+ }
+ }
+
+ @GuardedBy("mLock")
+ @Override
+ protected void onRegister() {
+ if (Build.IS_DEBUGGABLE) {
+ Preconditions.checkState(Thread.holdsLock(mLock));
+ }
+
+ mSettingsHelper.addOnBackgroundThrottleIntervalChangedListener(
+ mBackgroundThrottleIntervalChangedListener);
+ mSettingsHelper.addOnBackgroundThrottlePackageWhitelistChangedListener(
+ mBackgroundThrottlePackageWhitelistChangedListener);
+ mSettingsHelper.addOnLocationPackageBlacklistChangedListener(
+ mLocationPackageBlacklistChangedListener);
+ mSettingsHelper.addOnIgnoreSettingsPackageWhitelistChangedListener(
+ mIgnoreSettingsPackageWhitelistChangedListener);
+ mLocationPermissionsHelper.addListener(mLocationPermissionsListener);
+ mAppForegroundHelper.addListener(mAppForegroundChangedListener);
+ mLocationPowerSaveModeHelper.addListener(mLocationPowerSaveModeChangedListener);
+ mScreenInteractiveHelper.addListener(mScreenInteractiveChangedListener);
+ }
+
+ @GuardedBy("mLock")
+ @Override
+ protected void onUnregister() {
+ if (Build.IS_DEBUGGABLE) {
+ Preconditions.checkState(Thread.holdsLock(mLock));
+ }
+
+ mSettingsHelper.removeOnBackgroundThrottleIntervalChangedListener(
+ mBackgroundThrottleIntervalChangedListener);
+ mSettingsHelper.removeOnBackgroundThrottlePackageWhitelistChangedListener(
+ mBackgroundThrottlePackageWhitelistChangedListener);
+ mSettingsHelper.removeOnLocationPackageBlacklistChangedListener(
+ mLocationPackageBlacklistChangedListener);
+ mSettingsHelper.removeOnIgnoreSettingsPackageWhitelistChangedListener(
+ mIgnoreSettingsPackageWhitelistChangedListener);
+ mLocationPermissionsHelper.removeListener(mLocationPermissionsListener);
+ mAppForegroundHelper.removeListener(mAppForegroundChangedListener);
+ mLocationPowerSaveModeHelper.removeListener(mLocationPowerSaveModeChangedListener);
+ mScreenInteractiveHelper.removeListener(mScreenInteractiveChangedListener);
+ }
+
+ @GuardedBy("mLock")
+ @Override
+ protected void onRegistrationAdded(Object key, Registration registration) {
+ if (Build.IS_DEBUGGABLE) {
+ Preconditions.checkState(Thread.holdsLock(mLock));
+ }
+
+ mLocationUsageLogger.logLocationApiUsage(
+ LocationStatsEnums.USAGE_STARTED,
+ LocationStatsEnums.API_REQUEST_LOCATION_UPDATES,
+ registration.getIdentity().getPackageName(),
+ registration.getRequest(),
+ key instanceof PendingIntent,
+ key instanceof IBinder,
+ /* geofence= */ null,
+ registration.isForeground());
+
+ mLocationRequestStatistics.startRequesting(
+ registration.getIdentity().getPackageName(),
+ registration.getIdentity().getAttributionTag(),
+ mName,
+ registration.getRequest().getInterval(),
+ registration.isForeground());
+ }
+
+ @GuardedBy("mLock")
+ @Override
+ protected void onRegistrationRemoved(Object key, Registration registration) {
+ if (Build.IS_DEBUGGABLE) {
+ Preconditions.checkState(Thread.holdsLock(mLock));
+ }
+
+ mLocationRequestStatistics.stopRequesting(
+ registration.getIdentity().getPackageName(),
+ registration.getIdentity().getAttributionTag(),
+ mName);
+
+ mLocationUsageLogger.logLocationApiUsage(
+ LocationStatsEnums.USAGE_ENDED,
+ LocationStatsEnums.API_REQUEST_LOCATION_UPDATES,
+ registration.getIdentity().getPackageName(),
+ registration.getRequest(),
+ key instanceof PendingIntent,
+ key instanceof IBinder,
+ /* geofence= */ null,
+ registration.isForeground());
+ }
+
+ @GuardedBy("mLock")
+ @Override
+ protected boolean registerWithService(ProviderRequest mergedRequest) {
+ if (Build.IS_DEBUGGABLE) {
+ Preconditions.checkState(Thread.holdsLock(mLock));
+ }
+
+ mProvider.setRequest(mergedRequest);
+ return true;
+ }
+
+ @GuardedBy("mLock")
+ @Override
+ protected boolean reregisterWithService(ProviderRequest oldRequest,
+ ProviderRequest newRequest) {
+ return registerWithService(newRequest);
+ }
+
+ @GuardedBy("mLock")
+ @Override
+ protected void unregisterWithService() {
+ if (Build.IS_DEBUGGABLE) {
+ Preconditions.checkState(Thread.holdsLock(mLock));
+ }
+ mProvider.setRequest(ProviderRequest.EMPTY_REQUEST);
+ }
+
+ @GuardedBy("mLock")
+ @Override
+ protected boolean isActive(Registration registration) {
+ if (Build.IS_DEBUGGABLE) {
+ Preconditions.checkState(Thread.holdsLock(mLock));
+ }
+
+ CallerIdentity identity = registration.getIdentity();
+
+ if (!registration.isPermitted()) {
+ return false;
+ }
+
+ if (!registration.getRequest().isLocationSettingsIgnored()) {
+ if (!isEnabled(identity.getUserId())) {
+ return false;
+ }
+
+ switch (mLocationPowerSaveModeHelper.getLocationPowerSaveMode()) {
+ case LOCATION_MODE_FOREGROUND_ONLY:
+ if (!registration.isForeground()) {
+ return false;
+ }
+ break;
+ case LOCATION_MODE_GPS_DISABLED_WHEN_SCREEN_OFF:
+ if (!GPS_PROVIDER.equals(mName)) {
+ break;
+ }
+ // fall through
+ case LOCATION_MODE_THROTTLE_REQUESTS_WHEN_SCREEN_OFF:
+ // fall through
+ case LOCATION_MODE_ALL_DISABLED_WHEN_SCREEN_OFF:
+ if (!mScreenInteractiveHelper.isInteractive()) {
+ return false;
+ }
+ break;
+ case LOCATION_MODE_NO_CHANGE:
+ // fall through
+ default:
+ break;
+ }
+ }
+
+ return !mSettingsHelper.isLocationPackageBlacklisted(identity.getUserId(),
+ identity.getPackageName());
+ }
+
+ @GuardedBy("mLock")
+ @Override
+ protected ProviderRequest mergeRequests(Collection<Registration> registrations) {
+ if (Build.IS_DEBUGGABLE) {
+ Preconditions.checkState(Thread.holdsLock(mLock));
+ }
+
+ ProviderRequest.Builder providerRequest = new ProviderRequest.Builder();
+ // initialize the low power mode to true and set to false if any of the records requires
+ providerRequest.setLowPowerMode(true);
+
+ ArrayList<Registration> providerRegistrations = new ArrayList<>(registrations.size());
+ for (Registration registration : registrations) {
+ LocationRequest locationRequest = registration.getRequest();
+
+ if (locationRequest.isLocationSettingsIgnored()) {
+ providerRequest.setLocationSettingsIgnored(true);
+ }
+ if (!locationRequest.isLowPowerMode()) {
+ providerRequest.setLowPowerMode(false);
+ }
+
+ providerRequest.setInterval(
+ Math.min(locationRequest.getInterval(), providerRequest.getInterval()));
+ providerRegistrations.add(registration);
+ }
+
+ // collect contributing location requests
+ ArrayList<LocationRequest> providerRequests = new ArrayList<>(providerRegistrations.size());
+ final int registrationsSize = providerRegistrations.size();
+ for (int i = 0; i < registrationsSize; i++) {
+ providerRequests.add(providerRegistrations.get(i).getRequest());
+ }
+
+ providerRequest.setLocationRequests(providerRequests);
+
+ // calculate who to blame for power in a somewhat arbitrary fashion. we pick a threshold
+ // interval slightly higher that the minimum interval, and spread the blame across all
+ // contributing registrations under that threshold.
+ long thresholdIntervalMs = (providerRequest.getInterval() + 1000) * 3 / 2;
+ if (thresholdIntervalMs < 0) {
+ // handle overflow
+ thresholdIntervalMs = Long.MAX_VALUE;
+ }
+ for (int i = 0; i < registrationsSize; i++) {
+ LocationRequest request = providerRegistrations.get(i).getRequest();
+ if (request.getInterval() <= thresholdIntervalMs) {
+ providerRequest.getWorkSource().add(providerRegistrations.get(i).getWorkSource());
+ }
+ }
+
+ return providerRequest.build();
+ }
+
+ private void onUserChanged(int userId, int change) {
+ synchronized (mLock) {
+ switch (change) {
+ case UserListener.CURRENT_USER_CHANGED:
+ onEnabledChanged(userId);
+ break;
+ case UserListener.USER_STARTED:
+ onUserStarted(userId);
+ break;
+ case UserListener.USER_STOPPED:
+ onUserStopped(userId);
+ break;
+ }
+ }
+ }
+
+ private void onLocationEnabledChanged(int userId) {
+ synchronized (mLock) {
+ onEnabledChanged(userId);
+ }
+ }
+
+ private void onScreenInteractiveChanged(boolean screenInteractive) {
+ synchronized (mLock) {
+ switch (mLocationPowerSaveModeHelper.getLocationPowerSaveMode()) {
+ case LOCATION_MODE_GPS_DISABLED_WHEN_SCREEN_OFF:
+ if (!GPS_PROVIDER.equals(mName)) {
+ break;
+ }
+ // fall through
+ case LOCATION_MODE_THROTTLE_REQUESTS_WHEN_SCREEN_OFF:
+ // fall through
+ case LOCATION_MODE_ALL_DISABLED_WHEN_SCREEN_OFF:
+ updateService();
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ private void onBackgroundThrottlePackageWhitelistChanged() {
+ synchronized (mLock) {
+ updateRegistrations(Registration::onProviderLocationRequestChanged);
+ }
+ }
+
+ private void onBackgroundThrottleIntervalChanged() {
+ synchronized (mLock) {
+ updateRegistrations(Registration::onProviderLocationRequestChanged);
+ }
+ }
+
+ private void onLocationPowerSaveModeChanged(@LocationPowerSaveMode int locationPowerSaveMode) {
+ synchronized (mLock) {
+ // this is rare, just assume everything has changed to keep it simple
+ updateRegistrations(registration -> true);
+ }
+ }
+
+ private void onAppForegroundChanged(int uid, boolean foreground) {
+ synchronized (mLock) {
+ updateRegistrations(registration -> registration.onForegroundChanged(uid, foreground));
+ }
+ }
+
+ private void onIgnoreSettingsWhitelistChanged() {
+ synchronized (mLock) {
+ updateRegistrations(Registration::onProviderLocationRequestChanged);
+ }
+ }
+
+ private void onLocationPackageBlacklistChanged(int userId) {
+ synchronized (mLock) {
+ updateRegistrations(registration -> registration.getIdentity().getUserId() == userId);
+ }
+ }
+
+ private void onLocationPermissionsChanged(String packageName) {
+ synchronized (mLock) {
+ updateRegistrations(
+ registration -> registration.onLocationPermissionsChanged(packageName));
+ }
+ }
+
+ private void onLocationPermissionsChanged(int uid) {
+ synchronized (mLock) {
+ updateRegistrations(registration -> registration.onLocationPermissionsChanged(uid));
+ }
+ }
+
+ @GuardedBy("mLock")
+ @Override
+ public void onStateChanged(
+ AbstractLocationProvider.State oldState, AbstractLocationProvider.State newState) {
+ if (Build.IS_DEBUGGABLE) {
+ Preconditions.checkState(Thread.holdsLock(mLock));
+ }
+
+ if (oldState.allowed != newState.allowed) {
+ onEnabledChanged(UserHandle.USER_ALL);
+ }
+ }
+
+ @GuardedBy("mLock")
+ @Override
+ public void onReportLocation(Location location) {
+ if (Build.IS_DEBUGGABLE) {
+ Preconditions.checkState(Thread.holdsLock(mLock));
+ }
+
+ // don't validate mock locations
+ if (!location.isFromMockProvider()) {
+ if (location.getLatitude() == 0 && location.getLongitude() == 0) {
+ Log.w(TAG, "blocking 0,0 location from " + mName + " provider");
+ return;
+ }
+ }
+
+ if (!location.isComplete()) {
+ Log.w(TAG, "blocking incomplete location from " + mName + " provider");
+ return;
+ }
+
+ // update last location
+ setLastLocation(location, UserHandle.USER_ALL);
+
+ // notify passive provider
+ if (mPassiveManager != null) {
+ mPassiveManager.updateLocation(location);
+ }
+
+ // attempt listener delivery
+ deliverToListeners(registration -> {
+ return registration.acceptLocationChange(location);
+ });
+ }
+
+ @GuardedBy("mLock")
+ @Override
+ public void onReportLocation(List<Location> locations) {
+ if (!GPS_PROVIDER.equals(mName)) {
+ return;
+ }
+
+ mLocationManagerInternal.reportGnssBatchLocations(locations);
+ }
+
+ @GuardedBy("mLock")
+ private void onUserStarted(int userId) {
+ if (Build.IS_DEBUGGABLE) {
+ Preconditions.checkState(Thread.holdsLock(mLock));
+ }
+
+ if (userId == UserHandle.USER_NULL) {
+ return;
+ }
+
+ if (userId == UserHandle.USER_ALL) {
+ // clear the user's prior enabled state to prevent broadcast of enabled state change
+ mEnabled.clear();
+ onEnabledChanged(UserHandle.USER_ALL);
+ } else {
+ Preconditions.checkArgument(userId >= 0);
+
+ // clear the user's prior enabled state to prevent broadcast of enabled state change
+ mEnabled.delete(userId);
+ onEnabledChanged(userId);
+ }
+ }
+
+ @GuardedBy("mLock")
+ private void onUserStopped(int userId) {
+ if (Build.IS_DEBUGGABLE) {
+ Preconditions.checkState(Thread.holdsLock(mLock));
+ }
+
+ if (userId == UserHandle.USER_NULL) {
+ return;
+ }
+
+ if (userId == UserHandle.USER_ALL) {
+ onEnabledChanged(UserHandle.USER_ALL);
+ mEnabled.clear();
+ mLastLocations.clear();
+ } else {
+ Preconditions.checkArgument(userId >= 0);
+
+ onEnabledChanged(userId);
+ mEnabled.delete(userId);
+ mLastLocations.remove(userId);
+ }
+ }
+
+ @GuardedBy("mLock")
+ private void onEnabledChanged(int userId) {
+ if (Build.IS_DEBUGGABLE) {
+ Preconditions.checkState(Thread.holdsLock(mLock));
+ }
+
+ if (userId == UserHandle.USER_NULL) {
+ // used during initialization - ignore since many lower level operations (checking
+ // settings for instance) do not support the null user
+ return;
+ } else if (userId == UserHandle.USER_ALL) {
+ final int[] runningUserIds = mUserInfoHelper.getRunningUserIds();
+ for (int i = 0; i < runningUserIds.length; i++) {
+ onEnabledChanged(runningUserIds[i]);
+ }
+ return;
+ }
+
+ Preconditions.checkArgument(userId >= 0);
+
+ boolean enabled = mStarted
+ && mProvider.getState().allowed
+ && mUserInfoHelper.isCurrentUserId(userId)
+ && mSettingsHelper.isLocationEnabled(userId);
+
+ int index = mEnabled.indexOfKey(userId);
+ Boolean wasEnabled = index < 0 ? null : mEnabled.valueAt(index);
+ if (wasEnabled != null && wasEnabled == enabled) {
+ return;
+ }
+
+ mEnabled.put(userId, enabled);
+
+ if (D) {
+ Log.d(TAG, "[u" + userId + "] " + mName + " provider enabled = " + enabled);
+ }
+
+ // clear last locations if we become disabled
+ if (!enabled) {
+ LastLocation lastLocation = mLastLocations.get(userId);
+ if (lastLocation != null) {
+ lastLocation.clearLocations();
+ }
+ }
+
+ // do not send change notifications if we just saw this user for the first time
+ if (wasEnabled != null) {
+ // fused and passive provider never get public updates for legacy reasons
+ if (!FUSED_PROVIDER.equals(mName) && !PASSIVE_PROVIDER.equals(mName)) {
+ Intent intent = new Intent(LocationManager.PROVIDERS_CHANGED_ACTION)
+ .putExtra(LocationManager.EXTRA_PROVIDER_NAME, mName)
+ .putExtra(LocationManager.EXTRA_PROVIDER_ENABLED, enabled)
+ .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY)
+ .addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+ mContext.sendBroadcastAsUser(intent, UserHandle.of(userId));
+ }
+
+ // send updates to internal listeners - since we expect listener changes to be more
+ // frequent than enabled changes, we use copy-on-read instead of copy-on-write
+ if (!mEnabledListeners.isEmpty()) {
+ ProviderEnabledListener[] listeners = mEnabledListeners.toArray(
+ new ProviderEnabledListener[0]);
+ FgThread.getHandler().post(() -> {
+ for (int i = 0; i < listeners.length; i++) {
+ listeners[i].onProviderEnabledChanged(mName, userId, enabled);
+ }
+ });
+ }
+ }
+
+ // update active state of affected registrations
+ updateRegistrations(registration -> registration.getIdentity().getUserId() == userId);
+ }
+
+ public void dump(FileDescriptor fd, IndentingPrintWriter ipw, String[] args) {
+ synchronized (mLock) {
+ ipw.print(mName + " provider");
+ if (mProvider.isMock()) {
+ ipw.print(" [mock]");
+ }
+ ipw.println(":");
+ ipw.increaseIndent();
+
+ super.dump(fd, ipw, args);
+
+ int[] userIds = mUserInfoHelper.getRunningUserIds();
+ for (int userId : userIds) {
+ if (userIds.length != 1) {
+ ipw.println("user " + userId + ":");
+ ipw.increaseIndent();
+ }
+ ipw.println("last location=" + getLastLocation(userId, PERMISSION_FINE, false));
+ ipw.println("enabled=" + isEnabled(userId));
+ if (userIds.length != 1) {
+ ipw.decreaseIndent();
+ }
+ }
+ }
+
+ mProvider.dump(fd, ipw, args);
+
+ ipw.decreaseIndent();
+ }
+
+ private static class LastLocation {
+
+ @Nullable private Location mFineLocation;
+ @Nullable private Location mCoarseLocation;
+ @Nullable private Location mFineBypassLocation;
+ @Nullable private Location mCoarseBypassLocation;
+
+ public void clearMock() {
+ if (mFineLocation != null && mFineLocation.isFromMockProvider()) {
+ mFineLocation = null;
+ mCoarseLocation = null;
+ }
+ if (mFineBypassLocation != null && mFineBypassLocation.isFromMockProvider()) {
+ mFineBypassLocation = null;
+ mCoarseBypassLocation = null;
+ }
+ }
+
+ public void clearLocations() {
+ mFineLocation = null;
+ mCoarseLocation = null;
+ }
+
+ @Nullable
+ public Location get(@PermissionLevel int permissionLevel, boolean ignoreLocationSettings) {
+ switch (permissionLevel) {
+ case PERMISSION_FINE:
+ if (ignoreLocationSettings) {
+ return mFineBypassLocation;
+ } else {
+ return mFineLocation;
+ }
+ case PERMISSION_COARSE:
+ if (ignoreLocationSettings) {
+ return mCoarseBypassLocation;
+ } else {
+ return mCoarseLocation;
+ }
+ default:
+ // shouldn't be possible to have a client added without location permissions
+ throw new AssertionError();
+ }
+ }
+
+ public void set(Location location, Location coarseLocation) {
+ mFineLocation = location;
+ mCoarseLocation = calculateNextCoarse(mCoarseLocation, coarseLocation);
+ }
+
+ public void setBypass(Location location, Location coarseLocation) {
+ mFineBypassLocation = location;
+ mCoarseBypassLocation = calculateNextCoarse(mCoarseBypassLocation, coarseLocation);
+ }
+
+ private Location calculateNextCoarse(@Nullable Location oldCoarse, Location newCoarse) {
+ if (oldCoarse == null) {
+ return newCoarse;
+ }
+ // update last coarse interval only if enough time has passed
+ long timeDeltaMs = NANOSECONDS.toMillis(newCoarse.getElapsedRealtimeNanos())
+ - NANOSECONDS.toMillis(oldCoarse.getElapsedRealtimeNanos());
+ if (timeDeltaMs > FASTEST_COARSE_INTERVAL_MS) {
+ return newCoarse;
+ } else {
+ return oldCoarse;
+ }
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/location/MockProvider.java b/services/core/java/com/android/server/location/MockProvider.java
index c5bd5e6fed8c..fc88f147ea9d 100644
--- a/services/core/java/com/android/server/location/MockProvider.java
+++ b/services/core/java/com/android/server/location/MockProvider.java
@@ -40,9 +40,8 @@ public class MockProvider extends AbstractLocationProvider {
public MockProvider(ProviderProperties properties, CallerIdentity identity) {
// using a direct executor is ok because this class has no locks that could deadlock
- super(DIRECT_EXECUTOR);
+ super(DIRECT_EXECUTOR, identity);
setProperties(properties);
- setIdentity(identity);
}
/** Sets the allowed state of this mock provider. */
diff --git a/services/core/java/com/android/server/location/MockableLocationProvider.java b/services/core/java/com/android/server/location/MockableLocationProvider.java
index 54af1c84d36b..d8d435aa4ac0 100644
--- a/services/core/java/com/android/server/location/MockableLocationProvider.java
+++ b/services/core/java/com/android/server/location/MockableLocationProvider.java
@@ -241,7 +241,6 @@ public class MockableLocationProvider extends AbstractLocationProvider {
if (getState().properties != null) {
pw.println("properties=" + getState().properties);
}
- pw.println("request=" + mRequest);
}
if (provider != null) {
diff --git a/services/core/java/com/android/server/location/PassiveLocationProviderManager.java b/services/core/java/com/android/server/location/PassiveLocationProviderManager.java
new file mode 100644
index 000000000000..d4999ab8be0a
--- /dev/null
+++ b/services/core/java/com/android/server/location/PassiveLocationProviderManager.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.location;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.location.Location;
+import android.location.LocationManager;
+import android.os.Binder;
+
+import com.android.internal.util.Preconditions;
+import com.android.server.location.util.Injector;
+
+class PassiveLocationProviderManager extends LocationProviderManager {
+
+ PassiveLocationProviderManager(Context context, Injector injector) {
+ super(context, injector, LocationManager.PASSIVE_PROVIDER, null);
+ }
+
+ @Override
+ public void setRealProvider(AbstractLocationProvider provider) {
+ Preconditions.checkArgument(provider instanceof PassiveProvider);
+ super.setRealProvider(provider);
+ }
+
+ @Override
+ public void setMockProvider(@Nullable MockProvider provider) {
+ if (provider != null) {
+ throw new IllegalArgumentException("Cannot mock the passive provider");
+ }
+ }
+
+ public void updateLocation(Location location) {
+ synchronized (mLock) {
+ PassiveProvider passiveProvider = (PassiveProvider) mProvider.getProvider();
+ Preconditions.checkState(passiveProvider != null);
+
+ long identity = Binder.clearCallingIdentity();
+ try {
+ passiveProvider.updateLocation(location);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/location/gnss/GnssListenerMultiplexer.java b/services/core/java/com/android/server/location/gnss/GnssListenerMultiplexer.java
index 0b7968be484b..1b599b026c38 100644
--- a/services/core/java/com/android/server/location/gnss/GnssListenerMultiplexer.java
+++ b/services/core/java/com/android/server/location/gnss/GnssListenerMultiplexer.java
@@ -16,17 +16,21 @@
package com.android.server.location.gnss;
+import static android.location.LocationManager.GPS_PROVIDER;
+
import static com.android.server.location.LocationPermissions.PERMISSION_FINE;
import static com.android.server.location.gnss.GnssManagerService.TAG;
import android.annotation.Nullable;
import android.location.LocationManagerInternal;
+import android.location.LocationManagerInternal.ProviderEnabledListener;
import android.location.util.identity.CallerIdentity;
import android.os.IBinder;
import android.os.IInterface;
import android.os.Process;
import android.util.ArraySet;
+import com.android.internal.util.Preconditions;
import com.android.server.LocalServices;
import com.android.server.location.listeners.BinderListenerRegistration;
import com.android.server.location.listeners.ListenerMultiplexer;
@@ -161,8 +165,8 @@ public abstract class GnssListenerMultiplexer<TRequest, TListener extends IInter
protected final LocationManagerInternal mLocationManagerInternal;
private final UserListener mUserChangedListener = this::onUserChanged;
- private final SettingsHelper.UserSettingChangedListener mLocationEnabledChangedListener =
- this::onLocationEnabledChanged;
+ private final ProviderEnabledListener mProviderEnabledChangedListener =
+ this::onProviderEnabledChanged;
private final SettingsHelper.GlobalSettingChangedListener
mBackgroundThrottlePackageWhitelistChangedListener =
this::onBackgroundThrottlePackageWhitelistChanged;
@@ -233,12 +237,11 @@ public abstract class GnssListenerMultiplexer<TRequest, TListener extends IInter
}
CallerIdentity identity = registration.getIdentity();
- // TODO: this should be checking if the gps provider is enabled, not if location is enabled,
- // but this is the same for now.
return registration.isPermitted()
&& (registration.isForeground() || isBackgroundRestrictionExempt(identity))
&& mUserInfoHelper.isCurrentUserId(identity.getUserId())
- && mSettingsHelper.isLocationEnabled(identity.getUserId())
+ && mLocationManagerInternal.isProviderEnabledForUser(GPS_PROVIDER,
+ identity.getUserId())
&& !mSettingsHelper.isLocationPackageBlacklisted(identity.getUserId(),
identity.getPackageName());
}
@@ -263,7 +266,8 @@ public abstract class GnssListenerMultiplexer<TRequest, TListener extends IInter
}
mUserInfoHelper.addListener(mUserChangedListener);
- mSettingsHelper.addOnLocationEnabledChangedListener(mLocationEnabledChangedListener);
+ mLocationManagerInternal.addProviderEnabledListener(GPS_PROVIDER,
+ mProviderEnabledChangedListener);
mSettingsHelper.addOnBackgroundThrottlePackageWhitelistChangedListener(
mBackgroundThrottlePackageWhitelistChangedListener);
mSettingsHelper.addOnLocationPackageBlacklistChangedListener(
@@ -279,7 +283,8 @@ public abstract class GnssListenerMultiplexer<TRequest, TListener extends IInter
}
mUserInfoHelper.removeListener(mUserChangedListener);
- mSettingsHelper.removeOnLocationEnabledChangedListener(mLocationEnabledChangedListener);
+ mLocationManagerInternal.removeProviderEnabledListener(GPS_PROVIDER,
+ mProviderEnabledChangedListener);
mSettingsHelper.removeOnBackgroundThrottlePackageWhitelistChangedListener(
mBackgroundThrottlePackageWhitelistChangedListener);
mSettingsHelper.removeOnLocationPackageBlacklistChangedListener(
@@ -294,7 +299,8 @@ public abstract class GnssListenerMultiplexer<TRequest, TListener extends IInter
}
}
- private void onLocationEnabledChanged(int userId) {
+ private void onProviderEnabledChanged(String provider, int userId, boolean enabled) {
+ Preconditions.checkState(GPS_PROVIDER.equals(provider));
updateRegistrations(registration -> registration.getIdentity().getUserId() == userId);
}
diff --git a/services/core/java/com/android/server/location/gnss/GnssNetworkConnectivityHandler.java b/services/core/java/com/android/server/location/gnss/GnssNetworkConnectivityHandler.java
index e17cca423822..cea5a69526c6 100644
--- a/services/core/java/com/android/server/location/gnss/GnssNetworkConnectivityHandler.java
+++ b/services/core/java/com/android/server/location/gnss/GnssNetworkConnectivityHandler.java
@@ -88,7 +88,7 @@ class GnssNetworkConnectivityHandler {
// Default time limit in milliseconds for the ConnectivityManager to find a suitable
// network with SUPL connectivity or report an error.
- private static final int SUPL_NETWORK_REQUEST_TIMEOUT_MILLIS = 10 * 1000;
+ private static final int SUPL_NETWORK_REQUEST_TIMEOUT_MILLIS = 20 * 1000;
private static final int HASH_MAP_INITIAL_CAPACITY_TO_TRACK_CONNECTED_NETWORKS = 5;
diff --git a/services/core/java/com/android/server/location/listeners/ListenerMultiplexer.java b/services/core/java/com/android/server/location/listeners/ListenerMultiplexer.java
index 528cf8acd5b3..f94de9be0cfe 100644
--- a/services/core/java/com/android/server/location/listeners/ListenerMultiplexer.java
+++ b/services/core/java/com/android/server/location/listeners/ListenerMultiplexer.java
@@ -104,18 +104,18 @@ public abstract class ListenerMultiplexer<TKey, TRequest, TListener,
* should return true if a matching call to {@link #unregisterWithService()} is required to
* unregister (ie, if registration succeeds).
*
- * @see #reregisterWithService(Object)
+ * @see #reregisterWithService(Object, Object)
*/
- protected abstract boolean registerWithService(TMergedRequest mergedRequest);
+ protected abstract boolean registerWithService(TMergedRequest newRequest);
/**
* Invoked when the service already has a request, and it is being replaced with a new request.
* The default implementation unregisters first, then registers with the new merged request, but
* this may be overridden by subclasses in order to reregister more efficiently.
*/
- protected boolean reregisterWithService(TMergedRequest mergedRequest) {
+ protected boolean reregisterWithService(TMergedRequest oldRequest, TMergedRequest newRequest) {
unregisterWithService();
- return registerWithService(mergedRequest);
+ return registerWithService(newRequest);
}
/**
@@ -368,6 +368,7 @@ public abstract class ListenerMultiplexer<TKey, TRequest, TListener,
mCurrentRequest = null;
if (mServiceRegistered) {
mServiceRegistered = false;
+ mCurrentRequest = null;
unregisterWithService();
}
return;
@@ -376,11 +377,15 @@ public abstract class ListenerMultiplexer<TKey, TRequest, TListener,
TMergedRequest merged = mergeRequests(actives);
if (!mServiceRegistered || !Objects.equals(merged, mCurrentRequest)) {
if (mServiceRegistered) {
- mServiceRegistered = reregisterWithService(merged);
+ mServiceRegistered = reregisterWithService(mCurrentRequest, merged);
} else {
mServiceRegistered = registerWithService(merged);
}
- mCurrentRequest = merged;
+ if (mServiceRegistered) {
+ mCurrentRequest = merged;
+ } else {
+ mCurrentRequest = null;
+ }
}
} finally {
Binder.restoreCallingIdentity(identity);
@@ -389,29 +394,6 @@ public abstract class ListenerMultiplexer<TKey, TRequest, TListener,
}
/**
- * Evaluates the given predicate for all registrations, and forces an {@link #updateService()}
- * if any predicate returns true for an active registration. The predicate will always be
- * evaluated for all registrations, even inactive registrations, or if it has already returned
- * true for a prior registration.
- */
- protected final void updateService(Predicate<TRegistration> predicate) {
- synchronized (mRegistrations) {
- boolean updateService = false;
- final int size = mRegistrations.size();
- for (int i = 0; i < size; i++) {
- TRegistration registration = mRegistrations.valueAt(i);
- if (predicate.test(registration) && registration.isActive()) {
- updateService = true;
- }
- }
-
- if (updateService) {
- updateService();
- }
- }
- }
-
- /**
* Begins buffering calls to {@link #updateService()} until {@link UpdateServiceLock#close()}
* is called. This is useful to prevent extra work when combining multiple calls (for example,
* buffering {@code updateService()} until after multiple adds/removes/updates occur.
diff --git a/services/core/java/com/android/server/location/listeners/ListenerRegistration.java b/services/core/java/com/android/server/location/listeners/ListenerRegistration.java
index 0bdd1316d265..ac56c51568be 100644
--- a/services/core/java/com/android/server/location/listeners/ListenerRegistration.java
+++ b/services/core/java/com/android/server/location/listeners/ListenerRegistration.java
@@ -24,6 +24,7 @@ import android.annotation.Nullable;
import android.location.util.identity.CallerIdentity;
import android.os.Process;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.listeners.ListenerExecutor;
import com.android.server.FgThread;
@@ -39,6 +40,9 @@ import java.util.concurrent.Executor;
*/
public class ListenerRegistration<TRequest, TListener> implements ListenerExecutor {
+ @VisibleForTesting
+ public static final Executor IN_PROCESS_EXECUTOR = FgThread.getExecutor();
+
private final Executor mExecutor;
private final @Nullable TRequest mRequest;
private final CallerIdentity mIdentity;
@@ -55,9 +59,9 @@ public class ListenerRegistration<TRequest, TListener> implements ListenerExecut
// there's a slight loophole here for pending intents - pending intent callbacks can
// always be run on the direct executor since they're always asynchronous, but honestly
// you shouldn't be using pending intent callbacks within the same process anyways
- mExecutor = FgThread.getExecutor();
+ mExecutor = IN_PROCESS_EXECUTOR;
} else {
- mExecutor = DIRECT_EXECUTOR;
+ mExecutor = DIRECT_EXECUTOR;
}
mRequest = request;
@@ -73,7 +77,7 @@ public class ListenerRegistration<TRequest, TListener> implements ListenerExecut
/**
* Returns the request associated with this listener, or null if one wasn't supplied.
*/
- public final @Nullable TRequest getRequest() {
+ public @Nullable TRequest getRequest() {
return mRequest;
}
@@ -107,7 +111,7 @@ public class ListenerRegistration<TRequest, TListener> implements ListenerExecut
*/
protected void onInactive() {}
- final boolean isActive() {
+ public final boolean isActive() {
return mActive;
}
@@ -120,7 +124,7 @@ public class ListenerRegistration<TRequest, TListener> implements ListenerExecut
return false;
}
- final boolean isRegistered() {
+ public final boolean isRegistered() {
return mListener != null;
}
diff --git a/services/core/java/com/android/server/location/listeners/RemovableListenerRegistration.java b/services/core/java/com/android/server/location/listeners/RemovableListenerRegistration.java
index 6a815ead9f9f..0698cca903f0 100644
--- a/services/core/java/com/android/server/location/listeners/RemovableListenerRegistration.java
+++ b/services/core/java/com/android/server/location/listeners/RemovableListenerRegistration.java
@@ -39,7 +39,7 @@ public abstract class RemovableListenerRegistration<TRequest, TListener> extends
protected RemovableListenerRegistration(String tag, @Nullable TRequest request,
CallerIdentity callerIdentity, TListener listener) {
super(request, callerIdentity, listener);
- mTag = tag;
+ mTag = Objects.requireNonNull(tag);
}
/**
diff --git a/services/core/java/com/android/server/media/HandlerExecutor.java b/services/core/java/com/android/server/media/HandlerExecutor.java
new file mode 100644
index 000000000000..7c9e72bcf384
--- /dev/null
+++ b/services/core/java/com/android/server/media/HandlerExecutor.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.media;
+
+import android.annotation.NonNull;
+import android.os.Handler;
+
+import java.util.Objects;
+import java.util.concurrent.Executor;
+import java.util.concurrent.RejectedExecutionException;
+
+/**
+ * An adapter {@link Executor} that posts all executed tasks onto the given
+ * {@link Handler}.
+ *
+ * @hide
+ */
+public class HandlerExecutor implements Executor {
+ private final Handler mHandler;
+
+ public HandlerExecutor(@NonNull Handler handler) {
+ mHandler = Objects.requireNonNull(handler);
+ }
+
+ @Override
+ public void execute(Runnable command) {
+ if (!mHandler.post(command)) {
+ throw new RejectedExecutionException(mHandler + " is shutting down");
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/media/MediaSession2Record.java b/services/core/java/com/android/server/media/MediaSession2Record.java
index 5d1b74912546..162c388dadd1 100644
--- a/services/core/java/com/android/server/media/MediaSession2Record.java
+++ b/services/core/java/com/android/server/media/MediaSession2Record.java
@@ -20,7 +20,6 @@ import android.media.MediaController2;
import android.media.Session2CommandGroup;
import android.media.Session2Token;
import android.os.Handler;
-import android.os.HandlerExecutor;
import android.os.Looper;
import android.os.ResultReceiver;
import android.os.UserHandle;
diff --git a/services/core/java/com/android/server/pm/ApexManager.java b/services/core/java/com/android/server/pm/ApexManager.java
index 249b6801758b..07527c2a15d8 100644
--- a/services/core/java/com/android/server/pm/ApexManager.java
+++ b/services/core/java/com/android/server/pm/ApexManager.java
@@ -270,11 +270,12 @@ public abstract class ApexManager {
abstract boolean revertActiveSessions();
/**
- * Abandons the staged session with the given sessionId.
+ * Abandons the staged session with the given sessionId. Client should handle {@code false}
+ * return value carefully as failure here can leave device in inconsistent state.
*
- * @return {@code true} upon success, {@code false} if any remote exception occurs
+ * @return {@code true} upon success, {@code false} if any exception occurs
*/
- abstract boolean abortStagedSession(int sessionId) throws PackageManagerException;
+ abstract boolean abortStagedSession(int sessionId);
/**
* Uninstalls given {@code apexPackage}.
@@ -753,17 +754,13 @@ public abstract class ApexManager {
}
@Override
- boolean abortStagedSession(int sessionId) throws PackageManagerException {
+ boolean abortStagedSession(int sessionId) {
try {
waitForApexService().abortStagedSession(sessionId);
return true;
- } catch (RemoteException re) {
- Slog.e(TAG, "Unable to contact apexservice", re);
- return false;
} catch (Exception e) {
- throw new PackageManagerException(
- PackageInstaller.SessionInfo.STAGED_SESSION_VERIFICATION_FAILED,
- "Failed to abort staged session : " + e.getMessage());
+ Slog.e(TAG, e.getMessage(), e);
+ return false;
}
}
@@ -1122,7 +1119,7 @@ public abstract class ApexManager {
}
@Override
- boolean abortStagedSession(int sessionId) throws PackageManagerException {
+ boolean abortStagedSession(int sessionId) {
throw new UnsupportedOperationException();
}
diff --git a/services/core/java/com/android/server/pm/OWNERS b/services/core/java/com/android/server/pm/OWNERS
index fe6aad70c31e..e48862e2e5e0 100644
--- a/services/core/java/com/android/server/pm/OWNERS
+++ b/services/core/java/com/android/server/pm/OWNERS
@@ -14,16 +14,16 @@ per-file ApexManager.java = dariofreni@google.com, ioffe@google.com, olilan@goog
per-file StagingManager.java = dariofreni@google.com, ioffe@google.com, olilan@google.com
# dex
-per-file AbstractStatsBase.java = agampe@google.com, calin@google.com, ngeoffray@google.com
-per-file BackgroundDexOptService.java = agampe@google.com, calin@google.com, ngeoffray@google.com
-per-file CompilerStats.java = agampe@google.com, calin@google.com, ngeoffray@google.com
-per-file DynamicCodeLoggingService.java = alanstokes@google.com, agampe@google.com, calin@google.com, ngeoffray@google.com
-per-file InstructionSets.java = agampe@google.com, calin@google.com, ngeoffray@google.com
-per-file OtaDexoptService.java = agampe@google.com, calin@google.com, ngeoffray@google.com
-per-file OtaDexoptShellCommand.java = agampe@google.com, calin@google.com, ngeoffray@google.com
-per-file PackageDexOptimizer.java = agampe@google.com, calin@google.com, ngeoffray@google.com
-per-file PackageManagerServiceCompilerMapping.java = agampe@google.com, calin@google.com, ngeoffray@google.com
-per-file PackageUsage.java = agampe@google.com, calin@google.com, ngeoffray@google.com
+per-file AbstractStatsBase.java = calin@google.com, ngeoffray@google.com
+per-file BackgroundDexOptService.java = calin@google.com, ngeoffray@google.com
+per-file CompilerStats.java = calin@google.com, ngeoffray@google.com
+per-file DynamicCodeLoggingService.java = alanstokes@google.com, calin@google.com, ngeoffray@google.com
+per-file InstructionSets.java = calin@google.com, ngeoffray@google.com
+per-file OtaDexoptService.java = calin@google.com, ngeoffray@google.com
+per-file OtaDexoptShellCommand.java = calin@google.com, ngeoffray@google.com
+per-file PackageDexOptimizer.java = calin@google.com, ngeoffray@google.com
+per-file PackageManagerServiceCompilerMapping.java = calin@google.com, ngeoffray@google.com
+per-file PackageUsage.java = calin@google.com, ngeoffray@google.com
# multi user / cross profile
per-file CrossProfileAppsServiceImpl.java = omakoto@google.com, yamasani@google.com
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 312dcddd577d..55e7ca8ca838 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -1284,10 +1284,16 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
int N = mSessions.size();
for (int i = 0; i < N; i++) {
final PackageInstallerSession session = mSessions.valueAt(i);
- if (session.isStagedAndInTerminalState()) {
+
+ // Do not print finalized staged session as active install sessions
+ final PackageInstallerSession rootSession = session.hasParentSessionId()
+ ? getSession(session.getParentSessionId())
+ : session;
+ if (rootSession.isStagedAndInTerminalState()) {
finalizedSessions.add(session);
continue;
}
+
session.dump(pw);
pw.println();
}
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 7765f18300fe..05026a0cafb6 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -169,7 +169,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
private static final int MSG_STREAM_VALIDATE_AND_COMMIT = 2;
private static final int MSG_INSTALL = 3;
private static final int MSG_ON_PACKAGE_INSTALLED = 4;
- private static final int MSG_SESSION_VERIFICATION_FAILURE = 5;
+ private static final int MSG_SESSION_VALIDATION_FAILURE = 5;
/** XML constants used for persisting a session */
static final String TAG_SESSION = "session";
@@ -475,10 +475,10 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
packageName, returnCode, message, extras);
break;
- case MSG_SESSION_VERIFICATION_FAILURE:
+ case MSG_SESSION_VALIDATION_FAILURE:
final int error = msg.arg1;
final String detailMessage = (String) msg.obj;
- onSessionVerificationFailure(error, detailMessage);
+ onSessionValidationFailure(error, detailMessage);
break;
}
@@ -1246,14 +1246,14 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
// the parent
if (unrecoverableFailure != null) {
// {@link #streamValidateAndCommit()} calls
- // {@link #onSessionVerificationFailure(PackageManagerException)}, but we don't
+ // {@link #onSessionValidationFailure(PackageManagerException)}, but we don't
// expect it to ever do so for parent sessions. Call that on this parent to clean
// it up and notify listeners of the error.
- onSessionVerificationFailure(unrecoverableFailure);
+ onSessionValidationFailure(unrecoverableFailure);
// fail other child sessions that did not already fail
for (int i = nonFailingSessions.size() - 1; i >= 0; --i) {
PackageInstallerSession session = nonFailingSessions.get(i);
- session.onSessionVerificationFailure(unrecoverableFailure);
+ session.onSessionValidationFailure(unrecoverableFailure);
}
}
}
@@ -1575,11 +1575,11 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
assertMultiPackageConsistencyLocked(childSessions);
}
} catch (PackageManagerException e) {
- throw onSessionVerificationFailure(e);
+ throw onSessionValidationFailure(e);
} catch (Throwable e) {
// Convert all exceptions into package manager exceptions as only those are handled
// in the code above.
- throw onSessionVerificationFailure(new PackageManagerException(e));
+ throw onSessionValidationFailure(new PackageManagerException(e));
}
}
@@ -1613,20 +1613,20 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
}
return true;
} catch (PackageManagerException e) {
- throw onSessionVerificationFailure(e);
+ throw onSessionValidationFailure(e);
} catch (Throwable e) {
// Convert all exceptions into package manager exceptions as only those are handled
// in the code above.
- throw onSessionVerificationFailure(new PackageManagerException(e));
+ throw onSessionValidationFailure(new PackageManagerException(e));
}
}
- private PackageManagerException onSessionVerificationFailure(PackageManagerException e) {
- onSessionVerificationFailure(e.error, ExceptionUtils.getCompleteMessage(e));
+ private PackageManagerException onSessionValidationFailure(PackageManagerException e) {
+ onSessionValidationFailure(e.error, ExceptionUtils.getCompleteMessage(e));
return e;
}
- private void onSessionVerificationFailure(int error, String detailMessage) {
+ private void onSessionValidationFailure(int error, String detailMessage) {
// Session is sealed but could not be verified, we need to destroy it.
destroyInternal();
// Dispatch message to remove session from PackageInstallerService.
@@ -2091,7 +2091,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
if (ps == null) {
return 0;
}
- final File apkDirOrPath = ps.codePath;
+ final File apkDirOrPath = ps.getCodePath();
if (apkDirOrPath == null) {
return 0;
}
@@ -2990,7 +2990,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
synchronized (mLock) {
mDataLoaderFinished = true;
}
- dispatchSessionVerificationFailure(INSTALL_FAILED_MEDIA_UNAVAILABLE,
+ dispatchSessionValidationFailure(INSTALL_FAILED_MEDIA_UNAVAILABLE,
"Failure to obtain data loader");
return;
}
@@ -3040,7 +3040,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
synchronized (mLock) {
mDataLoaderFinished = true;
}
- dispatchSessionVerificationFailure(INSTALL_FAILED_MEDIA_UNAVAILABLE,
+ dispatchSessionValidationFailure(INSTALL_FAILED_MEDIA_UNAVAILABLE,
"Failed to prepare image.");
if (manualStartAndDestroy) {
dataLoader.destroy(dataLoaderId);
@@ -3061,7 +3061,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
synchronized (mLock) {
mDataLoaderFinished = true;
}
- dispatchSessionVerificationFailure(INSTALL_FAILED_MEDIA_UNAVAILABLE,
+ dispatchSessionValidationFailure(INSTALL_FAILED_MEDIA_UNAVAILABLE,
"DataLoader reported unrecoverable failure.");
break;
}
@@ -3117,7 +3117,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
synchronized (mLock) {
mDataLoaderFinished = true;
}
- dispatchSessionVerificationFailure(INSTALL_FAILED_MEDIA_UNAVAILABLE,
+ dispatchSessionValidationFailure(INSTALL_FAILED_MEDIA_UNAVAILABLE,
"Image is missing pages required for installation.");
break;
}
@@ -3142,8 +3142,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
return false;
}
- private void dispatchSessionVerificationFailure(int error, String detailMessage) {
- mHandler.obtainMessage(MSG_SESSION_VERIFICATION_FAILURE, error, -1,
+ private void dispatchSessionValidationFailure(int error, String detailMessage) {
+ mHandler.obtainMessage(MSG_SESSION_VALIDATION_FAILURE, error, -1,
detailMessage).sendToTarget();
}
@@ -3321,7 +3321,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
/** {@hide} */
void setStagedSessionReady() {
synchronized (mLock) {
- if (mDestroyed) return; // Do not allow destroyed staged session to change state
+ // Do not allow destroyed/failed staged session to change state
+ if (mDestroyed || mStagedSessionFailed) return;
mStagedSessionReady = true;
mStagedSessionApplied = false;
mStagedSessionFailed = false;
@@ -3332,10 +3333,10 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
}
/** {@hide} */
- void setStagedSessionFailed(@StagedSessionErrorCode int errorCode,
- String errorMessage) {
+ void setStagedSessionFailed(@StagedSessionErrorCode int errorCode, String errorMessage) {
synchronized (mLock) {
- if (mDestroyed) return; // Do not allow destroyed staged session to change state
+ // Do not allow destroyed/failed staged session to change state
+ if (mDestroyed || mStagedSessionFailed) return;
mStagedSessionReady = false;
mStagedSessionApplied = false;
mStagedSessionFailed = true;
@@ -3350,7 +3351,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
/** {@hide} */
void setStagedSessionApplied() {
synchronized (mLock) {
- if (mDestroyed) return; // Do not allow destroyed staged session to change state
+ // Do not allow destroyed/failed staged session to change state
+ if (mDestroyed || mStagedSessionFailed) return;
mStagedSessionReady = false;
mStagedSessionApplied = true;
mStagedSessionFailed = false;
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index a726c8d26b98..58a1648e51ad 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -3010,7 +3010,7 @@ public class PackageManagerService extends IPackageManager.Stub
final int packageSettingCount = mSettings.mPackages.size();
for (int i = packageSettingCount - 1; i >= 0; i--) {
PackageSetting ps = mSettings.mPackages.valueAt(i);
- if (!isExternal(ps) && (ps.codePath == null || !ps.codePath.exists())
+ if (!isExternal(ps) && (ps.getCodePath() == null || !ps.getCodePath().exists())
&& mSettings.getDisabledSystemPkgLPr(ps.name) != null) {
mSettings.mPackages.removeAt(i);
mSettings.enableSystemPackageLPw(ps.name);
@@ -3175,11 +3175,11 @@ public class PackageManagerService extends IPackageManager.Stub
logCriticalInfo(Log.WARN,
"Expecting better updated system app for " + ps.name
+ "; removing system app. Last known"
- + " codePath=" + ps.codePathString
+ + " codePath=" + ps.getCodePathString()
+ ", versionCode=" + ps.versionCode
+ "; scanned versionCode=" + scannedPkg.getLongVersionCode());
removePackageLI(scannedPkg, true);
- mExpectingBetter.put(ps.name, ps.codePath);
+ mExpectingBetter.put(ps.name, ps.getCodePath());
}
continue;
@@ -3202,14 +3202,14 @@ public class PackageManagerService extends IPackageManager.Stub
// code path, but, changes the package name.
final PackageSetting disabledPs =
mSettings.getDisabledSystemPkgLPr(ps.name);
- if (disabledPs.codePath == null || !disabledPs.codePath.exists()
+ if (disabledPs.getCodePath() == null || !disabledPs.getCodePath().exists()
|| disabledPs.pkg == null) {
possiblyDeletedUpdatedSystemApps.add(ps.name);
} else {
// We're expecting that the system app should remain disabled, but add
// it to expecting better to recover in case the data version cannot
// be scanned.
- mExpectingBetter.put(disabledPs.name, disabledPs.codePath);
+ mExpectingBetter.put(disabledPs.name, disabledPs.getCodePath());
}
}
}
@@ -8551,6 +8551,15 @@ public class PackageManagerService extends IPackageManager.Stub
if (listUninstalled) {
list = new ArrayList<>(mSettings.mPackages.size());
for (PackageSetting ps : mSettings.mPackages.values()) {
+ if (listFactory) {
+ if (!ps.isSystem()) {
+ continue;
+ }
+ PackageSetting psDisabled = mSettings.getDisabledSystemPkgLPr(ps);
+ if (psDisabled != null) {
+ ps = psDisabled;
+ }
+ }
if (filterSharedLibPackageLPr(ps, callingUid, userId, flags)) {
continue;
}
@@ -8565,7 +8574,16 @@ public class PackageManagerService extends IPackageManager.Stub
} else {
list = new ArrayList<>(mPackages.size());
for (AndroidPackage p : mPackages.values()) {
- final PackageSetting ps = getPackageSetting(p.getPackageName());
+ PackageSetting ps = getPackageSetting(p.getPackageName());
+ if (listFactory) {
+ if (!p.isSystem()) {
+ continue;
+ }
+ PackageSetting psDisabled = mSettings.getDisabledSystemPkgLPr(ps);
+ if (psDisabled != null) {
+ ps = psDisabled;
+ }
+ }
if (filterSharedLibPackageLPr(ps, callingUid, userId, flags)) {
continue;
}
@@ -9150,7 +9168,7 @@ public class PackageManagerService extends IPackageManager.Stub
: getLastModifiedTime(parsedPackage);
final VersionInfo settingsVersionForPackage = getSettingsVersionForPackage(parsedPackage);
if (ps != null && !forceCollect
- && ps.codePathString.equals(parsedPackage.getCodePath())
+ && ps.getCodePathString().equals(parsedPackage.getCodePath())
&& ps.timeStamp == lastModifiedTime
&& !isCompatSignatureUpdateNeeded(settingsVersionForPackage)
&& !isRecoverSignatureUpdateNeeded(settingsVersionForPackage)) {
@@ -9383,8 +9401,8 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
- final boolean newPkgChangedPaths =
- pkgAlreadyExists && !pkgSetting.codePathString.equals(parsedPackage.getCodePath());
+ final boolean newPkgChangedPaths = pkgAlreadyExists
+ && !pkgSetting.getCodePathString().equals(parsedPackage.getCodePath());
final boolean newPkgVersionGreater =
pkgAlreadyExists && parsedPackage.getLongVersionCode() > pkgSetting.versionCode;
final boolean isSystemPkgBetter = scanSystemPartition && isSystemPkgUpdated
@@ -9403,11 +9421,11 @@ public class PackageManagerService extends IPackageManager.Stub
"System package updated;"
+ " name: " + pkgSetting.name
+ "; " + pkgSetting.versionCode + " --> " + parsedPackage.getLongVersionCode()
- + "; " + pkgSetting.codePathString + " --> " + parsedPackage.getCodePath());
+ + "; " + pkgSetting.getCodePathString()
+ + " --> " + parsedPackage.getCodePath());
final InstallArgs args = createInstallArgsForExisting(
- pkgSetting.codePathString,
- pkgSetting.resourcePathString, getAppDexInstructionSets(
+ pkgSetting.getCodePathString(), getAppDexInstructionSets(
pkgSetting.primaryCpuAbiString, pkgSetting.secondaryCpuAbiString));
args.cleanUpResourcesLI();
synchronized (mLock) {
@@ -9482,11 +9500,10 @@ public class PackageManagerService extends IPackageManager.Stub
+ " name: " + pkgSetting.name
+ "; " + pkgSetting.versionCode + " --> "
+ parsedPackage.getLongVersionCode()
- + "; " + pkgSetting.codePathString + " --> "
+ + "; " + pkgSetting.getCodePathString() + " --> "
+ parsedPackage.getCodePath());
InstallArgs args = createInstallArgsForExisting(
- pkgSetting.codePathString,
- pkgSetting.resourcePathString, getAppDexInstructionSets(
+ pkgSetting.getCodePathString(), getAppDexInstructionSets(
pkgSetting.primaryCpuAbiString, pkgSetting.secondaryCpuAbiString));
synchronized (mInstallLock) {
args.cleanUpResourcesLI();
@@ -9499,7 +9516,7 @@ public class PackageManagerService extends IPackageManager.Stub
logCriticalInfo(Log.INFO,
"System package disabled;"
+ " name: " + pkgSetting.name
- + "; old: " + pkgSetting.codePathString + " @ "
+ + "; old: " + pkgSetting.getCodePathString() + " @ "
+ pkgSetting.versionCode
+ "; new: " + parsedPackage.getCodePath() + " @ "
+ parsedPackage.getCodePath());
@@ -11325,7 +11342,7 @@ public class PackageManagerService extends IPackageManager.Stub
if (changedAbiCodePath == null) {
changedAbiCodePath = new ArrayList<>();
}
- changedAbiCodePath.add(ps.codePathString);
+ changedAbiCodePath.add(ps.getCodePathString());
}
}
}
@@ -11421,7 +11438,6 @@ public class PackageManagerService extends IPackageManager.Stub
// Initialize package source and resource directories
final File destCodeFile = new File(parsedPackage.getCodePath());
- final File destResourceFile = new File(parsedPackage.getCodePath());
// We keep references to the derived CPU Abis from settings in oder to reuse
// them in the case where we're not upgrading or booting for the first time.
@@ -11479,7 +11495,7 @@ public class PackageManagerService extends IPackageManager.Stub
// REMOVE SharedUserSetting from method; update in a separate call
pkgSetting = Settings.createNewSetting(parsedPackage.getPackageName(),
originalPkgSetting, disabledPkgSetting, realPkgName, sharedUserSetting,
- destCodeFile, destResourceFile, parsedPackage.getNativeLibraryRootDir(),
+ destCodeFile, parsedPackage.getNativeLibraryRootDir(),
AndroidPackageUtils.getRawPrimaryCpuAbi(parsedPackage),
AndroidPackageUtils.getRawSecondaryCpuAbi(parsedPackage),
parsedPackage.getVersionCode(), pkgFlags, pkgPrivateFlags, user,
@@ -11497,7 +11513,7 @@ public class PackageManagerService extends IPackageManager.Stub
// secondaryCpuAbi are not known at this point so we always update them
// to null here, only to reset them at a later point.
Settings.updatePackageSetting(pkgSetting, disabledPkgSetting, sharedUserSetting,
- destCodeFile, destResourceFile, parsedPackage.getNativeLibraryDir(),
+ destCodeFile, parsedPackage.getNativeLibraryDir(),
AndroidPackageUtils.getPrimaryCpuAbi(parsedPackage, pkgSetting),
AndroidPackageUtils.getSecondaryCpuAbi(parsedPackage, pkgSetting),
PackageInfoUtils.appInfoFlags(parsedPackage, pkgSetting),
@@ -12066,15 +12082,13 @@ public class PackageManagerService extends IPackageManager.Stub
if (known != null) {
if (DEBUG_PACKAGE_SCANNING) {
Log.d(TAG, "Examining " + pkg.getCodePath()
- + " and requiring known paths " + known.codePathString
- + " & " + known.resourcePathString);
+ + " and requiring known path " + known.getCodePathString());
}
- if (!pkg.getCodePath().equals(known.codePathString)
- || !pkg.getCodePath().equals(known.resourcePathString)) {
+ if (!pkg.getCodePath().equals(known.getCodePathString())) {
throw new PackageManagerException(INSTALL_FAILED_PACKAGE_CHANGED,
"Application package " + pkg.getPackageName()
+ " found at " + pkg.getCodePath()
- + " but expected at " + known.codePathString
+ + " but expected at " + known.getCodePathString()
+ "; ignoring.");
}
} else {
@@ -15586,9 +15600,8 @@ public class PackageManagerService extends IPackageManager.Stub
* Create args that describe an existing installed package. Typically used
* when cleaning up old installs, or used as a move source.
*/
- private InstallArgs createInstallArgsForExisting(String codePath,
- String resourcePath, String[] instructionSets) {
- return new FileInstallArgs(codePath, resourcePath, instructionSets);
+ private InstallArgs createInstallArgsForExisting(String codePath, String[] instructionSets) {
+ return new FileInstallArgs(codePath, instructionSets);
}
static abstract class InstallArgs {
@@ -15669,10 +15682,8 @@ public class PackageManagerService extends IPackageManager.Stub
abstract boolean doRename(int status, ParsedPackage parsedPackage);
abstract int doPostInstall(int status, int uid);
- /** @see PackageSettingBase#codePathString */
+ /** @see PackageSettingBase#getCodePath() */
abstract String getCodePath();
- /** @see PackageSettingBase#resourcePathString */
- abstract String getResourcePath();
// Need installer lock especially for dex file removal.
abstract void cleanUpResourcesLI();
@@ -15743,14 +15754,13 @@ public class PackageManagerService extends IPackageManager.Stub
}
/** Existing install */
- FileInstallArgs(String codePath, String resourcePath, String[] instructionSets) {
+ FileInstallArgs(String codePath, String[] instructionSets) {
super(OriginInfo.fromNothing(), null, null, 0, InstallSource.EMPTY,
null, null, instructionSets, null, null, null, MODE_DEFAULT, null, 0,
PackageParser.SigningDetails.UNKNOWN,
PackageManager.INSTALL_REASON_UNKNOWN, false,
DataLoaderType.NONE);
this.codeFile = (codePath != null) ? new File(codePath) : null;
- this.resourceFile = (resourcePath != null) ? new File(resourcePath) : null;
}
int copyApk() {
@@ -15766,7 +15776,6 @@ public class PackageManagerService extends IPackageManager.Stub
if (origin.staged) {
if (DEBUG_INSTALL) Slog.d(TAG, origin.file + " already staged; skipping copy");
codeFile = origin.file;
- resourceFile = origin.file;
return PackageManager.INSTALL_SUCCEEDED;
}
@@ -15775,7 +15784,6 @@ public class PackageManagerService extends IPackageManager.Stub
final File tempDir =
mInstallerService.allocateStageDirLegacy(volumeUuid, isEphemeral);
codeFile = tempDir;
- resourceFile = tempDir;
} catch (IOException e) {
Slog.w(TAG, "Failed to create copy file: " + e);
return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
@@ -15846,7 +15854,6 @@ public class PackageManagerService extends IPackageManager.Stub
// Reflect the rename internally
codeFile = afterCodeFile;
- resourceFile = afterCodeFile;
// Reflect the rename in scanned details
try {
@@ -15875,11 +15882,6 @@ public class PackageManagerService extends IPackageManager.Stub
return (codeFile != null) ? codeFile.getAbsolutePath() : null;
}
- @Override
- String getResourcePath() {
- return (resourceFile != null) ? resourceFile.getAbsolutePath() : null;
- }
-
private boolean cleanUp() {
if (codeFile == null || !codeFile.exists()) {
return false;
@@ -15892,10 +15894,6 @@ public class PackageManagerService extends IPackageManager.Stub
removeCodePathLI(codeFile);
- if (resourceFile != null && !FileUtils.contains(codeFile, resourceFile)) {
- resourceFile.delete();
- }
-
return true;
}
@@ -15927,7 +15925,6 @@ public class PackageManagerService extends IPackageManager.Stub
*/
class MoveInstallArgs extends InstallArgs {
private File codeFile;
- private File resourceFile;
/** New install */
MoveInstallArgs(InstallParams params) {
@@ -15950,7 +15947,6 @@ public class PackageManagerService extends IPackageManager.Stub
final String toPathName = new File(move.fromCodePath).getName();
codeFile = new File(Environment.getDataAppDirectory(move.toUuid), toPathName);
- resourceFile = codeFile;
if (DEBUG_INSTALL) Slog.d(TAG, "codeFile after move is " + codeFile);
return PackageManager.INSTALL_SUCCEEDED;
@@ -15987,11 +15983,6 @@ public class PackageManagerService extends IPackageManager.Stub
return (codeFile != null) ? codeFile.getAbsolutePath() : null;
}
- @Override
- String getResourcePath() {
- return (resourceFile != null) ? resourceFile.getAbsolutePath() : null;
- }
-
private boolean cleanUp(String volumeUuid) {
final String toPathName = new File(move.fromCodePath).getName();
final File codeFile = new File(Environment.getDataAppDirectory(volumeUuid),
@@ -16777,7 +16768,6 @@ public class PackageManagerService extends IPackageManager.Stub
// installed. We need to make sure to delete the older one's .apk.
res.removedInfo.args = createInstallArgsForExisting(
oldPackage.getCodePath(),
- oldPackage.getCodePath(),
getAppDexInstructionSets(
AndroidPackageUtils.getPrimaryCpuAbi(oldPackage,
deletedPkgSetting),
@@ -18558,7 +18548,6 @@ public class PackageManagerService extends IPackageManager.Stub
// user handle installed state
int[] allUsers;
/** enabled state of the uninstalled application */
- final int origEnabledState;
synchronized (mLock) {
uninstalledPs = mSettings.mPackages.get(packageName);
if (uninstalledPs == null) {
@@ -18574,10 +18563,6 @@ public class PackageManagerService extends IPackageManager.Stub
}
disabledSystemPs = mSettings.getDisabledSystemPkgLPr(packageName);
- // Save the enabled state before we delete the package. When deleting a stub
- // application we always set the enabled state to 'disabled'.
- origEnabledState = uninstalledPs == null
- ? COMPONENT_ENABLED_STATE_DEFAULT : uninstalledPs.getEnabled(userId);
// Static shared libs can be declared by any package, so let us not
// allow removing a package if it provides a lib others depend on.
pkg = mPackages.get(packageName);
@@ -18656,20 +18641,32 @@ public class PackageManagerService extends IPackageManager.Stub
if (stubPkg != null && stubPkg.isStub()) {
final PackageSetting stubPs;
synchronized (mLock) {
- // restore the enabled state of the stub; the state is overwritten when
- // the stub is uninstalled
stubPs = mSettings.getPackageLPr(stubPkg.getPackageName());
- if (stubPs != null) {
- stubPs.setEnabled(origEnabledState, userId, "android");
- }
}
- if (origEnabledState == COMPONENT_ENABLED_STATE_DEFAULT
- || origEnabledState == COMPONENT_ENABLED_STATE_ENABLED) {
- if (DEBUG_COMPRESSION) {
- Slog.i(TAG, "Enabling system stub after removal; pkg: "
- + stubPkg.getPackageName());
+
+ if (stubPs != null) {
+ boolean enable = false;
+ for (int aUserId : allUsers) {
+ if (stubPs.getInstalled(aUserId)) {
+ int enabled = stubPs.getEnabled(aUserId);
+ if (enabled == COMPONENT_ENABLED_STATE_DEFAULT
+ || enabled == COMPONENT_ENABLED_STATE_ENABLED) {
+ enable = true;
+ break;
+ }
+ }
+ }
+
+ if (enable) {
+ if (DEBUG_COMPRESSION) {
+ Slog.i(TAG, "Enabling system stub after removal; pkg: "
+ + stubPkg.getPackageName());
+ }
+ enableCompressedPackage(stubPkg, stubPs);
+ } else if (DEBUG_COMPRESSION) {
+ Slog.i(TAG, "System stub disabled for all users, leaving uncompressed "
+ + "after removal; pkg: " + stubPkg.getPackageName());
}
- enableCompressedPackage(stubPkg, stubPs);
}
}
}
@@ -18998,7 +18995,7 @@ public class PackageManagerService extends IPackageManager.Stub
// Install the system package
if (DEBUG_REMOVE) Slog.d(TAG, "Re-installing system package: " + disabledPs);
try {
- installPackageFromSystemLIF(disabledPs.codePathString, allUserHandles,
+ installPackageFromSystemLIF(disabledPs.getCodePathString(), allUserHandles,
outInfo == null ? null : outInfo.origUsers, deletedPs.getPermissionsState(),
writeSettings);
} catch (PackageManagerException e) {
@@ -19013,8 +19010,15 @@ public class PackageManagerService extends IPackageManager.Stub
// and re-enable it afterward.
final PackageSetting stubPs = mSettings.mPackages.get(deletedPkg.getPackageName());
if (stubPs != null) {
- stubPs.setEnabled(
- COMPONENT_ENABLED_STATE_DISABLED, UserHandle.USER_SYSTEM, "android");
+ int userId = action.user == null
+ ? UserHandle.USER_ALL : action.user.getIdentifier();
+ if (userId == UserHandle.USER_ALL) {
+ for (int aUserId : allUserHandles) {
+ stubPs.setEnabled(COMPONENT_ENABLED_STATE_DISABLED, aUserId, "android");
+ }
+ } else if (userId >= UserHandle.USER_SYSTEM) {
+ stubPs.setEnabled(COMPONENT_ENABLED_STATE_DISABLED, userId, "android");
+ }
}
}
}
@@ -19123,7 +19127,7 @@ public class PackageManagerService extends IPackageManager.Stub
// Delete application code and resources only for parent packages
if (deleteCodeAndResources && (outInfo != null)) {
outInfo.args = createInstallArgsForExisting(
- ps.codePathString, ps.resourcePathString, getAppDexInstructionSets(
+ ps.getCodePathString(), getAppDexInstructionSets(
ps.primaryCpuAbiString, ps.secondaryCpuAbiString));
if (DEBUG_SD_INSTALL) Slog.i(TAG, "args=" + outInfo.args);
}
@@ -19660,7 +19664,7 @@ public class PackageManagerService extends IPackageManager.Stub
final String[] packageNames = { packageName };
final long[] ceDataInodes = { ps.getCeDataInode(userId) };
- final String[] codePaths = { ps.codePathString };
+ final String[] codePaths = { ps.getCodePathString() };
try {
mInstaller.getAppSize(ps.volumeUuid, packageNames, userId, 0,
@@ -22582,11 +22586,11 @@ public class PackageManagerService extends IPackageManager.Stub
synchronized (mInstallLock) {
final AndroidPackage pkg;
try {
- pkg = scanPackageTracedLI(ps.codePath, parseFlags, SCAN_INITIAL, 0, null);
+ pkg = scanPackageTracedLI(ps.getCodePath(), parseFlags, SCAN_INITIAL, 0, null);
loaded.add(pkg);
} catch (PackageManagerException e) {
- Slog.w(TAG, "Failed to scan " + ps.codePath + ": " + e.getMessage());
+ Slog.w(TAG, "Failed to scan " + ps.getCodePath() + ": " + e.getMessage());
}
if (!Build.FINGERPRINT.equals(ver.fingerprint)) {
@@ -22657,33 +22661,33 @@ public class PackageManagerService extends IPackageManager.Stub
final ArrayList<AndroidPackage> unloaded = new ArrayList<>();
synchronized (mInstallLock) {
- synchronized (mLock) {
- final List<PackageSetting> packages = mSettings.getVolumePackagesLPr(volumeUuid);
- for (PackageSetting ps : packages) {
- if (ps.pkg == null) continue;
-
- final AndroidPackage pkg = ps.pkg;
- final int deleteFlags = PackageManager.DELETE_KEEP_DATA;
- final PackageRemovedInfo outInfo = new PackageRemovedInfo(this);
-
- try (PackageFreezer freezer = freezePackageForDelete(ps.name, deleteFlags,
- "unloadPrivatePackagesInner")) {
- if (deletePackageLIF(ps.name, null, false, null, deleteFlags, outInfo,
- false, null)) {
- unloaded.add(pkg);
- } else {
- Slog.w(TAG, "Failed to unload " + ps.codePath);
+ synchronized (mLock) {
+ final List<PackageSetting> packages = mSettings.getVolumePackagesLPr(volumeUuid);
+ for (PackageSetting ps : packages) {
+ if (ps.pkg == null) continue;
+
+ final AndroidPackage pkg = ps.pkg;
+ final int deleteFlags = PackageManager.DELETE_KEEP_DATA;
+ final PackageRemovedInfo outInfo = new PackageRemovedInfo(this);
+
+ try (PackageFreezer freezer = freezePackageForDelete(ps.name, deleteFlags,
+ "unloadPrivatePackagesInner")) {
+ if (deletePackageLIF(ps.name, null, false, null, deleteFlags, outInfo,
+ false, null)) {
+ unloaded.add(pkg);
+ } else {
+ Slog.w(TAG, "Failed to unload " + ps.getCodePath());
+ }
}
+
+ // Try very hard to release any references to this package
+ // so we don't risk the system server being killed due to
+ // open FDs
+ AttributeCache.instance().removePackage(ps.name);
}
- // Try very hard to release any references to this package
- // so we don't risk the system server being killed due to
- // open FDs
- AttributeCache.instance().removePackage(ps.name);
+ mSettings.writeLPr();
}
-
- mSettings.writeLPr();
- }
}
if (DEBUG_INSTALL) Slog.d(TAG, "Unloaded packages " + unloaded);
@@ -22726,7 +22730,7 @@ public class PackageManagerService extends IPackageManager.Stub
final int packageCount = mSettings.mPackages.size();
for (int i = 0; i < packageCount; i++) {
final PackageSetting ps = mSettings.mPackages.valueAt(i);
- codePaths.add(ps.codePath.getAbsolutePath());
+ codePaths.add(ps.getCodePath().getAbsolutePath());
}
return codePaths;
}
@@ -23643,8 +23647,20 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
- void onNewUserCreated(final int userId) {
- mPermissionManager.onNewUserCreated(userId);
+ void onNewUserCreated(@UserIdInt int userId, boolean convertedFromPreCreated) {
+ if (DEBUG_PERMISSIONS) {
+ Slog.d(TAG, "onNewUserCreated(id=" + userId
+ + ", convertedFromPreCreated=" + convertedFromPreCreated + ")");
+ }
+ if (!convertedFromPreCreated) {
+ mPermissionManager.onNewUserCreated(userId);
+ return;
+ }
+ if (!readPermissionStateForUser(userId)) {
+ // Could not read the existing permissions, re-grant them.
+ Slog.i(TAG, "re-granting permissions for pre-created user " + userId);
+ mPermissionManager.onNewUserCreated(userId);
+ }
}
boolean readPermissionStateForUser(@UserIdInt int userId) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 668f375e2e9b..7aeec6d68d26 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -423,13 +423,15 @@ class PackageManagerShellCommand extends ShellCommand {
final List<ApplicationInfo> list;
if (packageName == null) {
final ParceledListSlice<ApplicationInfo> packages =
- mInterface.getInstalledApplications(
- PackageManager.MATCH_SYSTEM_ONLY, UserHandle.USER_SYSTEM);
+ mInterface.getInstalledApplications(PackageManager.MATCH_SYSTEM_ONLY
+ | PackageManager.MATCH_UNINSTALLED_PACKAGES,
+ UserHandle.USER_SYSTEM);
list = packages.getList();
} else {
list = new ArrayList<>(1);
- list.add(mInterface.getApplicationInfo(packageName,
- PackageManager.MATCH_SYSTEM_ONLY, UserHandle.USER_SYSTEM));
+ list.add(mInterface.getApplicationInfo(packageName, PackageManager.MATCH_SYSTEM_ONLY
+ | PackageManager.MATCH_UNINSTALLED_PACKAGES,
+ UserHandle.USER_SYSTEM));
}
for (ApplicationInfo info : list) {
if (info.isUpdatedSystemApp()) {
diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java
index 432d7f335ebc..a3a727367c56 100644
--- a/services/core/java/com/android/server/pm/PackageSetting.java
+++ b/services/core/java/com/android/server/pm/PackageSetting.java
@@ -71,13 +71,13 @@ public class PackageSetting extends PackageSettingBase {
private PackageStateUnserialized pkgState = new PackageStateUnserialized();
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
- public PackageSetting(String name, String realName, File codePath, File resourcePath,
+ public PackageSetting(String name, String realName, @NonNull File codePath,
String legacyNativeLibraryPathString, String primaryCpuAbiString,
String secondaryCpuAbiString, String cpuAbiOverrideString,
long pVersionCode, int pkgFlags, int privateFlags,
int sharedUserId, String[] usesStaticLibraries,
long[] usesStaticLibrariesVersions, Map<String, ArraySet<String>> mimeGroups) {
- super(name, realName, codePath, resourcePath, legacyNativeLibraryPathString,
+ super(name, realName, codePath, legacyNativeLibraryPathString,
primaryCpuAbiString, secondaryCpuAbiString, cpuAbiOverrideString,
pVersionCode, pkgFlags, privateFlags,
usesStaticLibraries, usesStaticLibrariesVersions);
diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java
index 834303cc14c6..6010344b8c65 100644
--- a/services/core/java/com/android/server/pm/PackageSettingBase.java
+++ b/services/core/java/com/android/server/pm/PackageSettingBase.java
@@ -64,10 +64,8 @@ public abstract class PackageSettingBase extends SettingBase {
* this is path to single base APK file; for cluster packages this is
* path to the cluster directory.
*/
- File codePath;
- String codePathString;
- File resourcePath;
- String resourcePathString;
+ private File mCodePath;
+ private String mCodePathString;
String[] usesStaticLibraries;
long[] usesStaticLibrariesVersions;
@@ -138,7 +136,7 @@ public abstract class PackageSettingBase extends SettingBase {
boolean forceQueryableOverride;
- PackageSettingBase(String name, String realName, File codePath, File resourcePath,
+ PackageSettingBase(String name, String realName, @NonNull File codePath,
String legacyNativeLibraryPathString, String primaryCpuAbiString,
String secondaryCpuAbiString, String cpuAbiOverrideString,
long pVersionCode, int pkgFlags, int pkgPrivateFlags,
@@ -148,10 +146,7 @@ public abstract class PackageSettingBase extends SettingBase {
this.realName = realName;
this.usesStaticLibraries = usesStaticLibraries;
this.usesStaticLibrariesVersions = usesStaticLibrariesVersions;
- this.codePath = codePath;
- this.codePathString = codePath.toString();
- this.resourcePath = resourcePath;
- this.resourcePathString = resourcePath.toString();
+ setCodePath(codePath);
this.legacyNativeLibraryPathString = legacyNativeLibraryPathString;
this.primaryCpuAbiString = primaryCpuAbiString;
this.secondaryCpuAbiString = secondaryCpuAbiString;
@@ -235,8 +230,7 @@ public abstract class PackageSettingBase extends SettingBase {
}
private void doCopy(PackageSettingBase orig) {
- codePath = orig.codePath;
- codePathString = orig.codePathString;
+ setCodePath(orig.getCodePath());
cpuAbiOverrideString = orig.cpuAbiOverrideString;
firstInstallTime = orig.firstInstallTime;
installPermissionsFixed = orig.installPermissionsFixed;
@@ -246,8 +240,6 @@ public abstract class PackageSettingBase extends SettingBase {
legacyNativeLibraryPathString = orig.legacyNativeLibraryPathString;
// Intentionally skip mOldCodePaths; it's not relevant for copies
primaryCpuAbiString = orig.primaryCpuAbiString;
- resourcePath = orig.resourcePath;
- resourcePathString = orig.resourcePathString;
secondaryCpuAbiString = orig.secondaryCpuAbiString;
signatures = orig.signatures;
timeStamp = orig.timeStamp;
@@ -705,6 +697,20 @@ public abstract class PackageSettingBase extends SettingBase {
return userState.harmfulAppWarning;
}
+ PackageSettingBase setCodePath(@NonNull File codePath) {
+ this.mCodePath = codePath;
+ this.mCodePathString = codePath.toString();
+ return this;
+ }
+
+ File getCodePath() {
+ return mCodePath;
+ }
+
+ String getCodePathString() {
+ return mCodePathString;
+ }
+
/**
* @see PackageUserState#overrideLabelAndIcon(ComponentName, String, Integer)
*
@@ -727,10 +733,7 @@ public abstract class PackageSettingBase extends SettingBase {
protected PackageSettingBase updateFrom(PackageSettingBase other) {
super.copyFrom(other);
- this.codePath = other.codePath;
- this.codePathString = other.codePathString;
- this.resourcePath = other.resourcePath;
- this.resourcePathString = other.resourcePathString;
+ setCodePath(other.getCodePath());
this.usesStaticLibraries = other.usesStaticLibraries;
this.usesStaticLibrariesVersions = other.usesStaticLibrariesVersions;
this.legacyNativeLibraryPathString = other.legacyNativeLibraryPathString;
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 1805713387ae..3e3e3c590491 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -538,7 +538,7 @@ public final class Settings {
return null;
}
p.getPkgState().setUpdatedSystemApp(false);
- PackageSetting ret = addPackageLPw(name, p.realName, p.codePath, p.resourcePath,
+ PackageSetting ret = addPackageLPw(name, p.realName, p.getCodePath(),
p.legacyNativeLibraryPathString, p.primaryCpuAbiString,
p.secondaryCpuAbiString, p.cpuAbiOverrideString,
p.appId, p.versionCode, p.pkgFlags, p.pkgPrivateFlags,
@@ -558,7 +558,7 @@ public final class Settings {
mDisabledSysPackages.remove(name);
}
- PackageSetting addPackageLPw(String name, String realName, File codePath, File resourcePath,
+ PackageSetting addPackageLPw(String name, String realName, File codePath,
String legacyNativeLibraryPathString, String primaryCpuAbiString,
String secondaryCpuAbiString, String cpuAbiOverrideString, int uid, long vc, int
pkgFlags, int pkgPrivateFlags, String[] usesStaticLibraries,
@@ -572,10 +572,9 @@ public final class Settings {
"Adding duplicate package, keeping first: " + name);
return null;
}
- p = new PackageSetting(name, realName, codePath, resourcePath,
- legacyNativeLibraryPathString, primaryCpuAbiString, secondaryCpuAbiString,
- cpuAbiOverrideString, vc, pkgFlags, pkgPrivateFlags,
- 0 /*userId*/, usesStaticLibraries, usesStaticLibraryNames,
+ p = new PackageSetting(name, realName, codePath, legacyNativeLibraryPathString,
+ primaryCpuAbiString, secondaryCpuAbiString, cpuAbiOverrideString, vc, pkgFlags,
+ pkgPrivateFlags, 0 /*userId*/, usesStaticLibraries, usesStaticLibraryNames,
mimeGroups);
p.appId = uid;
if (registerExistingAppIdLPw(uid, p, name)) {
@@ -635,7 +634,7 @@ public final class Settings {
*/
static @NonNull PackageSetting createNewSetting(String pkgName, PackageSetting originalPkg,
PackageSetting disabledPkg, String realPkgName, SharedUserSetting sharedUser,
- File codePath, File resourcePath, String legacyNativeLibraryPath, String primaryCpuAbi,
+ File codePath, String legacyNativeLibraryPath, String primaryCpuAbi,
String secondaryCpuAbi, long versionCode, int pkgFlags, int pkgPrivateFlags,
UserHandle installUser, boolean allowInstall, boolean instantApp,
boolean virtualPreload, UserManagerService userManager,
@@ -646,12 +645,11 @@ public final class Settings {
if (PackageManagerService.DEBUG_UPGRADE) Log.v(PackageManagerService.TAG, "Package "
+ pkgName + " is adopting original package " + originalPkg.name);
pkgSetting = new PackageSetting(originalPkg, pkgName /*realPkgName*/);
- pkgSetting.codePath = codePath;
+ pkgSetting.setCodePath(codePath);
pkgSetting.legacyNativeLibraryPathString = legacyNativeLibraryPath;
pkgSetting.pkgFlags = pkgFlags;
pkgSetting.pkgPrivateFlags = pkgPrivateFlags;
pkgSetting.primaryCpuAbiString = primaryCpuAbi;
- pkgSetting.resourcePath = resourcePath;
pkgSetting.secondaryCpuAbiString = secondaryCpuAbi;
// NOTE: Create a deeper copy of the package signatures so we don't
// overwrite the signatures in the original package setting.
@@ -662,7 +660,7 @@ public final class Settings {
// Update new package state.
pkgSetting.setTimeStamp(codePath.lastModified());
} else {
- pkgSetting = new PackageSetting(pkgName, realPkgName, codePath, resourcePath,
+ pkgSetting = new PackageSetting(pkgName, realPkgName, codePath,
legacyNativeLibraryPath, primaryCpuAbi, secondaryCpuAbi,
null /*cpuAbiOverrideString*/, versionCode, pkgFlags, pkgPrivateFlags,
0 /*sharedUserId*/, usesStaticLibraries,
@@ -756,10 +754,9 @@ public final class Settings {
*/
static void updatePackageSetting(@NonNull PackageSetting pkgSetting,
@Nullable PackageSetting disabledPkg, @Nullable SharedUserSetting sharedUser,
- @NonNull File codePath, File resourcePath,
- @Nullable String legacyNativeLibraryPath, @Nullable String primaryCpuAbi,
- @Nullable String secondaryCpuAbi, int pkgFlags, int pkgPrivateFlags,
- @NonNull UserManagerService userManager,
+ @NonNull File codePath, @Nullable String legacyNativeLibraryPath,
+ @Nullable String primaryCpuAbi, @Nullable String secondaryCpuAbi, int pkgFlags,
+ int pkgPrivateFlags, @NonNull UserManagerService userManager,
@Nullable String[] usesStaticLibraries, @Nullable long[] usesStaticLibrariesVersions,
@Nullable Set<String> mimeGroupNames)
throws PackageManagerException {
@@ -773,12 +770,12 @@ public final class Settings {
"Updating application package " + pkgName + " failed");
}
- if (!pkgSetting.codePath.equals(codePath)) {
+ if (!pkgSetting.getCodePath().equals(codePath)) {
final boolean isSystem = pkgSetting.isSystem();
Slog.i(PackageManagerService.TAG,
"Update" + (isSystem ? " system" : "")
+ " package " + pkgName
- + " code path from " + pkgSetting.codePathString
+ + " code path from " + pkgSetting.getCodePathString()
+ " to " + codePath.toString()
+ "; Retain data and using new");
if (!isSystem) {
@@ -800,19 +797,7 @@ public final class Settings {
// internal to external storage or vice versa.
pkgSetting.legacyNativeLibraryPathString = legacyNativeLibraryPath;
}
- pkgSetting.codePath = codePath;
- pkgSetting.codePathString = codePath.toString();
- }
- if (!pkgSetting.resourcePath.equals(resourcePath)) {
- final boolean isSystem = pkgSetting.isSystem();
- Slog.i(PackageManagerService.TAG,
- "Update" + (isSystem ? " system" : "")
- + " package " + pkgName
- + " resource path from " + pkgSetting.resourcePathString
- + " to " + resourcePath.toString()
- + "; Retain data and using new");
- pkgSetting.resourcePath = resourcePath;
- pkgSetting.resourcePathString = resourcePath.toString();
+ pkgSetting.setCodePath(codePath);
}
// If what we are scanning is a system (and possibly privileged) package,
// then make it so, regardless of whether it was previously installed only
@@ -2710,7 +2695,7 @@ public final class Settings {
private void writePackageListLPrInternal(int creatingUserId) {
// Only derive GIDs for active users (not dying)
- final List<UserInfo> users = getUsers(UserManagerService.getInstance(), true);
+ final List<UserInfo> users = getActiveUsers(UserManagerService.getInstance(), true);
int[] userIds = new int[users.size()];
for (int i = 0; i < userIds.length; i++) {
userIds[i] = users.get(i).id;
@@ -2812,14 +2797,11 @@ public final class Settings {
if (pkg.realName != null) {
serializer.attribute(null, "realName", pkg.realName);
}
- serializer.attribute(null, "codePath", pkg.codePathString);
+ serializer.attribute(null, "codePath", pkg.getCodePathString());
serializer.attribute(null, "ft", Long.toHexString(pkg.timeStamp));
serializer.attribute(null, "it", Long.toHexString(pkg.firstInstallTime));
serializer.attribute(null, "ut", Long.toHexString(pkg.lastUpdateTime));
serializer.attribute(null, "version", String.valueOf(pkg.versionCode));
- if (!pkg.resourcePathString.equals(pkg.codePathString)) {
- serializer.attribute(null, "resourcePath", pkg.resourcePathString);
- }
if (pkg.legacyNativeLibraryPathString != null) {
serializer.attribute(null, "nativeLibraryPath", pkg.legacyNativeLibraryPathString);
}
@@ -2857,10 +2839,7 @@ public final class Settings {
if (pkg.realName != null) {
serializer.attribute(null, "realName", pkg.realName);
}
- serializer.attribute(null, "codePath", pkg.codePathString);
- if (!pkg.resourcePathString.equals(pkg.codePathString)) {
- serializer.attribute(null, "resourcePath", pkg.resourcePathString);
- }
+ serializer.attribute(null, "codePath", pkg.getCodePathString());
if (pkg.legacyNativeLibraryPathString != null) {
serializer.attribute(null, "nativeLibraryPath", pkg.legacyNativeLibraryPathString);
@@ -3559,13 +3538,10 @@ public final class Settings {
String name = parser.getAttributeValue(null, ATTR_NAME);
String realName = parser.getAttributeValue(null, "realName");
String codePathStr = parser.getAttributeValue(null, "codePath");
- String resourcePathStr = parser.getAttributeValue(null, "resourcePath");
String legacyCpuAbiStr = parser.getAttributeValue(null, "requiredCpuAbi");
String legacyNativeLibraryPathStr = parser.getAttributeValue(null, "nativeLibraryPath");
- String parentPackageName = parser.getAttributeValue(null, "parentPackageName");
-
String primaryCpuAbiStr = parser.getAttributeValue(null, "primaryCpuAbi");
String secondaryCpuAbiStr = parser.getAttributeValue(null, "secondaryCpuAbi");
String cpuAbiOverrideStr = parser.getAttributeValue(null, "cpuAbiOverride");
@@ -3574,9 +3550,6 @@ public final class Settings {
primaryCpuAbiStr = legacyCpuAbiStr;
}
- if (resourcePathStr == null) {
- resourcePathStr = codePathStr;
- }
String version = parser.getAttributeValue(null, "version");
long versionCode = 0;
if (version != null) {
@@ -3593,9 +3566,8 @@ public final class Settings {
pkgPrivateFlags |= ApplicationInfo.PRIVATE_FLAG_PRIVILEGED;
}
PackageSetting ps = new PackageSetting(name, realName, new File(codePathStr),
- new File(resourcePathStr), legacyNativeLibraryPathStr, primaryCpuAbiStr,
- secondaryCpuAbiStr, cpuAbiOverrideStr, versionCode, pkgFlags, pkgPrivateFlags,
- 0 /*sharedUserId*/, null, null, null);
+ legacyNativeLibraryPathStr, primaryCpuAbiStr, secondaryCpuAbiStr, cpuAbiOverrideStr,
+ versionCode, pkgFlags, pkgPrivateFlags, 0 /*sharedUserId*/, null, null, null);
String timeStampStr = parser.getAttributeValue(null, "ft");
if (timeStampStr != null) {
try {
@@ -3666,7 +3638,6 @@ public final class Settings {
String idStr = null;
String sharedIdStr = null;
String codePathStr = null;
- String resourcePathStr = null;
String legacyCpuAbiString = null;
String legacyNativeLibraryPathStr = null;
String primaryCpuAbiString = null;
@@ -3700,7 +3671,6 @@ public final class Settings {
uidError = parser.getAttributeValue(null, "uidError");
sharedIdStr = parser.getAttributeValue(null, "sharedUserId");
codePathStr = parser.getAttributeValue(null, "codePath");
- resourcePathStr = parser.getAttributeValue(null, "resourcePath");
legacyCpuAbiString = parser.getAttributeValue(null, "requiredCpuAbi");
@@ -3818,9 +3788,6 @@ public final class Settings {
+ " sharedUserId=" + sharedIdStr);
final int userId = idStr != null ? Integer.parseInt(idStr) : 0;
final int sharedUserId = sharedIdStr != null ? Integer.parseInt(sharedIdStr) : 0;
- if (resourcePathStr == null) {
- resourcePathStr = codePathStr;
- }
if (realName != null) {
realName = realName.intern();
}
@@ -3834,10 +3801,10 @@ public final class Settings {
+ parser.getPositionDescription());
} else if (userId > 0) {
packageSetting = addPackageLPw(name.intern(), realName, new File(codePathStr),
- new File(resourcePathStr), legacyNativeLibraryPathStr, primaryCpuAbiString,
- secondaryCpuAbiString, cpuAbiOverrideString, userId, versionCode, pkgFlags,
- pkgPrivateFlags, null /*usesStaticLibraries*/,
- null /*usesStaticLibraryVersions*/, null /*mimeGroups*/);
+ legacyNativeLibraryPathStr, primaryCpuAbiString, secondaryCpuAbiString,
+ cpuAbiOverrideString, userId, versionCode, pkgFlags, pkgPrivateFlags,
+ null /*usesStaticLibraries*/, null /*usesStaticLibraryVersions*/,
+ null /*mimeGroups*/);
if (PackageManagerService.DEBUG_SETTINGS)
Log.i(PackageManagerService.TAG, "Reading package " + name + ": userId="
+ userId + " pkg=" + packageSetting);
@@ -3852,8 +3819,8 @@ public final class Settings {
}
} else if (sharedIdStr != null) {
if (sharedUserId > 0) {
- packageSetting = new PackageSetting(name.intern(), realName, new File(
- codePathStr), new File(resourcePathStr), legacyNativeLibraryPathStr,
+ packageSetting = new PackageSetting(name.intern(), realName,
+ new File(codePathStr), legacyNativeLibraryPathStr,
primaryCpuAbiString, secondaryCpuAbiString, cpuAbiOverrideString,
versionCode, pkgFlags, pkgPrivateFlags, sharedUserId,
null /*usesStaticLibraries*/,
@@ -4456,25 +4423,43 @@ public final class Settings {
}
/**
- * Return all users on the device, including partial or dying users.
+ * Returns all users on the device, including pre-created and dying users.
+ *
* @param userManager UserManagerService instance
* @return the list of users
*/
private static List<UserInfo> getAllUsers(UserManagerService userManager) {
- return getUsers(userManager, false);
+ return getUsers(userManager, /* excludeDying= */ false, /* excludePreCreated= */ false);
}
/**
- * Return the list of users on the device. Clear the calling identity before calling into
- * UserManagerService.
+ * Returns the list of users on the device, excluding pre-created ones.
+ *
* @param userManager UserManagerService instance
* @param excludeDying Indicates whether to exclude any users marked for deletion.
+ *
+ * @return the list of users
+ */
+ private static List<UserInfo> getActiveUsers(UserManagerService userManager,
+ boolean excludeDying) {
+ return getUsers(userManager, excludeDying, /* excludePreCreated= */ true);
+ }
+
+ /**
+ * Returns the list of users on the device.
+ *
+ * @param userManager UserManagerService instance
+ * @param excludeDying Indicates whether to exclude any users marked for deletion.
+ * @param excludePreCreated Indicates whether to exclude any pre-created users.
+ *
* @return the list of users
*/
- private static List<UserInfo> getUsers(UserManagerService userManager, boolean excludeDying) {
+ private static List<UserInfo> getUsers(UserManagerService userManager, boolean excludeDying,
+ boolean excludePreCreated) {
long id = Binder.clearCallingIdentity();
try {
- return userManager.getUsers(excludeDying);
+ return userManager.getUsers(/* excludePartial= */ true, excludeDying,
+ excludePreCreated);
} catch (NullPointerException npe) {
// packagemanager not yet initialized
} finally {
@@ -4657,9 +4642,9 @@ public final class Settings {
pw.print(prefix); pw.print(" sharedUser="); pw.println(ps.sharedUser);
}
pw.print(prefix); pw.print(" pkg="); pw.println(pkg);
- pw.print(prefix); pw.print(" codePath="); pw.println(ps.codePathString);
+ pw.print(prefix); pw.print(" codePath="); pw.println(ps.getCodePathString());
if (permissionNames == null) {
- pw.print(prefix); pw.print(" resourcePath="); pw.println(ps.resourcePathString);
+ pw.print(prefix); pw.print(" resourcePath="); pw.println(ps.getCodePathString());
pw.print(prefix); pw.print(" legacyNativeLibraryDir=");
pw.println(ps.legacyNativeLibraryPathString);
pw.print(prefix); pw.print(" primaryCpuAbi="); pw.println(ps.primaryCpuAbiString);
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index 89ed3c755783..700f7be83e15 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -260,7 +260,8 @@ public class ShortcutService extends IShortcutService.Stub {
private static final int PACKAGE_MATCH_FLAGS =
PackageManager.MATCH_DIRECT_BOOT_AWARE
| PackageManager.MATCH_DIRECT_BOOT_UNAWARE
- | PackageManager.MATCH_UNINSTALLED_PACKAGES;
+ | PackageManager.MATCH_UNINSTALLED_PACKAGES
+ | PackageManager.MATCH_DISABLED_COMPONENTS;
private static final int SYSTEM_APP_MASK =
ApplicationInfo.FLAG_SYSTEM | ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
@@ -278,12 +279,6 @@ public class ShortcutService extends IShortcutService.Stub {
}
};
- private static Predicate<ResolveInfo> ACTIVITY_NOT_SYSTEM_NOR_ENABLED = (ri) -> {
- final ApplicationInfo ai = ri.activityInfo.applicationInfo;
- final boolean isSystemApp = ai != null && (ai.flags & SYSTEM_APP_MASK) != 0;
- return !isSystemApp && !ri.activityInfo.enabled;
- };
-
private static Predicate<ResolveInfo> ACTIVITY_NOT_INSTALLED = (ri) ->
!isInstalled(ri.activityInfo);
@@ -3685,10 +3680,8 @@ public class ShortcutService extends IShortcutService.Stub {
final long start = getStatStartTime();
final long token = injectClearCallingIdentity();
try {
- return mIPackageManager.getPackageInfo(
- packageName, PACKAGE_MATCH_FLAGS | PackageManager.MATCH_DISABLED_COMPONENTS
- | (getSignatures ? PackageManager.GET_SIGNING_CERTIFICATES : 0),
- userId);
+ return mIPackageManager.getPackageInfo(packageName, PACKAGE_MATCH_FLAGS
+ | (getSignatures ? PackageManager.GET_SIGNING_CERTIFICATES : 0), userId);
} catch (RemoteException e) {
// Shouldn't happen.
Slog.wtf(TAG, "RemoteException", e);
@@ -3721,8 +3714,7 @@ public class ShortcutService extends IShortcutService.Stub {
final long start = getStatStartTime();
final long token = injectClearCallingIdentity();
try {
- return mIPackageManager.getApplicationInfo(packageName,
- PACKAGE_MATCH_FLAGS | PackageManager.MATCH_DISABLED_COMPONENTS, userId);
+ return mIPackageManager.getApplicationInfo(packageName, PACKAGE_MATCH_FLAGS, userId);
} catch (RemoteException e) {
// Shouldn't happen.
Slog.wtf(TAG, "RemoteException", e);
@@ -3753,9 +3745,8 @@ public class ShortcutService extends IShortcutService.Stub {
final long start = getStatStartTime();
final long token = injectClearCallingIdentity();
try {
- return mIPackageManager.getActivityInfo(activity, (PACKAGE_MATCH_FLAGS
- | PackageManager.MATCH_DISABLED_COMPONENTS | PackageManager.GET_META_DATA),
- userId);
+ return mIPackageManager.getActivityInfo(activity,
+ PACKAGE_MATCH_FLAGS | PackageManager.GET_META_DATA, userId);
} catch (RemoteException e) {
// Shouldn't happen.
Slog.wtf(TAG, "RemoteException", e);
@@ -3800,8 +3791,7 @@ public class ShortcutService extends IShortcutService.Stub {
List<PackageInfo> injectGetPackagesWithUninstalled(@UserIdInt int userId)
throws RemoteException {
final ParceledListSlice<PackageInfo> parceledList =
- mIPackageManager.getInstalledPackages(
- PACKAGE_MATCH_FLAGS | PackageManager.MATCH_DISABLED_COMPONENTS, userId);
+ mIPackageManager.getInstalledPackages(PACKAGE_MATCH_FLAGS, userId);
if (parceledList == null) {
return Collections.emptyList();
}
@@ -3836,6 +3826,41 @@ public class ShortcutService extends IShortcutService.Stub {
return (ai != null) && ((ai.flags & flags) == flags);
}
+ // Due to b/38267327, ActivityInfo.enabled may not reflect the current state of the component
+ // and we need to check the enabled state via PackageManager.getComponentEnabledSetting.
+ private boolean isEnabled(@Nullable ActivityInfo ai, int userId) {
+ if (ai == null) {
+ return false;
+ }
+
+ int enabledFlag;
+ final long token = injectClearCallingIdentity();
+ try {
+ enabledFlag = mIPackageManager.getComponentEnabledSetting(
+ ai.getComponentName(), userId);
+ } catch (RemoteException e) {
+ // Shouldn't happen.
+ Slog.wtf(TAG, "RemoteException", e);
+ return false;
+ } finally {
+ injectRestoreCallingIdentity(token);
+ }
+
+ if ((enabledFlag == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT && ai.enabled)
+ || enabledFlag == PackageManager.COMPONENT_ENABLED_STATE_ENABLED) {
+ return true;
+ }
+ return false;
+ }
+
+ private static boolean isSystem(@Nullable ActivityInfo ai) {
+ return (ai != null) && isSystem(ai.applicationInfo);
+ }
+
+ private static boolean isSystem(@Nullable ApplicationInfo ai) {
+ return (ai != null) && (ai.flags & SYSTEM_APP_MASK) != 0;
+ }
+
private static boolean isInstalled(@Nullable ApplicationInfo ai) {
return (ai != null) && ai.enabled && (ai.flags & ApplicationInfo.FLAG_INSTALLED) != 0;
}
@@ -3900,12 +3925,6 @@ public class ShortcutService extends IShortcutService.Stub {
return intent;
}
- private static boolean isSystemApp(@Nullable final ApplicationInfo ai) {
- final int systemAppMask =
- ApplicationInfo.FLAG_SYSTEM | ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
- return ai != null && ((ai.flags & systemAppMask) != 0);
- }
-
/**
* Same as queryIntentActivitiesAsUser, except it makes sure the package is installed,
* and only returns exported activities.
@@ -3938,7 +3957,10 @@ public class ShortcutService extends IShortcutService.Stub {
}
// Make sure the package is installed.
resolved.removeIf(ACTIVITY_NOT_INSTALLED);
- resolved.removeIf(ACTIVITY_NOT_SYSTEM_NOR_ENABLED);
+ resolved.removeIf((ri) -> {
+ final ActivityInfo ai = ri.activityInfo;
+ return !isSystem(ai) && !isEnabled(ai, userId);
+ });
if (exportedOnly) {
resolved.removeIf(ACTIVITY_NOT_EXPORTED);
}
diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java
index 89bdb3ecbff9..f9bf54a11df0 100644
--- a/services/core/java/com/android/server/pm/StagingManager.java
+++ b/services/core/java/com/android/server/pm/StagingManager.java
@@ -322,9 +322,6 @@ public class StagingManager {
}
final long activeVersion = activePackage.applicationInfo.longVersionCode;
if (activeVersion != session.params.requiredInstalledVersionCode) {
- if (!mApexManager.abortStagedSession(session.sessionId)) {
- Slog.e(TAG, "Failed to abort apex session " + session.sessionId);
- }
throw new PackageManagerException(
SessionInfo.STAGED_SESSION_VERIFICATION_FAILED,
"Installed version of APEX package " + activePackage.packageName
@@ -338,14 +335,11 @@ public class StagingManager {
throws PackageManagerException {
final long activeVersion = activePackage.applicationInfo.longVersionCode;
final long newVersionCode = newPackage.applicationInfo.longVersionCode;
- boolean isAppDebuggable = (activePackage.applicationInfo.flags
+ final boolean isAppDebuggable = (activePackage.applicationInfo.flags
& ApplicationInfo.FLAG_DEBUGGABLE) != 0;
final boolean allowsDowngrade = PackageManagerServiceUtils.isDowngradePermitted(
session.params.installFlags, isAppDebuggable);
if (activeVersion > newVersionCode && !allowsDowngrade) {
- if (!mApexManager.abortStagedSession(session.sessionId)) {
- Slog.e(TAG, "Failed to abort apex session " + session.sessionId);
- }
throw new PackageManagerException(
SessionInfo.STAGED_SESSION_VERIFICATION_FAILED,
"Downgrade of APEX package " + newPackage.packageName
@@ -835,37 +829,6 @@ public class StagingManager {
return null;
}
- private void verifyApksInSession(PackageInstallerSession session)
- throws PackageManagerException {
-
- final PackageInstallerSession apksToVerify = extractApksInSession(
- session, /* preReboot */ true);
- if (apksToVerify == null) {
- return;
- }
-
- final LocalIntentReceiverAsync receiver = new LocalIntentReceiverAsync(
- (Intent result) -> {
- int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,
- PackageInstaller.STATUS_FAILURE);
- if (status != PackageInstaller.STATUS_SUCCESS) {
- final String errorMessage = result.getStringExtra(
- PackageInstaller.EXTRA_STATUS_MESSAGE);
- Slog.e(TAG, "Failure to verify APK staged session "
- + session.sessionId + " [" + errorMessage + "]");
- session.setStagedSessionFailed(
- SessionInfo.STAGED_SESSION_VERIFICATION_FAILED, errorMessage);
- mPreRebootVerificationHandler.onPreRebootVerificationComplete(
- session.sessionId);
- return;
- }
- mPreRebootVerificationHandler.notifyPreRebootVerification_Apk_Complete(
- session.sessionId);
- });
-
- apksToVerify.commit(receiver.getIntentSender(), false);
- }
-
private void installApksInSession(@NonNull PackageInstallerSession session)
throws PackageManagerException {
@@ -908,10 +871,21 @@ public class StagingManager {
mPreRebootVerificationHandler.startPreRebootVerification(session.sessionId);
}
- private int parentOrOwnSessionId(PackageInstallerSession session) {
+ private int getSessionIdForParentOrSelf(PackageInstallerSession session) {
return session.hasParentSessionId() ? session.getParentSessionId() : session.sessionId;
}
+ private PackageInstallerSession getParentSessionOrSelf(PackageInstallerSession session) {
+ return session.hasParentSessionId()
+ ? getStagedSession(session.getParentSessionId())
+ : session;
+ }
+
+ private boolean isRollback(PackageInstallerSession session) {
+ final PackageInstallerSession root = getParentSessionOrSelf(session);
+ return root.params.installReason == PackageManager.INSTALL_REASON_ROLLBACK;
+ }
+
/**
* <p> Check if the session provided is non-overlapping with the active staged sessions.
*
@@ -937,6 +911,8 @@ public class StagingManager {
boolean supportsCheckpoint = ((StorageManager) mContext.getSystemService(
Context.STORAGE_SERVICE)).isCheckpointSupported();
+ final boolean isRollback = isRollback(session);
+
synchronized (mStagedSessions) {
for (int i = 0; i < mStagedSessions.size(); i++) {
final PackageInstallerSession stagedSession = mStagedSessions.valueAt(i);
@@ -951,8 +927,8 @@ public class StagingManager {
}
// Check if stagedSession has an active parent session or not
if (stagedSession.hasParentSessionId()) {
- int parentId = stagedSession.getParentSessionId();
- PackageInstallerSession parentSession = mStagedSessions.get(parentId);
+ final int parentId = stagedSession.getParentSessionId();
+ final PackageInstallerSession parentSession = mStagedSessions.get(parentId);
if (parentSession == null || parentSession.isStagedAndInTerminalState()
|| parentSession.isDestroyed()) {
// Parent session has been abandoned or terminated already
@@ -968,21 +944,37 @@ public class StagingManager {
continue;
}
- // If session is not among the active sessions, then it cannot have same package
- // name as any of the active sessions.
+ // New session cannot have same package name as one of the active sessions
if (session.getPackageName().equals(stagedSession.getPackageName())) {
- throw new PackageManagerException(
- PackageManager.INSTALL_FAILED_OTHER_STAGED_SESSION_IN_PROGRESS,
- "Package: " + session.getPackageName() + " in session: "
- + session.sessionId + " has been staged already by session: "
- + stagedSession.sessionId, null);
+ if (isRollback) {
+ // If the new session is a rollback, then it gets priority. The existing
+ // session is failed to unblock rollback.
+ final PackageInstallerSession root = getParentSessionOrSelf(stagedSession);
+ if (!ensureActiveApexSessionIsAborted(root)) {
+ Slog.e(TAG, "Failed to abort apex session " + root.sessionId);
+ // Safe to ignore active apex session abort failure since session
+ // will be marked failed on next step and staging directory for session
+ // will be deleted.
+ }
+ root.setStagedSessionFailed(
+ SessionInfo.STAGED_SESSION_OTHER_ERROR,
+ "Session was blocking rollback session: " + session.sessionId);
+ Slog.i(TAG, "Session " + root.sessionId + " is marked failed due to "
+ + "blocking rollback session: " + session.sessionId);
+ } else {
+ throw new PackageManagerException(
+ PackageManager.INSTALL_FAILED_OTHER_STAGED_SESSION_IN_PROGRESS,
+ "Package: " + session.getPackageName() + " in session: "
+ + session.sessionId + " has been staged already by session:"
+ + " " + stagedSession.sessionId, null);
+ }
}
// Staging multiple root sessions is not allowed if device doesn't support
// checkpoint. If session and stagedSession do not have common ancestor, they are
// from two different root sessions.
- if (!supportsCheckpoint
- && parentOrOwnSessionId(session) != parentOrOwnSessionId(stagedSession)) {
+ if (!supportsCheckpoint && getSessionIdForParentOrSelf(session)
+ != getSessionIdForParentOrSelf(stagedSession)) {
throw new PackageManagerException(
PackageManager.INSTALL_FAILED_OTHER_STAGED_SESSION_IN_PROGRESS,
"Cannot stage multiple sessions without checkpoint support", null);
@@ -1042,23 +1034,11 @@ public class StagingManager {
// A session could be marked ready once its pre-reboot verification ends
if (session.isStagedSessionReady()) {
- if (sessionContainsApex(session)) {
- try {
- ApexSessionInfo apexSession =
- mApexManager.getStagedSessionInfo(session.sessionId);
- if (apexSession == null || isApexSessionFinalized(apexSession)) {
- Slog.w(TAG,
- "Cannot abort session " + session.sessionId
- + " because it is not active.");
- } else {
- mApexManager.abortStagedSession(session.sessionId);
- }
- } catch (Exception e) {
- // Failed to contact apexd service. The apex might still be staged. We can still
- // safely cleanup the staged session since pre-reboot verification is complete.
- // Also, cleaning up the stageDir prevents the apex from being activated.
- Slog.w(TAG, "Could not contact apexd to abort staged session " + sessionId);
- }
+ if (!ensureActiveApexSessionIsAborted(session)) {
+ // Failed to ensure apex session is aborted, so it can still be staged. We can still
+ // safely cleanup the staged session since pre-reboot verification is complete.
+ // Also, cleaning up the stageDir prevents the apex from being activated.
+ Slog.e(TAG, "Failed to abort apex session " + session.sessionId);
}
}
@@ -1068,6 +1048,22 @@ public class StagingManager {
return true;
}
+ /**
+ * Ensure that there is no active apex session staged in apexd for the given session.
+ *
+ * @return returns true if it is ensured that there is no active apex session, otherwise false
+ */
+ private boolean ensureActiveApexSessionIsAborted(PackageInstallerSession session) {
+ if (!sessionContainsApex(session)) {
+ return true;
+ }
+ final ApexSessionInfo apexSession = mApexManager.getStagedSessionInfo(session.sessionId);
+ if (apexSession == null || isApexSessionFinalized(apexSession)) {
+ return true;
+ }
+ return mApexManager.abortStagedSession(session.sessionId);
+ }
+
private boolean isApexSessionFinalized(ApexSessionInfo session) {
/* checking if the session is in a final state, i.e., not active anymore */
return session.isUnknown || session.isActivationFailed || session.isSuccess
@@ -1294,8 +1290,8 @@ public class StagingManager {
+ sessionId);
return;
}
- if (session.isDestroyed()) {
- // No point in running verification on a destroyed session
+ if (session.isDestroyed() || session.isStagedSessionFailed()) {
+ // No point in running verification on a destroyed/failed session
onPreRebootVerificationComplete(sessionId);
return;
}
@@ -1348,6 +1344,17 @@ public class StagingManager {
obtainMessage(MSG_PRE_REBOOT_VERIFICATION_START, sessionId, 0).sendToTarget();
}
+ private void onPreRebootVerificationFailure(PackageInstallerSession session,
+ @SessionInfo.StagedSessionErrorCode int errorCode, String errorMessage) {
+ if (!ensureActiveApexSessionIsAborted(session)) {
+ Slog.e(TAG, "Failed to abort apex session " + session.sessionId);
+ // Safe to ignore active apex session abortion failure since session will be marked
+ // failed on next step and staging directory for session will be deleted.
+ }
+ session.setStagedSessionFailed(errorCode, errorMessage);
+ onPreRebootVerificationComplete(session.sessionId);
+ }
+
// Things to do when pre-reboot verification completes for a particular sessionId
private void onPreRebootVerificationComplete(int sessionId) {
// Remove it from mVerificationRunning so that verification is considered complete
@@ -1432,8 +1439,7 @@ public class StagingManager {
validateApexSignature(apexPackages.get(i));
}
} catch (PackageManagerException e) {
- session.setStagedSessionFailed(e.error, e.getMessage());
- onPreRebootVerificationComplete(session.sessionId);
+ onPreRebootVerificationFailure(session, e.error, e.getMessage());
return;
}
@@ -1460,16 +1466,42 @@ public class StagingManager {
try {
Slog.d(TAG, "Running a pre-reboot verification for APKs in session "
+ session.sessionId + " by performing a dry-run install");
-
// verifyApksInSession will notify the handler when APK verification is complete
verifyApksInSession(session);
- // TODO(b/118865310): abort the session on apexd.
} catch (PackageManagerException e) {
- session.setStagedSessionFailed(e.error, e.getMessage());
- onPreRebootVerificationComplete(session.sessionId);
+ onPreRebootVerificationFailure(session, e.error, e.getMessage());
}
}
+ private void verifyApksInSession(PackageInstallerSession session)
+ throws PackageManagerException {
+
+ final PackageInstallerSession apksToVerify = extractApksInSession(
+ session, /* preReboot */ true);
+ if (apksToVerify == null) {
+ return;
+ }
+
+ final LocalIntentReceiverAsync receiver = new LocalIntentReceiverAsync(
+ (Intent result) -> {
+ final int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,
+ PackageInstaller.STATUS_FAILURE);
+ if (status != PackageInstaller.STATUS_SUCCESS) {
+ final String errorMessage = result.getStringExtra(
+ PackageInstaller.EXTRA_STATUS_MESSAGE);
+ Slog.e(TAG, "Failure to verify APK staged session "
+ + session.sessionId + " [" + errorMessage + "]");
+ onPreRebootVerificationFailure(session,
+ SessionInfo.STAGED_SESSION_ACTIVATION_FAILED, errorMessage);
+ return;
+ }
+ mPreRebootVerificationHandler.notifyPreRebootVerification_Apk_Complete(
+ session.sessionId);
+ });
+
+ apksToVerify.commit(receiver.getIntentSender(), false);
+ }
+
/**
* Pre-reboot verification state for wrapping up:
* <p><ul>
@@ -1487,9 +1519,8 @@ public class StagingManager {
} catch (Exception e) {
// Failed to get hold of StorageManager
Slog.e(TAG, "Failed to get hold of StorageManager", e);
- session.setStagedSessionFailed(SessionInfo.STAGED_SESSION_UNKNOWN,
+ onPreRebootVerificationFailure(session, SessionInfo.STAGED_SESSION_UNKNOWN,
"Failed to get hold of StorageManager");
- onPreRebootVerificationComplete(session.sessionId);
return;
}
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 8f11fd529e60..e3bee7228c68 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -3497,7 +3497,7 @@ public class UserManagerService extends IUserManager.Stub {
}
t.traceBegin("PM.onNewUserCreated-" + userId);
- mPm.onNewUserCreated(userId);
+ mPm.onNewUserCreated(userId, /* convertedFromPreCreated= */ false);
t.traceEnd();
if (preCreate) {
// Must start user (which will be stopped right away, through
@@ -3570,10 +3570,7 @@ public class UserManagerService extends IUserManager.Stub {
writeUserListLP();
}
updateUserIds();
- if (!mPm.readPermissionStateForUser(preCreatedUser.id)) {
- // Could not read the existing permissions, re-grant them.
- mPm.onNewUserCreated(preCreatedUser.id);
- }
+ mPm.onNewUserCreated(preCreatedUser.id, /* convertedFromPreCreated= */ true);
dispatchUserAdded(preCreatedUser);
return preCreatedUser;
}
diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java
index 3ec61fdda917..7467439905eb 100644
--- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java
+++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java
@@ -18,7 +18,6 @@ package com.android.server.timezonedetector;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.annotation.UserIdInt;
import android.app.timezonedetector.ITimeZoneConfigurationListener;
import android.app.timezonedetector.ITimeZoneDetectorService;
import android.app.timezonedetector.ManualTimeZoneSuggestion;
@@ -38,6 +37,7 @@ import android.os.UserHandle;
import android.provider.Settings;
import android.util.IndentingPrintWriter;
import android.util.Slog;
+import android.util.SparseArray;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
@@ -60,7 +60,8 @@ import java.util.Objects;
* and making calls async, leaving the (consequently more testable) {@link TimeZoneDetectorStrategy}
* implementation to deal with the logic around time zone detection.
*/
-public final class TimeZoneDetectorService extends ITimeZoneDetectorService.Stub {
+public final class TimeZoneDetectorService extends ITimeZoneDetectorService.Stub
+ implements IBinder.DeathRecipient {
private static final String TAG = "TimeZoneDetectorService";
@@ -104,9 +105,15 @@ public final class TimeZoneDetectorService extends ITimeZoneDetectorService.Stub
@NonNull
private final TimeZoneDetectorStrategy mTimeZoneDetectorStrategy;
+ /**
+ * This sparse array acts as a map from userId to listeners running as that userId. User scoped
+ * as time zone detection configuration is partially user-specific, so different users can
+ * get different configuration.
+ */
@GuardedBy("mConfigurationListeners")
@NonNull
- private final ArrayList<ConfigListenerInfo> mConfigurationListeners = new ArrayList<>();
+ private final SparseArray<ArrayList<ITimeZoneConfigurationListener>> mConfigurationListeners =
+ new SparseArray<>();
private static TimeZoneDetectorService create(
@NonNull Context context, @NonNull Handler handler,
@@ -188,18 +195,23 @@ public final class TimeZoneDetectorService extends ITimeZoneDetectorService.Stub
Objects.requireNonNull(listener);
int userId = UserHandle.getCallingUserId();
- ConfigListenerInfo listenerInfo = new ConfigListenerInfo(userId, listener);
-
synchronized (mConfigurationListeners) {
- if (mConfigurationListeners.contains(listenerInfo)) {
+ ArrayList<ITimeZoneConfigurationListener> listeners =
+ mConfigurationListeners.get(userId);
+ if (listeners != null && listeners.contains(listener)) {
return;
}
try {
- // Ensure the reference to the listener is removed if the client process dies.
- listenerInfo.linkToDeath();
+ if (listeners == null) {
+ listeners = new ArrayList<>(1);
+ mConfigurationListeners.put(userId, listeners);
+ }
+
+ // Ensure the reference to the listener will be removed if the client process dies.
+ listener.asBinder().linkToDeath(this, 0 /* flags */);
// Only add the listener if we can linkToDeath().
- mConfigurationListeners.add(listenerInfo);
+ listeners.add(listener);
} catch (RemoteException e) {
Slog.e(TAG, "Unable to linkToDeath() for listener=" + listener, e);
}
@@ -213,21 +225,56 @@ public final class TimeZoneDetectorService extends ITimeZoneDetectorService.Stub
int userId = UserHandle.getCallingUserId();
synchronized (mConfigurationListeners) {
- ConfigListenerInfo toRemove = new ConfigListenerInfo(userId, listener);
- Iterator<ConfigListenerInfo> listenerIterator = mConfigurationListeners.iterator();
- while (listenerIterator.hasNext()) {
- ConfigListenerInfo currentListenerInfo = listenerIterator.next();
- if (currentListenerInfo.equals(toRemove)) {
- listenerIterator.remove();
-
- // Stop listening for the client process to die.
- try {
- currentListenerInfo.unlinkToDeath();
- } catch (RemoteException e) {
- Slog.e(TAG, "Unable to unlinkToDeath() for listener=" + listener, e);
+ boolean removedListener = false;
+ ArrayList<ITimeZoneConfigurationListener> userListeners =
+ mConfigurationListeners.get(userId);
+ if (userListeners.remove(listener)) {
+ // Stop listening for the client process to die.
+ listener.asBinder().unlinkToDeath(this, 0 /* flags */);
+ removedListener = true;
+ }
+ if (!removedListener) {
+ Slog.w(TAG, "Client asked to remove listenener=" + listener
+ + ", but no listeners were removed."
+ + " mConfigurationListeners=" + mConfigurationListeners);
+ }
+ }
+ }
+
+ @Override
+ public void binderDied() {
+ // Should not be used as binderDied(IBinder who) is overridden.
+ Slog.wtf(TAG, "binderDied() called unexpectedly.");
+ }
+
+ /**
+ * Called when one of the ITimeZoneConfigurationListener processes dies before calling
+ * {@link #removeConfigurationListener(ITimeZoneConfigurationListener)}.
+ */
+ @Override
+ public void binderDied(IBinder who) {
+ synchronized (mConfigurationListeners) {
+ boolean removedListener = false;
+ final int userCount = mConfigurationListeners.size();
+ for (int i = 0; i < userCount; i++) {
+ ArrayList<ITimeZoneConfigurationListener> userListeners =
+ mConfigurationListeners.valueAt(i);
+ Iterator<ITimeZoneConfigurationListener> userListenerIterator =
+ userListeners.iterator();
+ while (userListenerIterator.hasNext()) {
+ ITimeZoneConfigurationListener userListener = userListenerIterator.next();
+ if (userListener.asBinder().equals(who)) {
+ userListenerIterator.remove();
+ removedListener = true;
+ break;
}
}
}
+ if (!removedListener) {
+ Slog.w(TAG, "Notified of binder death for who=" + who
+ + ", but did not remove any listeners."
+ + " mConfigurationListeners=" + mConfigurationListeners);
+ }
}
}
@@ -243,14 +290,24 @@ public final class TimeZoneDetectorService extends ITimeZoneDetectorService.Stub
// problem.
synchronized (mConfigurationListeners) {
- for (ConfigListenerInfo listenerInfo : mConfigurationListeners) {
+ final int userCount = mConfigurationListeners.size();
+ for (int userIndex = 0; userIndex < userCount; userIndex++) {
+ int userId = mConfigurationListeners.keyAt(userIndex);
TimeZoneConfiguration configuration =
- mTimeZoneDetectorStrategy.getConfiguration(listenerInfo.getUserId());
- try {
- listenerInfo.getListener().onChange(configuration);
- } catch (RemoteException e) {
- Slog.w(TAG, "Unable to notify listener="
- + listenerInfo + " of updated configuration=" + configuration, e);
+ mTimeZoneDetectorStrategy.getConfiguration(userId);
+
+ ArrayList<ITimeZoneConfigurationListener> listeners =
+ mConfigurationListeners.valueAt(userIndex);
+ final int listenerCount = listeners.size();
+ for (int listenerIndex = 0; listenerIndex < listenerCount; listenerIndex++) {
+ ITimeZoneConfigurationListener listener = listeners.get(listenerIndex);
+ try {
+ listener.onChange(configuration);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Unable to notify listener=" + listener
+ + " for userId=" + userId
+ + " of updated configuration=" + configuration, e);
+ }
}
}
}
@@ -338,66 +395,5 @@ public final class TimeZoneDetectorService extends ITimeZoneDetectorService.Stub
(new TimeZoneDetectorShellCommand(this)).exec(
this, in, out, err, args, callback, resultReceiver);
}
-
- private class ConfigListenerInfo implements IBinder.DeathRecipient {
- private final @UserIdInt int mUserId;
- private final ITimeZoneConfigurationListener mListener;
-
- ConfigListenerInfo(
- @UserIdInt int userId, @NonNull ITimeZoneConfigurationListener listener) {
- this.mUserId = userId;
- this.mListener = Objects.requireNonNull(listener);
- }
-
- @UserIdInt int getUserId() {
- return mUserId;
- }
-
- ITimeZoneConfigurationListener getListener() {
- return mListener;
- }
-
- void linkToDeath() throws RemoteException {
- mListener.asBinder().linkToDeath(this, 0 /* flags */);
- }
-
- void unlinkToDeath() throws RemoteException {
- mListener.asBinder().unlinkToDeath(this, 0 /* flags */);
- }
-
- @Override
- public void binderDied() {
- synchronized (mConfigurationListeners) {
- Slog.i(TAG, "Configuration listener client died: " + this);
- mConfigurationListeners.remove(this);
- }
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (o == null || getClass() != o.getClass()) {
- return false;
- }
- ConfigListenerInfo that = (ConfigListenerInfo) o;
- return mUserId == that.mUserId
- && mListener.equals(that.mListener);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(mUserId, mListener);
- }
-
- @Override
- public String toString() {
- return "ConfigListenerInfo{"
- + "mUserId=" + mUserId
- + ", mListener=" + mListener
- + '}';
- }
- }
}
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index b72ff2db7e6c..1b4fac6f407a 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -70,7 +70,7 @@ import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TASK;
import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TOP;
import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_ALWAYS;
import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_DEFAULT;
-import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED;
+import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_IF_ALLOWLISTED;
import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_NEVER;
import static android.content.pm.ActivityInfo.PERSIST_ACROSS_REBOOTS;
import static android.content.pm.ActivityInfo.PERSIST_ROOT_ONLY;
@@ -168,7 +168,7 @@ import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLAS
import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_FREE_RESIZE;
import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_NONE;
import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_WINDOWING_MODE_RESIZE;
-import static com.android.server.wm.ActivityTaskManagerService.getInputDispatchingTimeoutLocked;
+import static com.android.server.wm.ActivityTaskManagerService.getInputDispatchingTimeoutMillisLocked;
import static com.android.server.wm.IdentifierProto.HASH_CODE;
import static com.android.server.wm.IdentifierProto.TITLE;
import static com.android.server.wm.IdentifierProto.USER_ID;
@@ -587,8 +587,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
*/
private boolean mOccludesParent;
- // The input dispatching timeout for this application token in nanoseconds.
- long mInputDispatchingTimeoutNanos;
+ // The input dispatching timeout for this application token in milliseconds.
+ long mInputDispatchingTimeoutMillis;
private boolean mShowWhenLocked;
private boolean mInheritShownWhenLocked;
@@ -1245,7 +1245,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
if (oldParent == null && newParent != null) {
// First time we are adding the activity to the system.
mVoiceInteraction = newTask.voiceSession != null;
- mInputDispatchingTimeoutNanos = getInputDispatchingTimeoutLocked(this) * 1000000L;
+ mInputDispatchingTimeoutMillis = getInputDispatchingTimeoutMillisLocked(this);
// TODO(b/36505427): Maybe this call should be moved inside
// updateOverrideConfiguration()
@@ -1683,7 +1683,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
if (options != null) {
final boolean useLockTask = options.getLockTaskMode();
if (useLockTask && lockTaskLaunchMode == LOCK_TASK_LAUNCH_MODE_DEFAULT) {
- lockTaskLaunchMode = LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED;
+ lockTaskLaunchMode = LOCK_TASK_LAUNCH_MODE_IF_ALLOWLISTED;
}
}
return lockTaskLaunchMode;
@@ -5651,8 +5651,9 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
} else {
// In this case another process added windows using this activity token. So, we call the
// generic service input dispatch timed out method so that the right process is blamed.
- return mAtmService.mAmInternal.inputDispatchingTimedOut(
- windowPid, false /* aboveSystem */, reason) < 0;
+ long timeoutMillis = mAtmService.mAmInternal.inputDispatchingTimedOut(
+ windowPid, false /* aboveSystem */, reason);
+ return timeoutMillis <= 0;
}
}
diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
index ed1ea353eb3e..2c475e0b9bcb 100644
--- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
@@ -74,9 +74,9 @@ import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_RECENTS;
import static com.android.server.wm.Task.ActivityState.PAUSED;
import static com.android.server.wm.Task.ActivityState.PAUSING;
import static com.android.server.wm.Task.FLAG_FORCE_HIDDEN_FOR_PINNED_TASK;
+import static com.android.server.wm.Task.LOCK_TASK_AUTH_ALLOWLISTED;
import static com.android.server.wm.Task.LOCK_TASK_AUTH_LAUNCHABLE;
import static com.android.server.wm.Task.LOCK_TASK_AUTH_LAUNCHABLE_PRIV;
-import static com.android.server.wm.Task.LOCK_TASK_AUTH_WHITELISTED;
import static com.android.server.wm.Task.REPARENT_KEEP_STACK_AT_FRONT;
import static com.android.server.wm.Task.TAG_CLEANUP;
import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS;
@@ -130,6 +130,7 @@ import android.util.MergedConfiguration;
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseIntArray;
+import android.view.Display;
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
@@ -788,7 +789,7 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks {
final LockTaskController lockTaskController = mService.getLockTaskController();
if (task.mLockTaskAuth == LOCK_TASK_AUTH_LAUNCHABLE
|| task.mLockTaskAuth == LOCK_TASK_AUTH_LAUNCHABLE_PRIV
- || (task.mLockTaskAuth == LOCK_TASK_AUTH_WHITELISTED
+ || (task.mLockTaskAuth == LOCK_TASK_AUTH_ALLOWLISTED
&& lockTaskController.getLockTaskModeState()
== LOCK_TASK_MODE_LOCKED)) {
lockTaskController.startLockTaskMode(task, false, 0 /* blank UID */);
@@ -1090,9 +1091,9 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks {
// Check if caller is already present on display
final boolean uidPresentOnDisplay = displayContent.isUidPresent(callingUid);
- final int displayOwnerUid = displayContent.mDisplay.getOwnerUid();
- if (displayContent.mDisplay.getType() == TYPE_VIRTUAL && displayOwnerUid != SYSTEM_UID) {
- // Limit launching on virtual displays, because their contents can be read from Surface
+ final Display display = displayContent.mDisplay;
+ if (!display.isTrusted()) {
+ // Limit launching on untrusted displays because their contents can be read from Surface
// by apps that created them.
if ((aInfo.flags & ActivityInfo.FLAG_ALLOW_EMBEDDED) == 0) {
if (DEBUG_TASKS) Slog.d(TAG, "Launch on display check:"
@@ -1116,7 +1117,7 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks {
}
// Check if the caller is the owner of the display.
- if (displayOwnerUid == callingUid) {
+ if (display.getOwnerUid() == callingUid) {
if (DEBUG_TASKS) Slog.d(TAG, "Launch on display check:"
+ " allow launch for owner of the display");
return true;
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
index 777ddda89e9d..2dc22ecfc022 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
@@ -528,8 +528,8 @@ public abstract class ActivityTaskManagerInternal {
public abstract void onActiveUidsCleared();
public abstract void onUidProcStateChanged(int uid, int procState);
- public abstract void onUidAddedToPendingTempWhitelist(int uid, String tag);
- public abstract void onUidRemovedFromPendingTempWhitelist(int uid);
+ public abstract void onUidAddedToPendingTempAllowlist(int uid, String tag);
+ public abstract void onUidRemovedFromPendingTempAllowlist(int uid);
/** Handle app crash event in {@link android.app.IActivityController} if there is one. */
public abstract boolean handleAppCrashInActivityController(String processName, int pid,
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 5534b8c257f0..627361d780a2 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -50,6 +50,7 @@ import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.os.FactoryTest.FACTORY_TEST_HIGH_LEVEL;
import static android.os.FactoryTest.FACTORY_TEST_LOW_LEVEL;
import static android.os.FactoryTest.FACTORY_TEST_OFF;
+import static android.os.IInputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
import static android.os.Process.FIRST_APPLICATION_UID;
import static android.os.Process.SYSTEM_UID;
import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
@@ -182,7 +183,6 @@ import android.database.ContentObserver;
import android.graphics.Bitmap;
import android.graphics.Point;
import android.graphics.Rect;
-import android.metrics.LogMaker;
import android.net.Uri;
import android.os.Binder;
import android.os.Build;
@@ -237,12 +237,9 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.AssistUtils;
import com.android.internal.app.IVoiceInteractor;
import com.android.internal.app.ProcessMap;
-import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
import com.android.internal.notification.SystemNotificationChannels;
import com.android.internal.os.TransferPipe;
-import com.android.internal.os.logging.MetricsLoggerWrapper;
import com.android.internal.policy.IKeyguardDismissCallback;
import com.android.internal.policy.KeyguardDismissCallback;
import com.android.internal.util.ArrayUtils;
@@ -314,10 +311,8 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
private static final String TAG_LOCKTASK = TAG + POSTFIX_LOCKTASK;
private static final String TAG_CONFIGURATION = TAG + POSTFIX_CONFIGURATION;
- // How long we wait until we timeout on key dispatching.
- public static final int KEY_DISPATCHING_TIMEOUT_MS = 5 * 1000;
// How long we wait until we timeout on key dispatching during instrumentation.
- static final int INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT_MS = 60 * 1000;
+ static final long INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT_MILLIS = 60 * 1000;
// How long we permit background activity starts after an activity in the process
// started or finished.
static final long ACTIVITY_BG_START_GRACE_PERIOD_MS = 10 * 1000;
@@ -385,7 +380,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
private AppOpsManager mAppOpsManager;
/** All active uids in the system. */
private final MirrorActiveUids mActiveUids = new MirrorActiveUids();
- private final SparseArray<String> mPendingTempWhitelist = new SparseArray<>();
+ private final SparseArray<String> mPendingTempAllowlist = new SparseArray<>();
/** All processes currently running that might have a window organized by name. */
final ProcessMap<WindowProcessController> mProcessNames = new ProcessMap<>();
/** All processes we currently have running mapped by pid and uid */
@@ -1111,7 +1106,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
@Override
public int startActivityIntentSender(IApplicationThread caller, IIntentSender target,
- IBinder whitelistToken, Intent fillInIntent, String resolvedType, IBinder resultTo,
+ IBinder allowlistToken, Intent fillInIntent, String resolvedType, IBinder resultTo,
String resultWho, int requestCode, int flagsMask, int flagsValues, Bundle bOptions) {
enforceNotIsolatedCaller("startActivityIntentSender");
// Refuse possible leaked file descriptors
@@ -1134,7 +1129,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
mAppSwitchesAllowedTime = 0;
}
}
- return pir.sendInner(0, fillInIntent, resolvedType, whitelistToken, null, null,
+ return pir.sendInner(0, fillInIntent, resolvedType, allowlistToken, null, null,
resultTo, resultWho, requestCode, flagsMask, flagsValues, bOptions);
}
@@ -3038,7 +3033,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
// system or a specific app.
// * System-initiated requests will only start the pinned mode (screen pinning)
// * App-initiated requests
- // - will put the device in fully locked mode (LockTask), if the app is whitelisted
+ // - will put the device in fully locked mode (LockTask), if the app is allowlisted
// - will start the pinned mode, otherwise
final int callingUid = Binder.getCallingUid();
long ident = Binder.clearCallingIdentity();
@@ -3078,7 +3073,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
"updateLockTaskPackages()");
}
synchronized (mGlobalLock) {
- if (DEBUG_LOCKTASK) Slog.w(TAG_LOCKTASK, "Whitelisting " + userId + ":"
+ if (DEBUG_LOCKTASK) Slog.w(TAG_LOCKTASK, "Allowlisting " + userId + ":"
+ Arrays.toString(packages));
getLockTaskController().updateLockTaskPackages(userId, packages);
}
@@ -4096,10 +4091,6 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
final Task stack = r.getRootTask();
stack.setPictureInPictureAspectRatio(aspectRatio);
stack.setPictureInPictureActions(actions);
- MetricsLoggerWrapper.logPictureInPictureEnter(mContext,
- r.info.applicationInfo.uid, r.shortComponentName,
- r.supportsEnterPipOnTaskSwitch);
- logPictureInPictureArgs(params);
}
};
@@ -4143,7 +4134,6 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
r.pictureInPictureArgs.getAspectRatio());
stack.setPictureInPictureActions(r.pictureInPictureArgs.getActions());
}
- logPictureInPictureArgs(params);
}
} finally {
Binder.restoreCallingIdentity(origId);
@@ -4157,18 +4147,6 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
return 3;
}
- private void logPictureInPictureArgs(PictureInPictureParams params) {
- if (params.hasSetActions()) {
- MetricsLogger.histogram(mContext, "tron_varz_picture_in_picture_actions_count",
- params.getActions().size());
- }
- if (params.hasSetAspectRatio()) {
- LogMaker lm = new LogMaker(MetricsEvent.ACTION_PICTURE_IN_PICTURE_ASPECT_RATIO_CHANGED);
- lm.addTaggedData(MetricsEvent.PICTURE_IN_PICTURE_ASPECT_RATIO, params.getAspectRatio());
- MetricsLogger.action(lm);
- }
- }
-
/**
* Checks the state of the system and the activity associated with the given {@param token} to
* verify that picture-in-picture is supported for that activity.
@@ -5376,15 +5354,18 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
}
}
- static long getInputDispatchingTimeoutLocked(ActivityRecord r) {
+ static long getInputDispatchingTimeoutMillisLocked(ActivityRecord r) {
if (r == null || !r.hasProcess()) {
- return KEY_DISPATCHING_TIMEOUT_MS;
+ return DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
}
- return getInputDispatchingTimeoutLocked(r.app);
+ return getInputDispatchingTimeoutMillisLocked(r.app);
}
- private static long getInputDispatchingTimeoutLocked(WindowProcessController r) {
- return r != null ? r.getInputDispatchingTimeout() : KEY_DISPATCHING_TIMEOUT_MS;
+ private static long getInputDispatchingTimeoutMillisLocked(WindowProcessController r) {
+ if (r == null) {
+ return DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
+ }
+ return r.getInputDispatchingTimeoutMillis();
}
/**
@@ -5977,11 +5958,11 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
}
/**
- * @return whitelist tag for a uid from mPendingTempWhitelist, null if not currently on
- * the whitelist
+ * @return allowlist tag for a uid from mPendingTempAllowlist, null if not currently on
+ * the allowlist
*/
- String getPendingTempWhitelistTagForUidLocked(int uid) {
- return mPendingTempWhitelist.get(uid);
+ String getPendingTempAllowlistTagForUidLocked(int uid) {
+ return mPendingTempAllowlist.get(uid);
}
void logAppTooSlow(WindowProcessController app, long startTime, String msg) {
@@ -7323,16 +7304,16 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
}
@Override
- public void onUidAddedToPendingTempWhitelist(int uid, String tag) {
+ public void onUidAddedToPendingTempAllowlist(int uid, String tag) {
synchronized (mGlobalLockWithoutBoost) {
- mPendingTempWhitelist.put(uid, tag);
+ mPendingTempAllowlist.put(uid, tag);
}
}
@Override
- public void onUidRemovedFromPendingTempWhitelist(int uid) {
+ public void onUidRemovedFromPendingTempAllowlist(int uid) {
synchronized (mGlobalLockWithoutBoost) {
- mPendingTempWhitelist.remove(uid);
+ mPendingTempAllowlist.remove(uid);
}
}
diff --git a/services/core/java/com/android/server/wm/DragState.java b/services/core/java/com/android/server/wm/DragState.java
index f840d9273f60..22dd1d332345 100644
--- a/services/core/java/com/android/server/wm/DragState.java
+++ b/services/core/java/com/android/server/wm/DragState.java
@@ -16,6 +16,8 @@
package com.android.server.wm;
+import static android.os.IInputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
+
import static com.android.server.wm.DragDropController.MSG_ANIMATION_END;
import static com.android.server.wm.DragDropController.MSG_DRAG_END_TIMEOUT;
import static com.android.server.wm.DragDropController.MSG_TEAR_DOWN_DRAG_AND_DROP_INPUT;
@@ -271,8 +273,7 @@ class DragState {
mDragApplicationHandle = new InputApplicationHandle(new Binder());
mDragApplicationHandle.name = "drag";
- mDragApplicationHandle.dispatchingTimeoutNanos =
- WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS;
+ mDragApplicationHandle.dispatchingTimeoutMillis = DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
mDragWindowHandle = new InputWindowHandle(mDragApplicationHandle,
display.getDisplayId());
@@ -280,8 +281,7 @@ class DragState {
mDragWindowHandle.token = mServerChannel.getToken();
mDragWindowHandle.layoutParamsFlags = 0;
mDragWindowHandle.layoutParamsType = WindowManager.LayoutParams.TYPE_DRAG;
- mDragWindowHandle.dispatchingTimeoutNanos =
- WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS;
+ mDragWindowHandle.dispatchingTimeoutMillis = DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
mDragWindowHandle.visible = true;
mDragWindowHandle.canReceiveKeys = false;
mDragWindowHandle.hasFocus = true;
diff --git a/services/core/java/com/android/server/wm/InputConsumerImpl.java b/services/core/java/com/android/server/wm/InputConsumerImpl.java
index 852b367259c1..3b24584b0357 100644
--- a/services/core/java/com/android/server/wm/InputConsumerImpl.java
+++ b/services/core/java/com/android/server/wm/InputConsumerImpl.java
@@ -16,6 +16,8 @@
package com.android.server.wm;
+import static android.os.IInputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
+
import android.graphics.Point;
import android.graphics.Rect;
import android.os.Binder;
@@ -69,16 +71,14 @@ class InputConsumerImpl implements IBinder.DeathRecipient {
mApplicationHandle = new InputApplicationHandle(new Binder());
mApplicationHandle.name = name;
- mApplicationHandle.dispatchingTimeoutNanos =
- WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS;
+ mApplicationHandle.dispatchingTimeoutMillis = DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
mWindowHandle = new InputWindowHandle(mApplicationHandle, displayId);
mWindowHandle.name = name;
mWindowHandle.token = mServerChannel.getToken();
mWindowHandle.layoutParamsType = WindowManager.LayoutParams.TYPE_INPUT_CONSUMER;
mWindowHandle.layoutParamsFlags = 0;
- mWindowHandle.dispatchingTimeoutNanos =
- WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS;
+ mWindowHandle.dispatchingTimeoutMillis = DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
mWindowHandle.visible = true;
mWindowHandle.canReceiveKeys = false;
mWindowHandle.hasFocus = false;
diff --git a/services/core/java/com/android/server/wm/InputManagerCallback.java b/services/core/java/com/android/server/wm/InputManagerCallback.java
index 9c4ac890fed8..e166bfc08ad4 100644
--- a/services/core/java/com/android/server/wm/InputManagerCallback.java
+++ b/services/core/java/com/android/server/wm/InputManagerCallback.java
@@ -10,6 +10,7 @@ import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import static com.android.server.wm.WindowManagerService.H.ON_POINTER_DOWN_OUTSIDE_FOCUS;
+import android.annotation.Nullable;
import android.os.Build;
import android.os.Debug;
import android.os.IBinder;
@@ -173,23 +174,23 @@ final class InputManagerCallback implements InputManagerService.WindowManagerCal
*/
@Override
public long notifyANR(InputApplicationHandle inputApplicationHandle, IBinder token,
- String reason) {
+ @Nullable Integer pid, String reason) {
final long startTime = SystemClock.uptimeMillis();
try {
- return notifyANRInner(inputApplicationHandle, token, reason);
+ return notifyANRInner(inputApplicationHandle, token, pid, reason);
} finally {
// Log the time because the method is called from InputDispatcher thread. It shouldn't
- // take too long that may affect input response time.
+ // take too long because it blocks input while executing.
Slog.d(TAG_WM, "notifyANR took " + (SystemClock.uptimeMillis() - startTime) + "ms");
}
}
private long notifyANRInner(InputApplicationHandle inputApplicationHandle, IBinder token,
- String reason) {
+ @Nullable Integer pid, String reason) {
ActivityRecord activity = null;
WindowState windowState = null;
boolean aboveSystem = false;
- int windowPid = INVALID_PID;
+ int windowPid = pid != null ? pid : INVALID_PID;
preDumpIfLockTooSlow();
@@ -258,18 +259,14 @@ final class InputManagerCallback implements InputManagerService.WindowManagerCal
if (!abort) {
// The activity manager declined to abort dispatching.
// Wait a bit longer and timeout again later.
- return activity.mInputDispatchingTimeoutNanos;
+ return TimeUnit.MILLISECONDS.toNanos(activity.mInputDispatchingTimeoutMillis);
}
} else if (windowState != null || windowPid != INVALID_PID) {
// Notify the activity manager about the timeout and let it decide whether
// to abort dispatching or keep waiting.
- long timeout = mService.mAmInternal.inputDispatchingTimedOut(windowPid, aboveSystem,
- reason);
- if (timeout >= 0) {
- // The activity manager declined to abort dispatching.
- // Wait a bit longer and timeout again later.
- return timeout * 1000000L; // nanoseconds
- }
+ long timeoutMillis =
+ mService.mAmInternal.inputDispatchingTimedOut(windowPid, aboveSystem, reason);
+ return TimeUnit.MILLISECONDS.toNanos(timeoutMillis);
}
return 0; // abort dispatching
}
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index 20f1b9f53013..791f47128be0 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -269,7 +269,7 @@ final class InputMonitor {
flags = child.getSurfaceTouchableRegion(inputWindowHandle, flags);
inputWindowHandle.layoutParamsFlags = flags;
inputWindowHandle.layoutParamsType = type;
- inputWindowHandle.dispatchingTimeoutNanos = child.getInputDispatchingTimeoutNanos();
+ inputWindowHandle.dispatchingTimeoutMillis = child.getInputDispatchingTimeoutMillis();
inputWindowHandle.visible = isVisible;
inputWindowHandle.canReceiveKeys = child.canReceiveKeys();
inputWindowHandle.hasFocus = hasFocus;
@@ -385,7 +385,7 @@ final class InputMonitor {
} else {
final InputApplicationHandle handle = newApp.mInputApplicationHandle;
handle.name = newApp.toString();
- handle.dispatchingTimeoutNanos = newApp.mInputDispatchingTimeoutNanos;
+ handle.dispatchingTimeoutMillis = newApp.mInputDispatchingTimeoutMillis;
mService.mInputManager.setFocusedApplication(mDisplayId, handle);
}
@@ -570,8 +570,7 @@ final class InputMonitor {
final String name, final int type, final boolean isVisible) {
inputWindowHandle.name = name;
inputWindowHandle.layoutParamsType = type;
- inputWindowHandle.dispatchingTimeoutNanos =
- WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS;
+ inputWindowHandle.dispatchingTimeoutMillis = 0; // it should never receive input
inputWindowHandle.visible = isVisible;
inputWindowHandle.canReceiveKeys = false;
inputWindowHandle.hasFocus = false;
diff --git a/services/core/java/com/android/server/wm/Letterbox.java b/services/core/java/com/android/server/wm/Letterbox.java
index 28dcbcdf3cc7..dccd3a669827 100644
--- a/services/core/java/com/android/server/wm/Letterbox.java
+++ b/services/core/java/com/android/server/wm/Letterbox.java
@@ -16,6 +16,7 @@
package com.android.server.wm;
+import static android.os.IInputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
import static android.view.SurfaceControl.HIDDEN;
import android.graphics.Point;
@@ -217,8 +218,7 @@ public class Letterbox {
| WindowManager.LayoutParams.FLAG_SPLIT_TOUCH
| WindowManager.LayoutParams.FLAG_SLIPPERY;
mWindowHandle.layoutParamsType = WindowManager.LayoutParams.TYPE_INPUT_CONSUMER;
- mWindowHandle.dispatchingTimeoutNanos =
- WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS;
+ mWindowHandle.dispatchingTimeoutMillis = DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
mWindowHandle.visible = true;
mWindowHandle.ownerPid = Process.myPid();
mWindowHandle.ownerUid = Process.myUid();
diff --git a/services/core/java/com/android/server/wm/LockTaskController.java b/services/core/java/com/android/server/wm/LockTaskController.java
index c7a438d527ad..8ef57f726658 100644
--- a/services/core/java/com/android/server/wm/LockTaskController.java
+++ b/services/core/java/com/android/server/wm/LockTaskController.java
@@ -33,11 +33,11 @@ import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_LOCKTAS
import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_LOCKTASK;
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.Task.LOCK_TASK_AUTH_ALLOWLISTED;
import static com.android.server.wm.Task.LOCK_TASK_AUTH_DONT_LOCK;
import static com.android.server.wm.Task.LOCK_TASK_AUTH_LAUNCHABLE;
import static com.android.server.wm.Task.LOCK_TASK_AUTH_LAUNCHABLE_PRIV;
import static com.android.server.wm.Task.LOCK_TASK_AUTH_PINNABLE;
-import static com.android.server.wm.Task.LOCK_TASK_AUTH_WHITELISTED;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -264,12 +264,12 @@ public class LockTaskController {
}
/**
- * @return whether the requested task is allowed to be locked (either whitelisted, or declares
+ * @return whether the requested task is allowed to be locked (either allowlisted, or declares
* lockTaskMode="always" in the manifest).
*/
- boolean isTaskWhitelisted(Task task) {
+ boolean isTaskAllowlisted(Task task) {
switch(task.mLockTaskAuth) {
- case LOCK_TASK_AUTH_WHITELISTED:
+ case LOCK_TASK_AUTH_ALLOWLISTED:
case LOCK_TASK_AUTH_LAUNCHABLE:
case LOCK_TASK_AUTH_LAUNCHABLE_PRIV:
return true;
@@ -311,7 +311,7 @@ public class LockTaskController {
private boolean isLockTaskModeViolationInternal(Task task, boolean isNewClearTask) {
// TODO: Double check what's going on here. If the task is already in lock task mode, it's
- // likely whitelisted, so will return false below.
+ // likely allowlisted, so will return false below.
if (isTaskLocked(task) && !isNewClearTask) {
// If the task is already at the top and won't be cleared, then allow the operation
return false;
@@ -327,7 +327,7 @@ public class LockTaskController {
return false;
}
- return !(isTaskWhitelisted(task) || mLockTaskModeTasks.isEmpty());
+ return !(isTaskAllowlisted(task) || mLockTaskModeTasks.isEmpty());
}
private boolean isRecentsAllowed(int userId) {
@@ -356,7 +356,7 @@ public class LockTaskController {
return false;
default:
}
- return isPackageWhitelisted(userId, packageName);
+ return isPackageAllowlisted(userId, packageName);
}
private boolean isEmergencyCallTask(Task task) {
@@ -556,7 +556,7 @@ public class LockTaskController {
if (!isSystemCaller) {
task.mLockTaskUid = callingUid;
if (task.mLockTaskAuth == LOCK_TASK_AUTH_PINNABLE) {
- // startLockTask() called by app, but app is not part of lock task whitelist. Show
+ // startLockTask() called by app, but app is not part of lock task allowlist. Show
// app pinning request. We will come back here with isSystemCaller true.
if (DEBUG_LOCKTASK) Slog.w(TAG_LOCKTASK, "Mode default, asking user");
StatusBarManagerInternal statusBarManager = LocalServices.getService(
@@ -649,8 +649,8 @@ public class LockTaskController {
/**
* Update packages that are allowed to be launched in lock task mode.
- * @param userId Which user this whitelist is associated with
- * @param packages The whitelist of packages allowed in lock task mode
+ * @param userId Which user this allowlist is associated with
+ * @param packages The allowlist of packages allowed in lock task mode
* @see #mLockTaskPackages
*/
void updateLockTaskPackages(int userId, String[] packages) {
@@ -659,19 +659,19 @@ public class LockTaskController {
boolean taskChanged = false;
for (int taskNdx = mLockTaskModeTasks.size() - 1; taskNdx >= 0; --taskNdx) {
final Task lockedTask = mLockTaskModeTasks.get(taskNdx);
- final boolean wasWhitelisted = lockedTask.mLockTaskAuth == LOCK_TASK_AUTH_LAUNCHABLE
- || lockedTask.mLockTaskAuth == LOCK_TASK_AUTH_WHITELISTED;
+ final boolean wasAllowlisted = lockedTask.mLockTaskAuth == LOCK_TASK_AUTH_LAUNCHABLE
+ || lockedTask.mLockTaskAuth == LOCK_TASK_AUTH_ALLOWLISTED;
lockedTask.setLockTaskAuth();
- final boolean isWhitelisted = lockedTask.mLockTaskAuth == LOCK_TASK_AUTH_LAUNCHABLE
- || lockedTask.mLockTaskAuth == LOCK_TASK_AUTH_WHITELISTED;
+ final boolean isAllowlisted = lockedTask.mLockTaskAuth == LOCK_TASK_AUTH_LAUNCHABLE
+ || lockedTask.mLockTaskAuth == LOCK_TASK_AUTH_ALLOWLISTED;
if (mLockTaskModeState != LOCK_TASK_MODE_LOCKED
|| lockedTask.mUserId != userId
- || !wasWhitelisted || isWhitelisted) {
+ || !wasAllowlisted || isAllowlisted) {
continue;
}
- // Terminate locked tasks that have recently lost whitelist authorization.
+ // Terminate locked tasks that have recently lost allowlist authorization.
if (DEBUG_LOCKTASK) Slog.d(TAG_LOCKTASK, "onLockTaskPackagesUpdated: removing " +
lockedTask + " mLockTaskAuth()=" + lockedTask.lockTaskAuthToString());
removeLockedTask(lockedTask);
@@ -697,17 +697,17 @@ public class LockTaskController {
}
}
- boolean isPackageWhitelisted(int userId, String pkg) {
+ boolean isPackageAllowlisted(int userId, String pkg) {
if (pkg == null) {
return false;
}
- String[] whitelist;
- whitelist = mLockTaskPackages.get(userId);
- if (whitelist == null) {
+ String[] allowlist;
+ allowlist = mLockTaskPackages.get(userId);
+ if (allowlist == null) {
return false;
}
- for (String whitelistedPkg : whitelist) {
- if (pkg.equals(whitelistedPkg)) {
+ for (String allowlistedPkg : allowlist) {
+ if (pkg.equals(allowlistedPkg)) {
return true;
}
}
diff --git a/services/core/java/com/android/server/wm/PolicyControl.java b/services/core/java/com/android/server/wm/PolicyControl.java
index 0f92bc83a666..61b6e0b25961 100644
--- a/services/core/java/com/android/server/wm/PolicyControl.java
+++ b/services/core/java/com/android/server/wm/PolicyControl.java
@@ -196,40 +196,40 @@ class PolicyControl {
private static final String ALL = "*";
private static final String APPS = "apps";
- private final ArraySet<String> mWhitelist;
- private final ArraySet<String> mBlacklist;
+ private final ArraySet<String> mAllowlist;
+ private final ArraySet<String> mDenylist;
- private Filter(ArraySet<String> whitelist, ArraySet<String> blacklist) {
- mWhitelist = whitelist;
- mBlacklist = blacklist;
+ private Filter(ArraySet<String> allowlist, ArraySet<String> denylist) {
+ mAllowlist = allowlist;
+ mDenylist = denylist;
}
boolean matches(LayoutParams attrs) {
if (attrs == null) return false;
boolean isApp = attrs.type >= WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW
&& attrs.type <= WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
- if (isApp && mBlacklist.contains(APPS)) return false;
- if (onBlacklist(attrs.packageName)) return false;
- if (isApp && mWhitelist.contains(APPS)) return true;
- return onWhitelist(attrs.packageName);
+ if (isApp && mDenylist.contains(APPS)) return false;
+ if (onDenylist(attrs.packageName)) return false;
+ if (isApp && mAllowlist.contains(APPS)) return true;
+ return onAllowlist(attrs.packageName);
}
boolean matches(String packageName) {
- return !onBlacklist(packageName) && onWhitelist(packageName);
+ return !onDenylist(packageName) && onAllowlist(packageName);
}
- private boolean onBlacklist(String packageName) {
- return mBlacklist.contains(packageName) || mBlacklist.contains(ALL);
+ private boolean onDenylist(String packageName) {
+ return mDenylist.contains(packageName) || mDenylist.contains(ALL);
}
- private boolean onWhitelist(String packageName) {
- return mWhitelist.contains(ALL) || mWhitelist.contains(packageName);
+ private boolean onAllowlist(String packageName) {
+ return mAllowlist.contains(ALL) || mAllowlist.contains(packageName);
}
void dump(PrintWriter pw) {
pw.print("Filter[");
- dump("whitelist", mWhitelist, pw); pw.print(',');
- dump("blacklist", mBlacklist, pw); pw.print(']');
+ dump("allowlist", mAllowlist, pw); pw.print(',');
+ dump("denylist", mDenylist, pw); pw.print(']');
}
private void dump(String name, ArraySet<String> set, PrintWriter pw) {
@@ -253,18 +253,18 @@ class PolicyControl {
// e.g. "com.package1", or "apps, com.android.keyguard" or "*"
static Filter parse(String value) {
if (value == null) return null;
- ArraySet<String> whitelist = new ArraySet<String>();
- ArraySet<String> blacklist = new ArraySet<String>();
+ ArraySet<String> allowlist = new ArraySet<String>();
+ ArraySet<String> denylist = new ArraySet<String>();
for (String token : value.split(",")) {
token = token.trim();
if (token.startsWith("-") && token.length() > 1) {
token = token.substring(1);
- blacklist.add(token);
+ denylist.add(token);
} else {
- whitelist.add(token);
+ allowlist.add(token);
}
}
- return new Filter(whitelist, blacklist);
+ return new Filter(allowlist, denylist);
}
}
}
diff --git a/services/core/java/com/android/server/wm/RecentTasks.java b/services/core/java/com/android/server/wm/RecentTasks.java
index ba2c0b6dc0ac..df5356303f8b 100644
--- a/services/core/java/com/android/server/wm/RecentTasks.java
+++ b/services/core/java/com/android/server/wm/RecentTasks.java
@@ -655,7 +655,8 @@ class RecentTasks {
}
for (int i = mTasks.size() - 1; i >= 0; --i) {
final Task task = mTasks.get(i);
- if (task.mUserId == userId && !mService.getLockTaskController().isTaskWhitelisted(task)) {
+ if (task.mUserId == userId
+ && !mService.getLockTaskController().isTaskAllowlisted(task)) {
remove(task);
}
}
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index ac96d144c4d0..1cb483c1d1a0 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -2571,7 +2571,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
mDisplayAccessUIDs.clear();
for (int displayNdx = getChildCount() - 1; displayNdx >= 0; --displayNdx) {
final DisplayContent displayContent = getChildAt(displayNdx);
- // Only bother calculating the whitelist for private displays
+ // Only bother calculating the allowlist for private displays
if (displayContent.isPrivate()) {
mDisplayAccessUIDs.append(
displayContent.mDisplayId, displayContent.getPresentUIDs());
diff --git a/services/core/java/com/android/server/wm/SafeActivityOptions.java b/services/core/java/com/android/server/wm/SafeActivityOptions.java
index b71ecbb8a72d..ede6708d5f8f 100644
--- a/services/core/java/com/android/server/wm/SafeActivityOptions.java
+++ b/services/core/java/com/android/server/wm/SafeActivityOptions.java
@@ -233,10 +233,10 @@ public class SafeActivityOptions {
Slog.w(TAG, msg);
throw new SecurityException(msg);
}
- // Check if someone tries to launch an unwhitelisted activity into LockTask mode.
+ // Check if someone tries to launch an unallowlisted activity into LockTask mode.
final boolean lockTaskMode = options.getLockTaskMode();
if (aInfo != null && lockTaskMode
- && !supervisor.mService.getLockTaskController().isPackageWhitelisted(
+ && !supervisor.mService.getLockTaskController().isPackageAllowlisted(
UserHandle.getUserId(callingUid), aInfo.packageName)) {
final String msg = "Permission Denial: starting " + getIntentString(intent)
+ " from " + callerApp + " (pid=" + callingPid
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index f3620050bed2..be0815b06051 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -45,7 +45,7 @@ import static android.content.pm.ActivityInfo.FLAG_RESUME_WHILE_PAUSING;
import static android.content.pm.ActivityInfo.FLAG_SHOW_FOR_ALL_USERS;
import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_ALWAYS;
import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_DEFAULT;
-import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED;
+import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_IF_ALLOWLISTED;
import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_NEVER;
import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_LANDSCAPE_ONLY;
import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PORTRAIT_ONLY;
@@ -210,7 +210,6 @@ import android.window.ITaskOrganizer;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.IVoiceInteractor;
-import com.android.internal.os.logging.MetricsLoggerWrapper;
import com.android.internal.util.XmlUtils;
import com.android.internal.util.function.pooled.PooledConsumer;
import com.android.internal.util.function.pooled.PooledFunction;
@@ -411,7 +410,7 @@ class Task extends WindowContainer<WindowContainer> {
/** Starts in LOCK_TASK_MODE_LOCKED automatically. Can start over existing lockTask task. */
final static int LOCK_TASK_AUTH_LAUNCHABLE = 2;
/** Can enter lockTask without user approval. Can start over existing lockTask task. */
- final static int LOCK_TASK_AUTH_WHITELISTED = 3;
+ final static int LOCK_TASK_AUTH_ALLOWLISTED = 3;
/** Priv-app that starts in LOCK_TASK_MODE_LOCKED automatically. Can start over existing
* lockTask task. */
final static int LOCK_TASK_AUTH_LAUNCHABLE_PRIV = 4;
@@ -1686,7 +1685,7 @@ class Task extends WindowContainer<WindowContainer> {
getDisplayArea().addStackReferenceIfNeeded((Task) child);
}
- // Make sure the list of display UID whitelists is updated
+ // Make sure the list of display UID allowlists is updated
// now that this record is in a new task.
mRootWindowContainer.updateUIDsPresentOnDisplay();
@@ -1903,7 +1902,7 @@ class Task extends WindowContainer<WindowContainer> {
case LOCK_TASK_AUTH_DONT_LOCK: return "LOCK_TASK_AUTH_DONT_LOCK";
case LOCK_TASK_AUTH_PINNABLE: return "LOCK_TASK_AUTH_PINNABLE";
case LOCK_TASK_AUTH_LAUNCHABLE: return "LOCK_TASK_AUTH_LAUNCHABLE";
- case LOCK_TASK_AUTH_WHITELISTED: return "LOCK_TASK_AUTH_WHITELISTED";
+ case LOCK_TASK_AUTH_ALLOWLISTED: return "LOCK_TASK_AUTH_ALLOWLISTED";
case LOCK_TASK_AUTH_LAUNCHABLE_PRIV: return "LOCK_TASK_AUTH_LAUNCHABLE_PRIV";
default: return "unknown=" + mLockTaskAuth;
}
@@ -1923,8 +1922,8 @@ class Task extends WindowContainer<WindowContainer> {
final LockTaskController lockTaskController = mAtmService.getLockTaskController();
switch (r.lockTaskLaunchMode) {
case LOCK_TASK_LAUNCH_MODE_DEFAULT:
- mLockTaskAuth = lockTaskController.isPackageWhitelisted(mUserId, pkg)
- ? LOCK_TASK_AUTH_WHITELISTED : LOCK_TASK_AUTH_PINNABLE;
+ mLockTaskAuth = lockTaskController.isPackageAllowlisted(mUserId, pkg)
+ ? LOCK_TASK_AUTH_ALLOWLISTED : LOCK_TASK_AUTH_PINNABLE;
break;
case LOCK_TASK_LAUNCH_MODE_NEVER:
@@ -1935,8 +1934,8 @@ class Task extends WindowContainer<WindowContainer> {
mLockTaskAuth = LOCK_TASK_AUTH_LAUNCHABLE_PRIV;
break;
- case LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED:
- mLockTaskAuth = lockTaskController.isPackageWhitelisted(mUserId, pkg)
+ case LOCK_TASK_LAUNCH_MODE_IF_ALLOWLISTED:
+ mLockTaskAuth = lockTaskController.isPackageAllowlisted(mUserId, pkg)
? LOCK_TASK_AUTH_LAUNCHABLE : LOCK_TASK_AUTH_PINNABLE;
break;
}
@@ -2366,7 +2365,6 @@ class Task extends WindowContainer<WindowContainer> {
private boolean shouldStartChangeTransition(int prevWinMode, int newWinMode) {
if (mWmService.mDisableTransitionAnimation
|| !isVisible()
- || getDisplayContent().mAppTransition.isTransitionSet()
|| getSurfaceControl() == null
|| !isLeafTask()) {
return false;
@@ -7372,8 +7370,6 @@ class Task extends WindowContainer<WindowContainer> {
getDisplayArea().positionChildAt(POSITION_TOP, this, false /* includingParents */);
mStackSupervisor.scheduleUpdatePictureInPictureModeIfNeeded(task, this);
- MetricsLoggerWrapper.logPictureInPictureFullScreen(mAtmService.mContext,
- task.effectiveUid, task.realActivity.flattenToString());
});
}
diff --git a/services/core/java/com/android/server/wm/TaskPositioner.java b/services/core/java/com/android/server/wm/TaskPositioner.java
index c68b660bb76f..3fbc0373e1a9 100644
--- a/services/core/java/com/android/server/wm/TaskPositioner.java
+++ b/services/core/java/com/android/server/wm/TaskPositioner.java
@@ -18,6 +18,7 @@ package com.android.server.wm;
import static android.app.ActivityTaskManager.RESIZE_MODE_USER;
import static android.app.ActivityTaskManager.RESIZE_MODE_USER_FORCED;
+import static android.os.IInputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
import static com.android.internal.policy.TaskResizingAlgorithm.CTRL_BOTTOM;
@@ -230,8 +231,8 @@ class TaskPositioner implements IBinder.DeathRecipient {
mDragApplicationHandle = new InputApplicationHandle(new Binder());
mDragApplicationHandle.name = TAG;
- mDragApplicationHandle.dispatchingTimeoutNanos =
- WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS;
+ mDragApplicationHandle.dispatchingTimeoutMillis = DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
+
mDragWindowHandle = new InputWindowHandle(mDragApplicationHandle,
displayContent.getDisplayId());
@@ -239,8 +240,7 @@ class TaskPositioner implements IBinder.DeathRecipient {
mDragWindowHandle.token = mServerChannel.getToken();
mDragWindowHandle.layoutParamsFlags = 0;
mDragWindowHandle.layoutParamsType = WindowManager.LayoutParams.TYPE_DRAG;
- mDragWindowHandle.dispatchingTimeoutNanos =
- WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS;
+ mDragWindowHandle.dispatchingTimeoutMillis = DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
mDragWindowHandle.visible = true;
mDragWindowHandle.canReceiveKeys = false;
mDragWindowHandle.hasFocus = true;
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
index f3c7a5dcb6d5..9b18ac8f7702 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
@@ -16,6 +16,7 @@
package com.android.server.wm;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.graphics.Color.WHITE;
import static android.graphics.Color.alpha;
import static android.view.View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
@@ -142,6 +143,7 @@ class TaskSnapshotSurface implements StartingSurface {
private final Handler mHandler;
private boolean mSizeMismatch;
private final Paint mBackgroundPaint = new Paint();
+ private final int mActivityType;
private final int mStatusBarColor;
@VisibleForTesting final SystemBarBackgroundPainter mSystemBarBackgroundPainter;
private final int mOrientationOnCreation;
@@ -173,6 +175,7 @@ class TaskSnapshotSurface implements StartingSurface {
final int windowFlags;
final int windowPrivateFlags;
final int currentOrientation;
+ final int activityType;
final InsetsState insetsState;
synchronized (service.mGlobalLock) {
final WindowState mainWindow = activity.findMainWindow();
@@ -241,6 +244,7 @@ class TaskSnapshotSurface implements StartingSurface {
taskBounds = new Rect();
task.getBounds(taskBounds);
currentOrientation = topFullscreenOpaqueWindow.getConfiguration().orientation;
+ activityType = activity.getActivityType();
final InsetsPolicy insetsPolicy = topFullscreenOpaqueWindow.getDisplayContent()
.getInsetsPolicy();
@@ -261,7 +265,8 @@ class TaskSnapshotSurface implements StartingSurface {
}
final TaskSnapshotSurface snapshotSurface = new TaskSnapshotSurface(service, window,
surfaceControl, snapshot, layoutParams.getTitle(), taskDescription, sysUiVis,
- windowFlags, windowPrivateFlags, taskBounds, currentOrientation, insetsState);
+ windowFlags, windowPrivateFlags, taskBounds, currentOrientation, activityType,
+ insetsState);
window.setOuter(snapshotSurface);
try {
session.relayout(window, window.mSeq, layoutParams, -1, -1, View.VISIBLE, 0, -1,
@@ -282,7 +287,7 @@ class TaskSnapshotSurface implements StartingSurface {
TaskSnapshotSurface(WindowManagerService service, Window window, SurfaceControl surfaceControl,
TaskSnapshot snapshot, CharSequence title, TaskDescription taskDescription,
int sysUiVis, int windowFlags, int windowPrivateFlags, Rect taskBounds,
- int currentOrientation, InsetsState insetsState) {
+ int currentOrientation, int activityType, InsetsState insetsState) {
mService = service;
mSurface = service.mSurfaceFactory.get();
mHandler = new Handler(mService.mH.getLooper());
@@ -298,6 +303,7 @@ class TaskSnapshotSurface implements StartingSurface {
windowPrivateFlags, sysUiVis, taskDescription, 1f, insetsState);
mStatusBarColor = taskDescription.getStatusBarColor();
mOrientationOnCreation = currentOrientation;
+ mActivityType = activityType;
mTransaction = mService.mTransactionFactory.get();
}
@@ -305,7 +311,9 @@ class TaskSnapshotSurface implements StartingSurface {
public void remove() {
synchronized (mService.mGlobalLock) {
final long now = SystemClock.uptimeMillis();
- if (mSizeMismatch && now - mShownTime < SIZE_MISMATCH_MINIMUM_TIME_MS) {
+ if (mSizeMismatch && now - mShownTime < SIZE_MISMATCH_MINIMUM_TIME_MS
+ // Show the latest content as soon as possible for unlocking to home.
+ && mActivityType != ACTIVITY_TYPE_HOME) {
mHandler.postAtTime(this::remove, mShownTime + SIZE_MISMATCH_MINIMUM_TIME_MS);
ProtoLog.v(WM_DEBUG_STARTING_WINDOW,
"Defer removing snapshot surface in %dms", (now - mShownTime));
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index ede92f0cad41..0b1d6bc0adfd 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -35,6 +35,7 @@ import static android.app.admin.DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER
import static android.content.pm.PackageManager.FEATURE_FREEFORM_WINDOW_MANAGEMENT;
import static android.content.pm.PackageManager.FEATURE_PC;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+import static android.os.IInputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
import static android.os.Process.INVALID_UID;
import static android.os.Process.SYSTEM_UID;
import static android.os.Process.myPid;
@@ -366,9 +367,6 @@ public class WindowManagerService extends IWindowManager.Stub
// proceding with safe mode detection.
private static final int INPUT_DEVICES_READY_FOR_SAFE_MODE_DETECTION_TIMEOUT_MILLIS = 1000;
- // Default input dispatching timeout in nanoseconds.
- static final long DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS = 5000 * 1000000L;
-
// Poll interval in milliseconds for watching boot animation finished.
// TODO(b/159045990) Migrate to SystemService.waitForState with dedicated thread.
private static final int BOOT_ANIMATION_POLL_INTERVAL = 50;
@@ -8090,7 +8088,7 @@ public class WindowManagerService extends IWindowManager.Stub
| LayoutParams.FLAG_SLIPPERY);
h.layoutParamsFlags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | sanitizedFlags;
h.layoutParamsType = type;
- h.dispatchingTimeoutNanos = DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS;
+ h.dispatchingTimeoutMillis = DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
h.canReceiveKeys = false;
h.hasFocus = false;
h.hasWallpaper = false;
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index df59c56f5aff..a58c5646858b 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -19,6 +19,7 @@ package com.android.server.wm;
import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.os.Build.VERSION_CODES.Q;
+import static android.os.IInputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
import static android.view.Display.INVALID_DISPLAY;
import static com.android.server.am.ActivityManagerService.MY_PID;
@@ -30,8 +31,7 @@ import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_RELEA
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.ActivityTaskManagerService.ACTIVITY_BG_START_GRACE_PERIOD_MS;
-import static com.android.server.wm.ActivityTaskManagerService.INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT_MS;
-import static com.android.server.wm.ActivityTaskManagerService.KEY_DISPATCHING_TIMEOUT_MS;
+import static com.android.server.wm.ActivityTaskManagerService.INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT_MILLIS;
import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_NONE;
import static com.android.server.wm.Task.ActivityState.DESTROYED;
import static com.android.server.wm.Task.ActivityState.DESTROYING;
@@ -41,6 +41,7 @@ import static com.android.server.wm.Task.ActivityState.RESUMED;
import static com.android.server.wm.Task.ActivityState.STARTED;
import static com.android.server.wm.Task.ActivityState.STOPPING;
+
import android.Manifest;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -1064,10 +1065,16 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
return RELAUNCH_REASON_NONE;
}
- public long getInputDispatchingTimeout() {
+ /**
+ * Get the current dispatching timeout. If instrumentation is currently taking place, return
+ * a longer value. Shorter timeout is returned otherwise.
+ * @return The timeout in milliseconds
+ */
+ public long getInputDispatchingTimeoutMillis() {
synchronized (mAtm.mGlobalLock) {
return isInstrumenting() || isUsingWrapper()
- ? INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT_MS : KEY_DISPATCHING_TIMEOUT_MS;
+ ? INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT_MILLIS :
+ DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
}
}
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index ef78420a3646..ab78e74b9e37 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -25,6 +25,7 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.app.WindowConfiguration.isSplitScreenWindowingMode;
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
import static android.graphics.GraphicsProtos.dumpPointProto;
+import static android.os.IInputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
import static android.os.PowerManager.DRAW_WAKE_LOCK;
import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
import static android.view.InsetsState.ITYPE_IME;
@@ -1635,10 +1636,10 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
}
}
- public long getInputDispatchingTimeoutNanos() {
+ public long getInputDispatchingTimeoutMillis() {
return mActivityRecord != null
- ? mActivityRecord.mInputDispatchingTimeoutNanos
- : WindowManagerService.DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS;
+ ? mActivityRecord.mInputDispatchingTimeoutMillis
+ : DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
}
@Override
diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp
index 0e1b2f25c7af..4b5f38c40e4f 100644
--- a/services/core/jni/Android.bp
+++ b/services/core/jni/Android.bp
@@ -99,6 +99,7 @@ cc_defaults {
"libpowermanager",
"libutils",
"libui",
+ "libvibratorservice",
"libinput",
"libinputflinger",
"libinputflinger_base",
diff --git a/services/core/jni/com_android_server_VibratorService.cpp b/services/core/jni/com_android_server_VibratorService.cpp
index 05aa3594eb68..74e2328105dc 100644
--- a/services/core/jni/com_android_server_VibratorService.cpp
+++ b/services/core/jni/com_android_server_VibratorService.cpp
@@ -33,6 +33,8 @@
#include <inttypes.h>
#include <stdio.h>
+#include <vibratorservice/VibratorHalController.h>
+
using android::hardware::Return;
using android::hardware::Void;
using android::hardware::vibrator::V1_0::EffectStrength;
@@ -226,8 +228,24 @@ bool isValidEffect(jlong effect) {
return val >= *iter.begin() && val <= *std::prev(iter.end());
}
-static void vibratorInit(JNIEnv *env, jclass clazz)
-{
+static aidl::CompositeEffect effectFromJavaPrimitive(JNIEnv* env, jobject primitive) {
+ aidl::CompositeEffect effect;
+ effect.primitive = static_cast<aidl::CompositePrimitive>(
+ env->GetIntField(primitive, gPrimitiveClassInfo.id));
+ effect.scale = static_cast<float>(env->GetFloatField(primitive, gPrimitiveClassInfo.scale));
+ effect.delayMs = static_cast<int32_t>(env->GetIntField(primitive, gPrimitiveClassInfo.delay));
+ return effect;
+}
+
+static void destroyVibratorController(void* rawVibratorController) {
+ vibrator::HalController* vibratorController =
+ reinterpret_cast<vibrator::HalController*>(rawVibratorController);
+ if (vibratorController) {
+ delete vibratorController;
+ }
+}
+
+static jlong vibratorInit(JNIEnv* /* env */, jclass /* clazz */) {
if (auto hal = getHal<aidl::IVibrator>()) {
// IBinder::pingBinder isn't accessible as a pointer function
// but getCapabilities can serve the same purpose
@@ -236,25 +254,26 @@ static void vibratorInit(JNIEnv *env, jclass clazz)
} else {
halCall(&V1_0::IVibrator::ping).isOk();
}
+ std::unique_ptr<vibrator::HalController> controller =
+ std::make_unique<vibrator::HalController>();
+ controller->init();
+ return reinterpret_cast<jlong>(controller.release());
}
-static jboolean vibratorExists(JNIEnv* /* env */, jclass /* clazz */)
-{
- bool ok;
+static jlong vibratorGetFinalizer(JNIEnv* /* env */, jclass /* clazz */) {
+ return static_cast<jlong>(reinterpret_cast<uintptr_t>(&destroyVibratorController));
+}
- if (auto hal = getHal<aidl::IVibrator>()) {
- // IBinder::pingBinder isn't accessible as a pointer function
- // but getCapabilities can serve the same purpose
- int32_t cap;
- ok = hal->call(&aidl::IVibrator::getCapabilities, &cap).isOk();
- } else {
- ok = halCall(&V1_0::IVibrator::ping).isOk();
+static jboolean vibratorExists(JNIEnv* env, jclass /* clazz */, jlong controllerPtr) {
+ vibrator::HalController* controller = reinterpret_cast<vibrator::HalController*>(controllerPtr);
+ if (controller == nullptr) {
+ ALOGE("vibratorExists failed because controller was not initialized");
+ return JNI_FALSE;
}
- return ok ? JNI_TRUE : JNI_FALSE;
+ return controller->ping().isOk() ? JNI_TRUE : JNI_FALSE;
}
-static void vibratorOn(JNIEnv* /* env */, jclass /* clazz */, jlong timeout_ms)
-{
+static void vibratorOn(JNIEnv* /* env */, jclass /* clazz */, jlong timeout_ms) {
if (auto hal = getHal<aidl::IVibrator>()) {
auto status = hal->call(&aidl::IVibrator::on, timeout_ms, nullptr);
if (!status.isOk()) {
@@ -268,93 +287,53 @@ static void vibratorOn(JNIEnv* /* env */, jclass /* clazz */, jlong timeout_ms)
}
}
-static void vibratorOff(JNIEnv* /* env */, jclass /* clazz */)
-{
- if (auto hal = getHal<aidl::IVibrator>()) {
- auto status = hal->call(&aidl::IVibrator::off);
- if (!status.isOk()) {
- ALOGE("vibratorOff command failed: %s", status.toString8().string());
- }
- } else {
- Status retStatus = halCall(&V1_0::IVibrator::off).withDefault(Status::UNKNOWN_ERROR);
- if (retStatus != Status::OK) {
- ALOGE("vibratorOff command failed (%" PRIu32 ").", static_cast<uint32_t>(retStatus));
- }
- }
-}
-
-static jlong vibratorSupportsAmplitudeControl(JNIEnv*, jclass) {
- if (auto hal = getHal<aidl::IVibrator>()) {
- int32_t cap = 0;
- if (!hal->call(&aidl::IVibrator::getCapabilities, &cap).isOk()) {
- return false;
- }
- return (cap & aidl::IVibrator::CAP_AMPLITUDE_CONTROL) > 0;
- } else {
- return halCall(&V1_0::IVibrator::supportsAmplitudeControl).withDefault(false);
+static void vibratorOff(JNIEnv* env, jclass /* clazz */, jlong controllerPtr) {
+ vibrator::HalController* controller = reinterpret_cast<vibrator::HalController*>(controllerPtr);
+ if (controller == nullptr) {
+ ALOGE("vibratorOff failed because controller was not initialized");
+ return;
}
+ controller->off();
}
-static void vibratorSetAmplitude(JNIEnv*, jclass, jint amplitude) {
- if (auto hal = getHal<aidl::IVibrator>()) {
- auto status = hal->call(&aidl::IVibrator::IVibrator::setAmplitude, static_cast<float>(amplitude) / UINT8_MAX);
- if (!status.isOk()) {
- ALOGE("Failed to set vibrator amplitude: %s", status.toString8().string());
- }
- } else {
- Status status = halCall(&V1_0::IVibrator::setAmplitude, static_cast<uint32_t>(amplitude))
- .withDefault(Status::UNKNOWN_ERROR);
- if (status != Status::OK) {
- ALOGE("Failed to set vibrator amplitude (%" PRIu32 ").",
- static_cast<uint32_t>(status));
- }
+static void vibratorSetAmplitude(JNIEnv* env, jclass /* clazz */, jlong controllerPtr,
+ jint amplitude) {
+ vibrator::HalController* controller = reinterpret_cast<vibrator::HalController*>(controllerPtr);
+ if (controller == nullptr) {
+ ALOGE("vibratorSetAmplitude failed because controller was not initialized");
+ return;
}
+ controller->setAmplitude(static_cast<int32_t>(amplitude));
}
-static jboolean vibratorSupportsExternalControl(JNIEnv*, jclass) {
- if (auto hal = getHal<aidl::IVibrator>()) {
- int32_t cap = 0;
- if (!hal->call(&aidl::IVibrator::getCapabilities, &cap).isOk()) {
- return false;
- }
- return (cap & aidl::IVibrator::CAP_EXTERNAL_CONTROL) > 0;
- } else {
- return halCall(&V1_3::IVibrator::supportsExternalControl).withDefault(false);
+static void vibratorSetExternalControl(JNIEnv* env, jclass /* clazz */, jlong controllerPtr,
+ jboolean enabled) {
+ vibrator::HalController* controller = reinterpret_cast<vibrator::HalController*>(controllerPtr);
+ if (controller == nullptr) {
+ ALOGE("vibratorSetExternalControl failed because controller was not initialized");
+ return;
}
+ controller->setExternalControl(enabled);
}
-static void vibratorSetExternalControl(JNIEnv*, jclass, jboolean enabled) {
- if (auto hal = getHal<aidl::IVibrator>()) {
- auto status = hal->call(&aidl::IVibrator::IVibrator::setExternalControl, enabled);
- if (!status.isOk()) {
- ALOGE("Failed to set vibrator external control: %s", status.toString8().string());
- }
- } else {
- Status status = halCall(&V1_3::IVibrator::setExternalControl, static_cast<uint32_t>(enabled))
- .withDefault(Status::UNKNOWN_ERROR);
- if (status != Status::OK) {
- ALOGE("Failed to set vibrator external control (%" PRIu32 ").",
- static_cast<uint32_t>(status));
- }
+static jintArray vibratorGetSupportedEffects(JNIEnv* env, jclass /* clazz */, jlong controllerPtr) {
+ vibrator::HalController* controller = reinterpret_cast<vibrator::HalController*>(controllerPtr);
+ if (controller == nullptr) {
+ ALOGE("vibratorGetSupportedEffects failed because controller was not initialized");
+ return nullptr;
}
-}
-
-static jintArray vibratorGetSupportedEffects(JNIEnv *env, jclass) {
- if (auto hal = getHal<aidl::IVibrator>()) {
- std::vector<aidl::Effect> supportedEffects;
- if (!hal->call(&aidl::IVibrator::getSupportedEffects, &supportedEffects).isOk()) {
- return nullptr;
- }
- jintArray arr = env->NewIntArray(supportedEffects.size());
- env->SetIntArrayRegion(arr, 0, supportedEffects.size(),
- reinterpret_cast<jint*>(supportedEffects.data()));
- return arr;
- } else {
+ auto result = controller->getSupportedEffects();
+ if (!result.isOk()) {
return nullptr;
}
+ std::vector<aidl::Effect> supportedEffects = result.value();
+ jintArray effects = env->NewIntArray(supportedEffects.size());
+ env->SetIntArrayRegion(effects, 0, supportedEffects.size(),
+ reinterpret_cast<jint*>(supportedEffects.data()));
+ return effects;
}
-static jlong vibratorPerformEffect(JNIEnv* env, jclass, jlong effect, jlong strength,
+static jlong vibratorPerformEffect(JNIEnv* env, jclass /* clazz */, jlong effect, jlong strength,
jobject vibration, jboolean withCallback) {
if (auto hal = getHal<aidl::IVibrator>()) {
int32_t lengthMs;
@@ -420,17 +399,8 @@ static jlong vibratorPerformEffect(JNIEnv* env, jclass, jlong effect, jlong stre
return -1;
}
-static aidl::CompositeEffect effectFromJavaPrimitive(JNIEnv* env, jobject primitive) {
- aidl::CompositeEffect effect;
- effect.primitive = static_cast<aidl::CompositePrimitive>(
- env->GetIntField(primitive, gPrimitiveClassInfo.id));
- effect.scale = static_cast<float>(env->GetFloatField(primitive, gPrimitiveClassInfo.scale));
- effect.delayMs = static_cast<int>(env->GetIntField(primitive, gPrimitiveClassInfo.delay));
- return effect;
-}
-
-static void vibratorPerformComposedEffect(JNIEnv* env, jclass, jobjectArray composition,
- jobject vibration) {
+static void vibratorPerformComposedEffect(JNIEnv* env, jclass /* clazz */, jobjectArray composition,
+ jobject vibration) {
auto hal = getHal<aidl::IVibrator>();
if (!hal) {
return;
@@ -451,65 +421,71 @@ static void vibratorPerformComposedEffect(JNIEnv* env, jclass, jobjectArray comp
}
}
-static jlong vibratorGetCapabilities(JNIEnv*, jclass) {
- if (auto hal = getHal<aidl::IVibrator>()) {
- int32_t cap = 0;
- if (!hal->call(&aidl::IVibrator::getCapabilities, &cap).isOk()) {
- return 0;
- }
- return cap;
+static jlong vibratorGetCapabilities(JNIEnv* env, jclass /* clazz */, jlong controllerPtr) {
+ vibrator::HalController* controller = reinterpret_cast<vibrator::HalController*>(controllerPtr);
+ if (controller == nullptr) {
+ ALOGE("vibratorGetCapabilities failed because controller was not initialized");
+ return 0;
}
-
- return 0;
+ auto result = controller->getCapabilities();
+ return result.isOk() ? static_cast<jlong>(result.value()) : 0;
}
-static void vibratorAlwaysOnEnable(JNIEnv* env, jclass, jlong id, jlong effect, jlong strength) {
- auto status = halCall(&aidl::IVibrator::alwaysOnEnable, id,
- static_cast<aidl::Effect>(effect), static_cast<aidl::EffectStrength>(strength));
- if (!status.isOk()) {
- ALOGE("vibratortAlwaysOnEnable command failed (%s).", status.toString8().string());
+static void vibratorAlwaysOnEnable(JNIEnv* env, jclass /* clazz */, jlong controllerPtr, jlong id,
+ jlong effect, jlong strength) {
+ vibrator::HalController* controller = reinterpret_cast<vibrator::HalController*>(controllerPtr);
+ if (controller == nullptr) {
+ ALOGE("vibratorAlwaysOnEnable failed because controller was not initialized");
+ return;
}
+ controller->alwaysOnEnable(static_cast<int32_t>(id), static_cast<aidl::Effect>(effect),
+ static_cast<aidl::EffectStrength>(strength));
}
-static void vibratorAlwaysOnDisable(JNIEnv* env, jclass, jlong id) {
- auto status = halCall(&aidl::IVibrator::alwaysOnDisable, id);
- if (!status.isOk()) {
- ALOGE("vibratorAlwaysOnDisable command failed (%s).", status.toString8().string());
+static void vibratorAlwaysOnDisable(JNIEnv* env, jclass /* clazz */, jlong controllerPtr,
+ jlong id) {
+ vibrator::HalController* controller = reinterpret_cast<vibrator::HalController*>(controllerPtr);
+ if (controller == nullptr) {
+ ALOGE("vibratorAlwaysOnDisable failed because controller was not initialized");
+ return;
}
+ controller->alwaysOnDisable(static_cast<int32_t>(id));
}
static const JNINativeMethod method_table[] = {
- {"vibratorExists", "()Z", (void*)vibratorExists},
- {"vibratorInit", "()V", (void*)vibratorInit},
+ {"vibratorInit", "()J", (void*)vibratorInit},
+ {"vibratorGetFinalizer", "()J", (void*)vibratorGetFinalizer},
+ {"vibratorExists", "(J)Z", (void*)vibratorExists},
{"vibratorOn", "(J)V", (void*)vibratorOn},
- {"vibratorOff", "()V", (void*)vibratorOff},
- {"vibratorSupportsAmplitudeControl", "()Z", (void*)vibratorSupportsAmplitudeControl},
- {"vibratorSetAmplitude", "(I)V", (void*)vibratorSetAmplitude},
+ {"vibratorOff", "(J)V", (void*)vibratorOff},
+ {"vibratorSetAmplitude", "(JI)V", (void*)vibratorSetAmplitude},
{"vibratorPerformEffect", "(JJLcom/android/server/VibratorService$Vibration;Z)J",
(void*)vibratorPerformEffect},
{"vibratorPerformComposedEffect",
"([Landroid/os/VibrationEffect$Composition$PrimitiveEffect;Lcom/android/server/"
"VibratorService$Vibration;)V",
(void*)vibratorPerformComposedEffect},
- {"vibratorGetSupportedEffects", "()[I", (void*)vibratorGetSupportedEffects},
- {"vibratorSupportsExternalControl", "()Z", (void*)vibratorSupportsExternalControl},
- {"vibratorSetExternalControl", "(Z)V", (void*)vibratorSetExternalControl},
- {"vibratorGetCapabilities", "()J", (void*)vibratorGetCapabilities},
- {"vibratorAlwaysOnEnable", "(JJJ)V", (void*)vibratorAlwaysOnEnable},
- {"vibratorAlwaysOnDisable", "(J)V", (void*)vibratorAlwaysOnDisable},
+ {"vibratorGetSupportedEffects", "(J)[I", (void*)vibratorGetSupportedEffects},
+ {"vibratorSetExternalControl", "(JZ)V", (void*)vibratorSetExternalControl},
+ {"vibratorGetCapabilities", "(J)J", (void*)vibratorGetCapabilities},
+ {"vibratorAlwaysOnEnable", "(JJJJ)V", (void*)vibratorAlwaysOnEnable},
+ {"vibratorAlwaysOnDisable", "(JJ)V", (void*)vibratorAlwaysOnDisable},
};
int register_android_server_VibratorService(JNIEnv *env) {
- sMethodIdOnComplete = GetMethodIDOrDie(env,
- FindClassOrDie(env, "com/android/server/VibratorService$Vibration"),
- "onComplete", "()V");
- jclass primitiveClass = FindClassOrDie(env,
- "android/os/VibrationEffect$Composition$PrimitiveEffect");
+ sMethodIdOnComplete =
+ GetMethodIDOrDie(env,
+ FindClassOrDie(env, "com/android/server/VibratorService$Vibration"),
+ "onComplete", "()V");
+
+ jclass primitiveClass =
+ FindClassOrDie(env, "android/os/VibrationEffect$Composition$PrimitiveEffect");
gPrimitiveClassInfo.id = GetFieldIDOrDie(env, primitiveClass, "id", "I");
gPrimitiveClassInfo.scale = GetFieldIDOrDie(env, primitiveClass, "scale", "F");
gPrimitiveClassInfo.delay = GetFieldIDOrDie(env, primitiveClass, "delay", "I");
- return jniRegisterNativeMethods(env, "com/android/server/VibratorService",
- method_table, NELEM(method_table));
+
+ return jniRegisterNativeMethods(env, "com/android/server/VibratorService", method_table,
+ NELEM(method_table));
}
-};
+}; // namespace android
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index 784366318319..0202c88009fd 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -710,9 +710,8 @@ std::chrono::nanoseconds NativeInputManager::notifyAnr(
jobject tokenObj = javaObjectForIBinder(env, token);
jstring reasonObj = env->NewStringUTF(reason.c_str());
- jlong newTimeout = env->CallLongMethod(mServiceObj,
- gServiceClassInfo.notifyANR, inputApplicationHandleObj, tokenObj,
- reasonObj);
+ jlong newTimeout = env->CallLongMethod(mServiceObj, gServiceClassInfo.notifyANR,
+ inputApplicationHandleObj, tokenObj, reasonObj);
if (checkAndClearExceptionFromCallback(env, "notifyANR")) {
newTimeout = 0; // abort dispatch
} else {
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index c11c4b2e25c1..97ae505b4fcf 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -121,9 +121,7 @@ import com.android.server.inputmethod.MultiClientInputMethodManagerService;
import com.android.server.integrity.AppIntegrityManagerService;
import com.android.server.lights.LightsService;
import com.android.server.location.LocationManagerService;
-import com.android.server.media.MediaResourceMonitorService;
import com.android.server.media.MediaRouterService;
-import com.android.server.media.MediaSessionService;
import com.android.server.media.projection.MediaProjectionManagerService;
import com.android.server.net.NetworkPolicyManagerService;
import com.android.server.net.NetworkStatsService;
@@ -312,6 +310,10 @@ public final class SystemServer {
"com.android.server.rollback.RollbackManagerService";
private static final String ALARM_MANAGER_SERVICE_CLASS =
"com.android.server.alarm.AlarmManagerService";
+ private static final String MEDIA_SESSION_SERVICE_CLASS =
+ "com.android.server.media.MediaSessionService";
+ private static final String MEDIA_RESOURCE_MONITOR_SERVICE_CLASS =
+ "com.android.server.media.MediaResourceMonitorService";
private static final String TETHERING_CONNECTOR_CLASS = "android.net.ITetheringConnector";
@@ -1893,7 +1895,7 @@ public final class SystemServer {
t.traceEnd();
t.traceBegin("StartMediaSessionService");
- mSystemServiceManager.startService(MediaSessionService.class);
+ mSystemServiceManager.startService(MEDIA_SESSION_SERVICE_CLASS);
t.traceEnd();
if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_HDMI_CEC)) {
@@ -1917,7 +1919,7 @@ public final class SystemServer {
if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_PICTURE_IN_PICTURE)) {
t.traceBegin("StartMediaResourceMonitor");
- mSystemServiceManager.startService(MediaResourceMonitorService.class);
+ mSystemServiceManager.startService(MEDIA_RESOURCE_MONITOR_SERVICE_CLASS);
t.traceEnd();
}
diff --git a/services/people/java/com/android/server/people/PeopleService.java b/services/people/java/com/android/server/people/PeopleService.java
index 37bf66491882..33317a38853e 100644
--- a/services/people/java/com/android/server/people/PeopleService.java
+++ b/services/people/java/com/android/server/people/PeopleService.java
@@ -19,6 +19,8 @@ package com.android.server.people;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
+import android.app.people.ConversationChannel;
+import android.app.people.IPeopleManager;
import android.app.prediction.AppPredictionContext;
import android.app.prediction.AppPredictionSessionId;
import android.app.prediction.AppTarget;
@@ -26,8 +28,11 @@ import android.app.prediction.AppTargetEvent;
import android.app.prediction.IPredictionCallback;
import android.content.Context;
import android.content.pm.ParceledListSlice;
+import android.os.Binder;
import android.os.CancellationSignal;
+import android.os.Process;
import android.os.RemoteException;
+import android.os.UserHandle;
import android.util.ArrayMap;
import android.util.Slog;
@@ -35,6 +40,7 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.server.SystemService;
import com.android.server.people.data.DataManager;
+import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
@@ -68,6 +74,7 @@ public class PeopleService extends SystemService {
@Override
public void onStart() {
+ publishBinderService(Context.PEOPLE_SERVICE, new BinderService());
publishLocalService(PeopleServiceInternal.class, new LocalService());
}
@@ -81,6 +88,38 @@ public class PeopleService extends SystemService {
mDataManager.onUserStopping(user.getUserIdentifier());
}
+ /**
+ * Enforces that only the system or root UID can make certain calls.
+ *
+ * @param message used as message if SecurityException is thrown
+ * @throws SecurityException if the caller is not system or root
+ */
+ private static void enforceSystemOrRoot(String message) {
+ int uid = Binder.getCallingUid();
+ if (!UserHandle.isSameApp(uid, Process.SYSTEM_UID) && uid != Process.ROOT_UID) {
+ throw new SecurityException("Only system may " + message);
+ }
+ }
+
+ private final class BinderService extends IPeopleManager.Stub {
+
+ @Override
+ public ParceledListSlice<ConversationChannel> getRecentConversations() {
+ enforceSystemOrRoot("get recent conversations");
+ return new ParceledListSlice<>(new ArrayList<>());
+ }
+
+ @Override
+ public void removeRecentConversation(String packageName, int userId, String shortcutId) {
+ enforceSystemOrRoot("remove a recent conversation");
+ }
+
+ @Override
+ public void removeAllRecentConversations() {
+ enforceSystemOrRoot("remove all recent conversations");
+ }
+ }
+
@VisibleForTesting
final class LocalService extends PeopleServiceInternal {
diff --git a/services/tests/PackageManagerComponentOverrideTests/src/com/android/server/pm/test/override/PackageManagerComponentLabelIconOverrideTest.kt b/services/tests/PackageManagerComponentOverrideTests/src/com/android/server/pm/test/override/PackageManagerComponentLabelIconOverrideTest.kt
index ecdb30f5e84b..09552082e4af 100644
--- a/services/tests/PackageManagerComponentOverrideTests/src/com/android/server/pm/test/override/PackageManagerComponentLabelIconOverrideTest.kt
+++ b/services/tests/PackageManagerComponentOverrideTests/src/com/android/server/pm/test/override/PackageManagerComponentLabelIconOverrideTest.kt
@@ -33,7 +33,6 @@ import com.android.server.pm.parsing.pkg.PackageImpl
import com.android.server.pm.parsing.pkg.ParsedPackage
import com.android.server.pm.permission.PermissionManagerServiceInternal
import com.android.server.pm.test.override.PackageManagerComponentLabelIconOverrideTest.Companion.Params.AppType
-import com.android.server.pm.test.override.R
import com.android.server.testutils.TestHandler
import com.android.server.testutils.mock
import com.android.server.testutils.mockThrowOnUnmocked
@@ -266,7 +265,7 @@ class PackageManagerComponentLabelIconOverrideTest {
.hideAsFinal()
private fun makePkgSetting(pkgName: String) = spy(PackageSetting(pkgName, null, File("/test"),
- File("/test"), null, null, null, null, 0, 0, 0, 0, null, null, null)) {
+ null, null, null, null, 0, 0, 0, 0, null, null, null)) {
this.pkgState.isUpdatedSystemApp = params.isUpdatedSystemApp
}
diff --git a/services/tests/PackageManagerServiceTests/host/Android.bp b/services/tests/PackageManagerServiceTests/host/Android.bp
index 41dfade1a09a..cffcdd8f94bd 100644
--- a/services/tests/PackageManagerServiceTests/host/Android.bp
+++ b/services/tests/PackageManagerServiceTests/host/Android.bp
@@ -25,17 +25,28 @@ java_test_host {
],
test_suites: ["general-tests"],
java_resources: [
- ":PackageManagerDummyAppVersion1",
- ":PackageManagerDummyAppVersion2",
- ":PackageManagerDummyAppVersion3",
- ":PackageManagerDummyAppVersion4",
- ":PackageManagerDummyAppOriginalOverride",
- ":PackageManagerServiceHostTestsResources",
- ]
+ ":PackageManagerTestAppStub",
+ ":PackageManagerTestAppVersion1",
+ ":PackageManagerTestAppVersion2",
+ ":PackageManagerTestAppVersion3",
+ ":PackageManagerTestAppVersion3Invalid",
+ ":PackageManagerTestAppVersion4",
+ ":PackageManagerTestAppOriginalOverride",
+ ],
}
-filegroup {
- name: "PackageManagerServiceHostTestsResources",
- srcs: [ "resources/*" ],
- path: "resources/"
+genrule {
+ name: "PackageManagerTestAppVersion3Invalid",
+ tools: [
+ "soong_zip",
+ "zipalign",
+ ],
+ srcs: [
+ ":PackageManagerTestAppVersion3",
+ ],
+ out: ["PackageManagerTestAppVersion3Invalid.apk"],
+ cmd: "mkdir -p $(genDir)/apk && unzip $(in) -d $(genDir)/apk" +
+ " && truncate -s 800 $(genDir)/apk/META-INF/CERT.RSA" +
+ " && $(location soong_zip) -o $(genDir)/temp.apk -L 0 -C $(genDir)/apk -D $(genDir)/apk" +
+ " && $(location zipalign) -f 4 $(genDir)/temp.apk $(out)",
}
diff --git a/services/tests/PackageManagerServiceTests/host/resources/PackageManagerDummyAppVersion3Invalid.apk b/services/tests/PackageManagerServiceTests/host/resources/PackageManagerDummyAppVersion3Invalid.apk
deleted file mode 100644
index 127886cf8e9e..000000000000
--- a/services/tests/PackageManagerServiceTests/host/resources/PackageManagerDummyAppVersion3Invalid.apk
+++ /dev/null
Binary files differ
diff --git a/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/HostUtils.kt b/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/HostUtils.kt
index 234fcf19062d..8dfefaf9750f 100644
--- a/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/HostUtils.kt
+++ b/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/HostUtils.kt
@@ -21,8 +21,9 @@ import com.android.tradefed.device.ITestDevice
import java.io.File
import java.io.FileOutputStream
-internal fun SystemPreparer.pushApk(file: String, partition: Partition) =
- pushResourceFile(file, HostUtils.makePathForApk(file, partition).toString())
+internal fun SystemPreparer.pushApk(javaResourceName: String, partition: Partition) =
+ pushResourceFile(javaResourceName, HostUtils.makePathForApk(javaResourceName, partition)
+ .toString())
internal fun SystemPreparer.deleteApkFolders(
partition: Partition,
@@ -58,4 +59,55 @@ internal object HostUtils {
}
return file
}
+
+ /**
+ * dumpsys package and therefore device.getAppPackageInfo doesn't work immediately after reboot,
+ * so the following methods parse the package dump directly to see if the path matches.
+ */
+ fun getCodePaths(device: ITestDevice, pkgName: String) =
+ device.executeShellCommand("pm dump $pkgName")
+ .lineSequence()
+ .map(String::trim)
+ .filter { it.startsWith("codePath=") }
+ .map { it.removePrefix("codePath=") }
+ .toList()
+
+ private fun userIdLineSequence(device: ITestDevice, pkgName: String) =
+ device.executeShellCommand("pm dump $pkgName")
+ .lineSequence()
+ .dropWhile { !it.startsWith("Packages:") }
+ .takeWhile {
+ !it.startsWith("Hidden system packages:") &&
+ !it.startsWith("Queries:")
+ }
+ .map(String::trim)
+ .filter { it.startsWith("User ") }
+
+ fun getUserIdToPkgEnabledState(device: ITestDevice, pkgName: String) =
+ userIdLineSequence(device, pkgName).associate {
+ val userId = it.removePrefix("User ")
+ .takeWhile(Char::isDigit)
+ .toInt()
+ val enabled = it.substringAfter("enabled=")
+ .takeWhile(Char::isDigit)
+ .toInt()
+ .let {
+ when (it) {
+ 0, 1 -> true
+ else -> false
+ }
+ }
+ userId to enabled
+ }
+
+ fun getUserIdToPkgInstalledState(device: ITestDevice, pkgName: String) =
+ userIdLineSequence(device, pkgName).associate {
+ val userId = it.removePrefix("User ")
+ .takeWhile(Char::isDigit)
+ .toInt()
+ val installed = it.substringAfter("installed=")
+ .takeWhile { !it.isWhitespace() }
+ .toBoolean()
+ userId to installed
+ }
}
diff --git a/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/InvalidNewSystemAppTest.kt b/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/InvalidNewSystemAppTest.kt
index 39b40d8d3195..b7d135991ccd 100644
--- a/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/InvalidNewSystemAppTest.kt
+++ b/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/InvalidNewSystemAppTest.kt
@@ -33,11 +33,11 @@ import org.junit.runner.RunWith
class InvalidNewSystemAppTest : BaseHostJUnit4Test() {
companion object {
- private const val TEST_PKG_NAME = "com.android.server.pm.test.dummy_app"
- private const val VERSION_ONE = "PackageManagerDummyAppVersion1.apk"
- private const val VERSION_TWO = "PackageManagerDummyAppVersion2.apk"
- private const val VERSION_THREE_INVALID = "PackageManagerDummyAppVersion3Invalid.apk"
- private const val VERSION_FOUR = "PackageManagerDummyAppVersion4.apk"
+ private const val TEST_PKG_NAME = "com.android.server.pm.test.test_app"
+ private const val VERSION_ONE = "PackageManagerTestAppVersion1.apk"
+ private const val VERSION_TWO = "PackageManagerTestAppVersion2.apk"
+ private const val VERSION_THREE_INVALID = "PackageManagerTestAppVersion3Invalid.apk"
+ private const val VERSION_FOUR = "PackageManagerTestAppVersion4.apk"
@get:ClassRule
val deviceRebootRule = SystemPreparer.TestRuleDelegate(true)
@@ -49,14 +49,14 @@ class InvalidNewSystemAppTest : BaseHostJUnit4Test() {
@get:Rule
val rules = RuleChain.outerRule(tempFolder).around(preparer)!!
- private val filePath = HostUtils.makePathForApk("PackageManagerDummyApp.apk", Partition.PRODUCT)
+ private val filePath = HostUtils.makePathForApk("PackageManagerTestApp.apk", Partition.PRODUCT)
@Before
@After
fun removeApk() {
device.uninstallPackage(TEST_PKG_NAME)
- device.deleteFile(filePath.parent.toString())
- device.reboot()
+ preparer.deleteFile(filePath.parent.toString())
+ .reboot()
}
@Test
diff --git a/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/OriginalPackageMigrationTest.kt b/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/OriginalPackageMigrationTest.kt
index fb0348c3146b..4ae3ca5f7263 100644
--- a/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/OriginalPackageMigrationTest.kt
+++ b/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/OriginalPackageMigrationTest.kt
@@ -33,11 +33,11 @@ import org.junit.runner.RunWith
class OriginalPackageMigrationTest : BaseHostJUnit4Test() {
companion object {
- private const val TEST_PKG_NAME = "com.android.server.pm.test.dummy_app"
- private const val VERSION_ONE = "PackageManagerDummyAppVersion1.apk"
- private const val VERSION_TWO = "PackageManagerDummyAppVersion2.apk"
- private const val VERSION_THREE = "PackageManagerDummyAppVersion3.apk"
- private const val NEW_PKG = "PackageManagerDummyAppOriginalOverride.apk"
+ private const val TEST_PKG_NAME = "com.android.server.pm.test.test_app"
+ private const val VERSION_ONE = "PackageManagerTestAppVersion1.apk"
+ private const val VERSION_TWO = "PackageManagerTestAppVersion2.apk"
+ private const val VERSION_THREE = "PackageManagerTestAppVersion3.apk"
+ private const val NEW_PKG = "PackageManagerTestAppOriginalOverride.apk"
@get:ClassRule
val deviceRebootRule = SystemPreparer.TestRuleDelegate(true)
@@ -55,6 +55,7 @@ class OriginalPackageMigrationTest : BaseHostJUnit4Test() {
fun deleteApkFolders() {
preparer.deleteApkFolders(Partition.SYSTEM, VERSION_ONE, VERSION_TWO, VERSION_THREE,
NEW_PKG)
+ .reboot()
}
@Test
@@ -99,9 +100,7 @@ class OriginalPackageMigrationTest : BaseHostJUnit4Test() {
}
private fun assertCodePath(apk: String) {
- // dumpsys package and therefore device.getAppPackageInfo doesn't work here for some reason,
- // so parse the package dump directly to see if the path matches.
- assertThat(device.executeShellCommand("pm dump $TEST_PKG_NAME"))
- .contains(HostUtils.makePathForApk(apk, Partition.SYSTEM).parent.toString())
+ assertThat(HostUtils.getCodePaths(device, TEST_PKG_NAME))
+ .containsExactly(HostUtils.makePathForApk(apk, Partition.SYSTEM).parent.toString())
}
}
diff --git a/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/SystemStubMultiUserDisableUninstallTest.kt b/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/SystemStubMultiUserDisableUninstallTest.kt
new file mode 100644
index 000000000000..bc478b0e2c90
--- /dev/null
+++ b/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/SystemStubMultiUserDisableUninstallTest.kt
@@ -0,0 +1,650 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.pm.test
+
+import com.android.internal.util.test.SystemPreparer
+import com.android.tradefed.device.ITestDevice
+import com.android.tradefed.device.UserInfo
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner
+import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test
+import com.google.common.truth.Truth.assertThat
+import org.junit.AfterClass
+import org.junit.Before
+import org.junit.ClassRule
+import org.junit.Rule
+import org.junit.Test
+import org.junit.rules.RuleChain
+import org.junit.rules.TemporaryFolder
+import org.junit.runner.RunWith
+import java.io.File
+import java.util.zip.GZIPOutputStream
+
+@RunWith(DeviceJUnit4ClassRunner::class)
+class SystemStubMultiUserDisableUninstallTest : BaseHostJUnit4Test() {
+
+ companion object {
+ private const val TEST_PKG_NAME = "com.android.server.pm.test.test_app"
+ private const val VERSION_STUB = "PackageManagerTestAppStub.apk"
+ private const val VERSION_ONE = "PackageManagerTestAppVersion1.apk"
+
+ /**
+ * How many total users on device to test, including primary. This will clean up any
+ * users created specifically for this test.
+ */
+ private const val USER_COUNT = 3
+
+ /**
+ * Whether to manually reset state at each test method without rebooting
+ * for faster iterative development.
+ */
+ private const val DEBUG_NO_REBOOT = false
+
+ @get:ClassRule
+ val deviceRebootRule = SystemPreparer.TestRuleDelegate(true)
+
+ private val parentClassName = SystemStubMultiUserDisableUninstallTest::class.java.simpleName
+
+ private val deviceCompressedFile =
+ HostUtils.makePathForApk("$parentClassName.apk", Partition.PRODUCT).parent
+ .resolve("$parentClassName.apk.gz")
+
+ private val stubFile =
+ HostUtils.makePathForApk("$parentClassName-Stub.apk", Partition.PRODUCT)
+
+ private val secondaryUsers = mutableListOf<Int>()
+ private val usersToRemove = mutableListOf<Int>()
+ private var savedDevice: ITestDevice? = null
+ private var savedPreparer: SystemPreparer? = null
+
+ private fun setUpUsers(device: ITestDevice) {
+ if (this.savedDevice != null) return
+ this.savedDevice = device
+ secondaryUsers.clear()
+ secondaryUsers += device.userInfos.values.map(UserInfo::userId).filterNot { it == 0 }
+ while (secondaryUsers.size < USER_COUNT) {
+ secondaryUsers += device.createUser(parentClassName + secondaryUsers.size)
+ .also { usersToRemove += it }
+ }
+ }
+
+ @JvmStatic
+ @AfterClass
+ fun cleanUp() {
+ savedDevice ?: return
+
+ usersToRemove.forEach {
+ savedDevice?.removeUser(it)
+ }
+
+ savedDevice?.uninstallPackage(TEST_PKG_NAME)
+ savedDevice?.deleteFile(stubFile.parent.toString())
+ savedDevice?.deleteFile(deviceCompressedFile.parent.toString())
+ savedDevice?.reboot()
+ savedDevice = null
+
+ if (DEBUG_NO_REBOOT) {
+ savedPreparer?.after()
+ savedPreparer = null
+ }
+ }
+ }
+
+ private val tempFolder = TemporaryFolder()
+ private val preparer: SystemPreparer = SystemPreparer(tempFolder,
+ SystemPreparer.RebootStrategy.START_STOP, deviceRebootRule) { this.device }
+
+ @get:Rule
+ val rules = RuleChain.outerRule(tempFolder).let {
+ if (DEBUG_NO_REBOOT) {
+ it!!
+ } else {
+ it.around(preparer)!!
+ }
+ }
+
+ private var hostCompressedFile: File? = null
+
+ private val previousCodePaths = mutableListOf<String>()
+
+ @Before
+ fun ensureUserAndCompressStubAndInstall() {
+ setUpUsers(device)
+
+ val initialized = hostCompressedFile != null
+ if (!initialized) {
+ hostCompressedFile = tempFolder.newFile()
+ hostCompressedFile!!.outputStream().use {
+ javaClass.classLoader
+ .getResource(VERSION_ONE)!!
+ .openStream()
+ .use { input ->
+ GZIPOutputStream(it).use { output ->
+ input.copyTo(output)
+ }
+ }
+ }
+ }
+
+ device.uninstallPackage(TEST_PKG_NAME)
+
+ if (!initialized || !DEBUG_NO_REBOOT) {
+ savedPreparer = preparer
+ preparer.pushResourceFile(VERSION_STUB, stubFile.toString())
+ .pushFile(hostCompressedFile, deviceCompressedFile.toString())
+ .reboot()
+ }
+
+ // This test forces the state to installed/enabled for all users,
+ // since it only tests the uninstall/disable side.
+ installExisting(User.PRIMARY)
+ installExisting(User.SECONDARY)
+
+ ensureEnabled()
+
+ // Ensure data app isn't re-installed multiple times by comparing against the original path
+ val codePath = HostUtils.getCodePaths(device, TEST_PKG_NAME).first()
+ assertThat(codePath).contains("/data/app")
+ assertThat(codePath).contains(TEST_PKG_NAME)
+
+ previousCodePaths.clear()
+ previousCodePaths += codePath
+
+ assertState(
+ primaryInstalled = true, primaryEnabled = true,
+ secondaryInstalled = true, secondaryEnabled = true,
+ codePaths = listOf(CodePath.SAME, CodePath.SYSTEM)
+ )
+ }
+
+ @Test
+ fun disablePrimaryFirstAndUninstall() {
+ toggleEnabled(false, User.PRIMARY)
+
+ assertState(
+ primaryInstalled = true, primaryEnabled = false,
+ secondaryInstalled = true, secondaryEnabled = true,
+ codePaths = listOf(CodePath.SAME, CodePath.SYSTEM)
+ )
+
+ toggleEnabled(false, User.SECONDARY)
+
+ assertState(
+ primaryInstalled = true, primaryEnabled = false,
+ secondaryInstalled = true, secondaryEnabled = false,
+ codePaths = listOf(CodePath.SAME, CodePath.SYSTEM)
+ )
+
+ device.uninstallPackage(TEST_PKG_NAME)
+
+ assertState(
+ primaryInstalled = true, primaryEnabled = false,
+ secondaryInstalled = true, secondaryEnabled = false,
+ codePaths = listOf(CodePath.SYSTEM)
+ )
+ }
+
+ @Test
+ fun disableSecondaryFirstAndUninstall() {
+ toggleEnabled(false, User.SECONDARY)
+
+ assertState(
+ primaryInstalled = true, primaryEnabled = true,
+ secondaryInstalled = true, secondaryEnabled = false,
+ codePaths = listOf(CodePath.SAME, CodePath.SYSTEM)
+ )
+
+ toggleEnabled(false, User.PRIMARY)
+
+ assertState(
+ primaryInstalled = true, primaryEnabled = false,
+ secondaryInstalled = true, secondaryEnabled = false,
+ codePaths = listOf(CodePath.SAME, CodePath.SYSTEM)
+ )
+
+ device.uninstallPackage(TEST_PKG_NAME)
+
+ assertState(
+ primaryInstalled = true, primaryEnabled = false,
+ secondaryInstalled = true, secondaryEnabled = false,
+ codePaths = listOf(CodePath.SYSTEM)
+ )
+ }
+
+ @Test
+ fun disabledUninstalledEnablePrimaryFirst() {
+ toggleEnabled(false, User.PRIMARY)
+ toggleEnabled(false, User.SECONDARY)
+ device.uninstallPackage(TEST_PKG_NAME)
+
+ toggleEnabled(true, User.PRIMARY)
+
+ assertState(
+ primaryInstalled = true, primaryEnabled = true,
+ secondaryInstalled = true, secondaryEnabled = false,
+ codePaths = listOf(CodePath.DIFFERENT, CodePath.SYSTEM)
+ )
+
+ toggleEnabled(true, User.SECONDARY)
+
+ assertState(
+ primaryInstalled = true, primaryEnabled = true,
+ secondaryInstalled = true, secondaryEnabled = true,
+ codePaths = listOf(CodePath.SAME, CodePath.SYSTEM)
+ )
+ }
+
+ @Test
+ fun disabledUninstalledEnableSecondaryFirst() {
+ toggleEnabled(false, User.PRIMARY)
+ toggleEnabled(false, User.SECONDARY)
+ device.uninstallPackage(TEST_PKG_NAME)
+
+ toggleEnabled(true, User.SECONDARY)
+
+ assertState(
+ primaryInstalled = true, primaryEnabled = false,
+ secondaryInstalled = true, secondaryEnabled = true,
+ codePaths = listOf(CodePath.DIFFERENT, CodePath.SYSTEM)
+ )
+
+ toggleEnabled(true, User.PRIMARY)
+
+ assertState(
+ primaryInstalled = true, primaryEnabled = true,
+ secondaryInstalled = true, secondaryEnabled = true,
+ codePaths = listOf(CodePath.SAME, CodePath.SYSTEM)
+ )
+ }
+
+ @Test
+ fun uninstallPrimaryFirstByUserAndInstallExistingPrimaryFirst() {
+ uninstall(User.PRIMARY)
+
+ assertState(
+ primaryInstalled = false, primaryEnabled = true,
+ secondaryInstalled = true, secondaryEnabled = true,
+ codePaths = listOf(CodePath.DIFFERENT, CodePath.SYSTEM)
+ )
+
+ uninstall(User.SECONDARY)
+
+ assertState(
+ primaryInstalled = false, primaryEnabled = true,
+ secondaryInstalled = false, secondaryEnabled = true,
+ codePaths = listOf(CodePath.DIFFERENT, CodePath.SYSTEM)
+ )
+
+ installExisting(User.PRIMARY)
+
+ assertState(
+ primaryInstalled = true, primaryEnabled = true,
+ secondaryInstalled = false, secondaryEnabled = true,
+ codePaths = listOf(CodePath.SAME, CodePath.SYSTEM)
+ )
+
+ installExisting(User.SECONDARY)
+
+ assertState(
+ primaryInstalled = true, primaryEnabled = true,
+ secondaryInstalled = true, secondaryEnabled = true,
+ codePaths = listOf(CodePath.SAME, CodePath.SYSTEM)
+ )
+ }
+
+ @Test
+ fun uninstallSecondaryFirstByUserAndInstallExistingSecondaryFirst() {
+ uninstall(User.PRIMARY)
+
+ assertState(
+ primaryInstalled = false, primaryEnabled = true,
+ secondaryInstalled = true, secondaryEnabled = true,
+ codePaths = listOf(CodePath.DIFFERENT, CodePath.SYSTEM)
+ )
+
+ uninstall(User.SECONDARY)
+
+ assertState(
+ primaryInstalled = false, primaryEnabled = true,
+ secondaryInstalled = false, secondaryEnabled = true,
+ codePaths = listOf(CodePath.DIFFERENT, CodePath.SYSTEM)
+ )
+
+ installExisting(User.SECONDARY)
+
+ assertState(
+ primaryInstalled = false, primaryEnabled = true,
+ secondaryInstalled = true, secondaryEnabled = true,
+ codePaths = listOf(CodePath.SAME, CodePath.SYSTEM)
+ )
+
+ installExisting(User.PRIMARY)
+
+ assertState(
+ primaryInstalled = true, primaryEnabled = true,
+ secondaryInstalled = true, secondaryEnabled = true,
+ codePaths = listOf(CodePath.SAME, CodePath.SYSTEM)
+ )
+ }
+
+ @Test
+ fun uninstallUpdatesAndEnablePrimaryFirst() {
+ device.executeShellCommand("pm uninstall-system-updates $TEST_PKG_NAME")
+
+ // Uninstall-system-updates always disables system user 0
+ // TODO: Is this intentional? There is no user argument for this command.
+ assertState(
+ primaryInstalled = true, primaryEnabled = false,
+ secondaryInstalled = true, secondaryEnabled = true,
+ // If any user is enabled when uninstalling updates, /data is re-uncompressed
+ codePaths = listOf(CodePath.DIFFERENT, CodePath.SYSTEM)
+ )
+
+ toggleEnabled(true, User.PRIMARY)
+
+ assertState(
+ primaryInstalled = true, primaryEnabled = true,
+ secondaryInstalled = true, secondaryEnabled = true,
+ codePaths = listOf(CodePath.SAME, CodePath.SYSTEM)
+ )
+
+ // Test enabling secondary to ensure path does not change, even though it's already enabled
+ toggleEnabled(true, User.SECONDARY)
+
+ assertState(
+ primaryInstalled = true, primaryEnabled = true,
+ secondaryInstalled = true, secondaryEnabled = true,
+ codePaths = listOf(CodePath.SAME, CodePath.SYSTEM)
+ )
+ }
+
+ @Test
+ fun uninstallUpdatesAndEnableSecondaryFirst() {
+ device.executeShellCommand("pm uninstall-system-updates $TEST_PKG_NAME")
+
+ // Uninstall-system-updates always disables system user 0
+ assertState(
+ primaryInstalled = true, primaryEnabled = false,
+ secondaryInstalled = true, secondaryEnabled = true,
+ // If any user is enabled when uninstalling updates, /data is re-uncompressed
+ codePaths = listOf(CodePath.DIFFERENT, CodePath.SYSTEM)
+ )
+
+ toggleEnabled(true, User.SECONDARY)
+
+ assertState(
+ primaryInstalled = true, primaryEnabled = false,
+ secondaryInstalled = true, secondaryEnabled = true,
+ codePaths = listOf(CodePath.SAME, CodePath.SYSTEM)
+ )
+
+ toggleEnabled(true, User.PRIMARY)
+
+ assertState(
+ primaryInstalled = true, primaryEnabled = true,
+ secondaryInstalled = true, secondaryEnabled = true,
+ codePaths = listOf(CodePath.SAME, CodePath.SYSTEM)
+ )
+ }
+
+ @Test
+ fun disabledUninstallUpdatesAndEnablePrimaryFirst() {
+ toggleEnabled(false, User.PRIMARY)
+ toggleEnabled(false, User.SECONDARY)
+
+ device.executeShellCommand("pm uninstall-system-updates $TEST_PKG_NAME")
+
+ assertState(
+ primaryInstalled = true, primaryEnabled = false,
+ secondaryInstalled = true, secondaryEnabled = false,
+ codePaths = listOf(CodePath.SYSTEM)
+ )
+
+ toggleEnabled(true, User.PRIMARY)
+
+ assertState(
+ primaryInstalled = true, primaryEnabled = true,
+ secondaryInstalled = true, secondaryEnabled = false,
+ codePaths = listOf(CodePath.DIFFERENT, CodePath.SYSTEM)
+ )
+
+ toggleEnabled(true, User.SECONDARY)
+
+ assertState(
+ primaryInstalled = true, primaryEnabled = true,
+ secondaryInstalled = true, secondaryEnabled = true,
+ codePaths = listOf(CodePath.SAME, CodePath.SYSTEM)
+ )
+ }
+
+ @Test
+ fun disabledUninstallUpdatesAndEnableSecondaryFirst() {
+ toggleEnabled(false, User.PRIMARY)
+ toggleEnabled(false, User.SECONDARY)
+
+ device.executeShellCommand("pm uninstall-system-updates $TEST_PKG_NAME")
+
+ assertState(
+ primaryInstalled = true, primaryEnabled = false,
+ secondaryInstalled = true, secondaryEnabled = false,
+ codePaths = listOf(CodePath.SYSTEM)
+ )
+
+ toggleEnabled(true, User.SECONDARY)
+
+ assertState(
+ primaryInstalled = true, primaryEnabled = false,
+ secondaryInstalled = true, secondaryEnabled = true,
+ codePaths = listOf(CodePath.DIFFERENT, CodePath.SYSTEM)
+ )
+
+ toggleEnabled(true, User.PRIMARY)
+
+ assertState(
+ primaryInstalled = true, primaryEnabled = true,
+ secondaryInstalled = true, secondaryEnabled = true,
+ codePaths = listOf(CodePath.SAME, CodePath.SYSTEM)
+ )
+ }
+
+ @Test
+ fun uninstalledUninstallUpdatesAndEnablePrimaryFirst() {
+ uninstall(User.PRIMARY)
+ uninstall(User.SECONDARY)
+
+ device.executeShellCommand("pm uninstall-system-updates $TEST_PKG_NAME")
+
+ // Uninstall-system-updates always disables system user 0
+ assertState(
+ primaryInstalled = false, primaryEnabled = false,
+ secondaryInstalled = false, secondaryEnabled = true,
+ codePaths = listOf(CodePath.SYSTEM)
+ )
+
+ toggleEnabled(true, User.PRIMARY)
+
+ assertState(
+ primaryInstalled = false, primaryEnabled = true,
+ secondaryInstalled = false, secondaryEnabled = true,
+ codePaths = listOf(CodePath.DIFFERENT, CodePath.SYSTEM)
+ )
+
+ toggleEnabled(true, User.SECONDARY)
+
+ assertState(
+ primaryInstalled = false, primaryEnabled = true,
+ secondaryInstalled = false, secondaryEnabled = true,
+ codePaths = listOf(CodePath.SAME, CodePath.SYSTEM)
+ )
+ }
+
+ @Test
+ fun uninstalledUninstallUpdatesAndEnableSecondaryFirst() {
+ uninstall(User.PRIMARY)
+ uninstall(User.SECONDARY)
+
+ device.executeShellCommand("pm uninstall-system-updates $TEST_PKG_NAME")
+
+ // Uninstall-system-updates always disables system user 0
+ assertState(
+ primaryInstalled = false, primaryEnabled = false,
+ secondaryInstalled = false, secondaryEnabled = true,
+ codePaths = listOf(CodePath.SYSTEM)
+ )
+
+ toggleEnabled(true, User.SECONDARY)
+
+ assertState(
+ primaryInstalled = false, primaryEnabled = false,
+ secondaryInstalled = false, secondaryEnabled = true,
+ codePaths = listOf(CodePath.DIFFERENT, CodePath.SYSTEM)
+ )
+
+ toggleEnabled(true, User.PRIMARY)
+
+ assertState(
+ primaryInstalled = false, primaryEnabled = true,
+ secondaryInstalled = false, secondaryEnabled = true,
+ codePaths = listOf(CodePath.SAME, CodePath.SYSTEM)
+ )
+ }
+
+ private fun ensureEnabled() {
+ toggleEnabled(true, User.PRIMARY)
+ toggleEnabled(true, User.SECONDARY)
+
+ assertThat(HostUtils.getUserIdToPkgEnabledState(device, TEST_PKG_NAME).all { it.value })
+ .isTrue()
+ }
+
+ private fun toggleEnabled(enabled: Boolean, user: User, pkgName: String = TEST_PKG_NAME) {
+ val command = if (enabled) "enable" else "disable"
+ @Suppress("UNUSED_VARIABLE") val exhaust: Any = when (user) {
+ User.PRIMARY -> {
+ device.executeShellCommand("pm $command --user 0 $pkgName")
+ }
+ User.SECONDARY -> {
+ secondaryUsers.forEach {
+ device.executeShellCommand("pm $command --user $it $pkgName")
+ }
+ }
+ }
+ }
+
+ private fun uninstall(user: User, pkgName: String = TEST_PKG_NAME) {
+ @Suppress("UNUSED_VARIABLE") val exhaust: Any = when (user) {
+ User.PRIMARY -> {
+ device.executeShellCommand("pm uninstall --user 0 $pkgName")
+ }
+ User.SECONDARY -> {
+ secondaryUsers.forEach {
+ device.executeShellCommand("pm uninstall --user $it $pkgName")
+ }
+ }
+ }
+ }
+
+ private fun installExisting(user: User, pkgName: String = TEST_PKG_NAME) {
+ @Suppress("UNUSED_VARIABLE") val exhaust: Any = when (user) {
+ User.PRIMARY -> {
+ device.executeShellCommand("pm install-existing --user 0 $pkgName")
+ }
+ User.SECONDARY -> {
+ secondaryUsers.forEach {
+ device.executeShellCommand("pm install-existing --user $it $pkgName")
+ }
+ }
+ }
+ }
+
+ private fun assertState(
+ primaryInstalled: Boolean,
+ primaryEnabled: Boolean,
+ secondaryInstalled: Boolean,
+ secondaryEnabled: Boolean,
+ codePaths: List<CodePath>
+ ) {
+ HostUtils.getUserIdToPkgInstalledState(device, TEST_PKG_NAME)
+ .forEach { (userId, installed) ->
+ if (userId == 0) {
+ assertThat(installed).isEqualTo(primaryInstalled)
+ } else {
+ assertThat(installed).isEqualTo(secondaryInstalled)
+ }
+ }
+
+ HostUtils.getUserIdToPkgEnabledState(device, TEST_PKG_NAME)
+ .forEach { (userId, enabled) ->
+ if (userId == 0) {
+ assertThat(enabled).isEqualTo(primaryEnabled)
+ } else {
+ assertThat(enabled).isEqualTo(secondaryEnabled)
+ }
+ }
+
+ assertCodePaths(codePaths.first(), codePaths.getOrNull(1))
+ }
+
+ private fun assertCodePaths(firstCodePath: CodePath, secondCodePath: CodePath? = null) {
+ val codePaths = HostUtils.getCodePaths(device, TEST_PKG_NAME)
+ assertThat(codePaths).hasSize(listOfNotNull(firstCodePath, secondCodePath).size)
+
+ when (firstCodePath) {
+ CodePath.SAME -> {
+ assertThat(codePaths[0]).contains("/data/app")
+ assertThat(codePaths[0]).contains(TEST_PKG_NAME)
+ assertThat(codePaths[0]).isEqualTo(previousCodePaths.last())
+ }
+ CodePath.DIFFERENT -> {
+ assertThat(codePaths[0]).contains("/data/app")
+ assertThat(codePaths[0]).contains(TEST_PKG_NAME)
+ assertThat(previousCodePaths).doesNotContain(codePaths[0])
+ previousCodePaths.add(codePaths[0])
+ }
+ CodePath.SYSTEM -> assertThat(codePaths[0]).isEqualTo(stubFile.parent.toString())
+ }
+
+ when (secondCodePath) {
+ CodePath.SAME, CodePath.DIFFERENT ->
+ throw AssertionError("secondDataPath cannot be a data path")
+ CodePath.SYSTEM -> assertThat(codePaths[1]).isEqualTo(stubFile.parent.toString())
+ }
+ }
+
+ enum class User {
+ /** The primary system user 0 */
+ PRIMARY,
+
+ /**
+ * All other users on the device that are not 0. This is split into an enum so that all
+ * methods that handle secondary act on all non-system users. Some behaviors only occur
+ * if a package state is marked for all non-primary users on the device, which can be
+ * more than just 1.
+ */
+ SECONDARY
+ }
+
+ enum class CodePath {
+ /** The data code path hasn't changed */
+ SAME,
+
+ /** New data code path */
+ DIFFERENT,
+
+ /** The static system code path */
+ SYSTEM
+ }
+}
diff --git a/services/tests/PackageManagerServiceTests/host/test-apps/Android.bp b/services/tests/PackageManagerServiceTests/host/test-apps/Android.bp
index c9b29275a731..4a3076e4736a 100644
--- a/services/tests/PackageManagerServiceTests/host/test-apps/Android.bp
+++ b/services/tests/PackageManagerServiceTests/host/test-apps/Android.bp
@@ -13,26 +13,32 @@
// limitations under the License.
android_test_helper_app {
- name: "PackageManagerDummyAppVersion1",
+ name: "PackageManagerTestAppStub",
+ manifest: "AndroidManifestVersion1.xml",
+ srcs: []
+}
+
+android_test_helper_app {
+ name: "PackageManagerTestAppVersion1",
manifest: "AndroidManifestVersion1.xml"
}
android_test_helper_app {
- name: "PackageManagerDummyAppVersion2",
+ name: "PackageManagerTestAppVersion2",
manifest: "AndroidManifestVersion2.xml"
}
android_test_helper_app {
- name: "PackageManagerDummyAppVersion3",
+ name: "PackageManagerTestAppVersion3",
manifest: "AndroidManifestVersion3.xml"
}
android_test_helper_app {
- name: "PackageManagerDummyAppVersion4",
+ name: "PackageManagerTestAppVersion4",
manifest: "AndroidManifestVersion4.xml"
}
android_test_helper_app {
- name: "PackageManagerDummyAppOriginalOverride",
+ name: "PackageManagerTestAppOriginalOverride",
manifest: "AndroidManifestOriginalOverride.xml"
}
diff --git a/services/tests/PackageManagerServiceTests/host/test-apps/AndroidManifestOriginalOverride.xml b/services/tests/PackageManagerServiceTests/host/test-apps/AndroidManifestOriginalOverride.xml
index f16e1bc8a927..cba580e44065 100644
--- a/services/tests/PackageManagerServiceTests/host/test-apps/AndroidManifestOriginalOverride.xml
+++ b/services/tests/PackageManagerServiceTests/host/test-apps/AndroidManifestOriginalOverride.xml
@@ -16,10 +16,10 @@
-->
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.server.pm.test.dummy_app.override"
+ package="com.android.server.pm.test.test_app.override"
android:versionCode="2"
>
- <original-package android:name="com.android.server.pm.test.dummy_app"/>
+ <original-package android:name="com.android.server.pm.test.test_app"/>
</manifest>
diff --git a/services/tests/PackageManagerServiceTests/host/test-apps/AndroidManifestVersion1.xml b/services/tests/PackageManagerServiceTests/host/test-apps/AndroidManifestVersion1.xml
index b492a31349fc..efc7372a177c 100644
--- a/services/tests/PackageManagerServiceTests/host/test-apps/AndroidManifestVersion1.xml
+++ b/services/tests/PackageManagerServiceTests/host/test-apps/AndroidManifestVersion1.xml
@@ -16,12 +16,12 @@
-->
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.server.pm.test.dummy_app"
+ package="com.android.server.pm.test.test_app"
android:versionCode="1"
>
<permission
- android:name="com.android.server.pm.test.dummy_app.TEST_PERMISSION"
+ android:name="com.android.server.pm.test.test_app.TEST_PERMISSION"
android:protectionLevel="normal"
/>
diff --git a/services/tests/PackageManagerServiceTests/host/test-apps/AndroidManifestVersion2.xml b/services/tests/PackageManagerServiceTests/host/test-apps/AndroidManifestVersion2.xml
index 25e9f8eb2a67..620054c5dd57 100644
--- a/services/tests/PackageManagerServiceTests/host/test-apps/AndroidManifestVersion2.xml
+++ b/services/tests/PackageManagerServiceTests/host/test-apps/AndroidManifestVersion2.xml
@@ -16,12 +16,12 @@
-->
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.server.pm.test.dummy_app"
+ package="com.android.server.pm.test.test_app"
android:versionCode="2"
>
<permission
- android:name="com.android.server.pm.test.dummy_app.TEST_PERMISSION"
+ android:name="com.android.server.pm.test.test_app.TEST_PERMISSION"
android:protectionLevel="normal"
/>
diff --git a/services/tests/PackageManagerServiceTests/host/test-apps/AndroidManifestVersion3.xml b/services/tests/PackageManagerServiceTests/host/test-apps/AndroidManifestVersion3.xml
index 935f5e62f508..1997771783dd 100644
--- a/services/tests/PackageManagerServiceTests/host/test-apps/AndroidManifestVersion3.xml
+++ b/services/tests/PackageManagerServiceTests/host/test-apps/AndroidManifestVersion3.xml
@@ -16,12 +16,12 @@
-->
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.server.pm.test.dummy_app"
+ package="com.android.server.pm.test.test_app"
android:versionCode="3"
>
<permission
- android:name="com.android.server.pm.test.dummy_app.TEST_PERMISSION"
+ android:name="com.android.server.pm.test.test_app.TEST_PERMISSION"
android:protectionLevel="normal"
/>
diff --git a/services/tests/PackageManagerServiceTests/host/test-apps/AndroidManifestVersion4.xml b/services/tests/PackageManagerServiceTests/host/test-apps/AndroidManifestVersion4.xml
index d0643cbb2aeb..d6ade0304189 100644
--- a/services/tests/PackageManagerServiceTests/host/test-apps/AndroidManifestVersion4.xml
+++ b/services/tests/PackageManagerServiceTests/host/test-apps/AndroidManifestVersion4.xml
@@ -16,12 +16,12 @@
-->
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.server.pm.test.dummy_app"
+ package="com.android.server.pm.test.test_app"
android:versionCode="4"
>
<permission
- android:name="com.android.server.pm.test.dummy_app.TEST_PERMISSION"
+ android:name="com.android.server.pm.test.test_app.TEST_PERMISSION"
android:protectionLevel="normal"
/>
diff --git a/services/tests/mockingservicestests/AndroidManifest.xml b/services/tests/mockingservicestests/AndroidManifest.xml
index 44eb8285c7db..a398961db4c3 100644
--- a/services/tests/mockingservicestests/AndroidManifest.xml
+++ b/services/tests/mockingservicestests/AndroidManifest.xml
@@ -17,6 +17,8 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.frameworks.mockingservicestests">
+ <uses-sdk android:targetSdkVersion="30" />
+
<uses-permission android:name="android.permission.LOG_COMPAT_CHANGE"/>
<uses-permission android:name="android.permission.READ_COMPAT_CHANGE_CONFIG"/>
<uses-permission android:name="android.permission.CHANGE_CONFIGURATION" />
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
index 2a267c413c31..1b2711d3938b 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
@@ -99,6 +99,7 @@ import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
+import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
@@ -165,7 +166,7 @@ public class MockingOomAdjusterTests {
setFieldValue(ActivityManagerService.class, sService, "mHandler",
mock(ActivityManagerService.MainHandler.class));
setFieldValue(ActivityManagerService.class, sService, "mProcessStats",
- mock(ProcessStatsService.class));
+ new ProcessStatsService(sService, new File(sContext.getFilesDir(), "procstats")));
setFieldValue(ActivityManagerService.class, sService, "mBackupTargets",
mock(SparseArray.class));
setFieldValue(ActivityManagerService.class, sService, "mOomAdjProfiler",
diff --git a/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java
index 0a61c443e0bd..7a3a9504a0b3 100644
--- a/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java
@@ -130,7 +130,9 @@ public class AppOpsServiceTest {
}
@After
- public void resetStaticMocks() {
+ public void tearDown() {
+ mAppOpsService.shutdown();
+
mMockingSession.finishMocking();
}
@@ -216,9 +218,8 @@ public class AppOpsServiceTest {
false);
mAppOpsService.writeState();
- // Create a new app ops service, and initialize its state from XML.
+ // Create a new app ops service which will initialize its state from XML.
setupAppOpsService();
- mAppOpsService.readState();
// Query the state of the 2nd service.
List<PackageOps> loggedOps = getLoggedOps();
@@ -233,9 +234,8 @@ public class AppOpsServiceTest {
mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, sMyPackageName, null, false, null, false);
mAppOpsService.shutdown();
- // Create a new app ops service, and initialize its state from XML.
+ // Create a new app ops service which will initialize its state from XML.
setupAppOpsService();
- mAppOpsService.readState();
// Query the state of the 2nd service.
List<PackageOps> loggedOps = getLoggedOps();
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/LocationProviderManagerTest.java b/services/tests/mockingservicestests/src/com/android/server/location/LocationProviderManagerTest.java
new file mode 100644
index 000000000000..1cb004a6dc1e
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/location/LocationProviderManagerTest.java
@@ -0,0 +1,971 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.location;
+
+import static android.app.AlarmManager.ELAPSED_REALTIME_WAKEUP;
+import static android.app.AlarmManager.WINDOW_EXACT;
+import static android.app.AppOpsManager.OP_FINE_LOCATION;
+import static android.app.AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION;
+import static android.app.AppOpsManager.OP_MONITOR_LOCATION;
+import static android.location.Criteria.ACCURACY_COARSE;
+import static android.location.Criteria.ACCURACY_FINE;
+import static android.location.Criteria.POWER_HIGH;
+import static android.location.LocationManager.PASSIVE_PROVIDER;
+
+import static androidx.test.ext.truth.location.LocationSubject.assertThat;
+
+import static com.android.internal.util.ConcurrentUtils.DIRECT_EXECUTOR;
+import static com.android.server.location.LocationPermissions.PERMISSION_COARSE;
+import static com.android.server.location.LocationPermissions.PERMISSION_FINE;
+import static com.android.server.location.LocationUtils.createLocation;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.isNull;
+import static org.mockito.ArgumentMatchers.nullable;
+import static org.mockito.Mockito.after;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.MockitoAnnotations.initMocks;
+
+import android.app.AlarmManager;
+import android.app.AlarmManager.OnAlarmListener;
+import android.content.Context;
+import android.location.ILocationCallback;
+import android.location.ILocationListener;
+import android.location.Location;
+import android.location.LocationManagerInternal;
+import android.location.LocationManagerInternal.ProviderEnabledListener;
+import android.location.LocationRequest;
+import android.location.util.identity.CallerIdentity;
+import android.os.Bundle;
+import android.os.CancellationSignal;
+import android.os.Handler;
+import android.os.ICancellationSignal;
+import android.os.IRemoteCallback;
+import android.os.PowerManager;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.os.WorkSource;
+import android.platform.test.annotations.Presubmit;
+import android.util.Log;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.internal.location.ProviderProperties;
+import com.android.internal.location.ProviderRequest;
+import com.android.server.FgThread;
+import com.android.server.LocalServices;
+import com.android.server.location.listeners.ListenerRegistration;
+import com.android.server.location.util.FakeUserInfoHelper;
+import com.android.server.location.util.TestInjector;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.Collections;
+import java.util.Random;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+@Presubmit
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class LocationProviderManagerTest {
+
+ private static final String TAG = "LocationProviderManagerTest";
+
+ private static final long TIMEOUT_MS = 1000;
+
+ private static final int CURRENT_USER = FakeUserInfoHelper.DEFAULT_USERID;
+ private static final int OTHER_USER = CURRENT_USER + 10;
+
+ private static final String NAME = "test";
+ private static final ProviderProperties PROPERTIES = new ProviderProperties(false, false, false,
+ false, true, true, true, POWER_HIGH, ACCURACY_FINE);
+ private static final CallerIdentity IDENTITY = CallerIdentity.forTest(CURRENT_USER, 1,
+ "mypackage",
+ "attribution");
+
+ private Random mRandom;
+
+ @Mock
+ private LocationManagerInternal mInternal;
+ @Mock
+ private Context mContext;
+ @Mock
+ private AlarmManager mAlarmManager;
+ @Mock
+ private PowerManager mPowerManager;
+ @Mock
+ private PowerManager.WakeLock mWakeLock;
+
+ private TestInjector mInjector;
+ private PassiveLocationProviderManager mPassive;
+ private TestProvider mProvider;
+
+ private LocationProviderManager mManager;
+
+ @Before
+ public void setUp() {
+ initMocks(this);
+
+ long seed = System.currentTimeMillis();
+ Log.i(TAG, "location random seed: " + seed);
+
+ mRandom = new Random(seed);
+
+ LocalServices.addService(LocationManagerInternal.class, mInternal);
+
+ doReturn("android").when(mContext).getPackageName();
+ doReturn(mAlarmManager).when(mContext).getSystemService(AlarmManager.class);
+ doReturn(mPowerManager).when(mContext).getSystemService(PowerManager.class);
+ doReturn(mWakeLock).when(mPowerManager).newWakeLock(anyInt(), anyString());
+
+ mInjector = new TestInjector();
+ mInjector.getUserInfoHelper().startUser(OTHER_USER);
+
+ mPassive = new PassiveLocationProviderManager(mContext, mInjector);
+ mPassive.startManager();
+ mPassive.setRealProvider(new PassiveProvider(mContext));
+
+ mProvider = new TestProvider(PROPERTIES, IDENTITY);
+ mProvider.setProviderAllowed(true);
+
+ mManager = new LocationProviderManager(mContext, mInjector, NAME, mPassive);
+ mManager.startManager();
+ mManager.setRealProvider(mProvider);
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ LocalServices.removeServiceForTest(LocationManagerInternal.class);
+
+ // some test failures may leave the fg thread stuck, interrupt until we get out of it
+ CountDownLatch latch = new CountDownLatch(1);
+ FgThread.getExecutor().execute(latch::countDown);
+ int count = 0;
+ while (++count < 10 && !latch.await(10, TimeUnit.MILLISECONDS)) {
+ FgThread.get().getLooper().getThread().interrupt();
+ }
+ }
+
+ @Test
+ public void testProperties() {
+ assertThat(mManager.getName()).isEqualTo(NAME);
+ assertThat(mManager.getProperties()).isEqualTo(PROPERTIES);
+ assertThat(mManager.getIdentity()).isEqualTo(IDENTITY);
+ assertThat(mManager.hasProvider()).isTrue();
+
+ ProviderProperties newProperties = new ProviderProperties(true, true, true,
+ true, false, false, false, POWER_HIGH, ACCURACY_COARSE);
+ mProvider.setProperties(newProperties);
+ assertThat(mManager.getProperties()).isEqualTo(newProperties);
+
+ CallerIdentity newIdentity = CallerIdentity.forTest(OTHER_USER, 1, "otherpackage",
+ "otherattribution");
+ mProvider.setIdentity(newIdentity);
+ assertThat(mManager.getIdentity()).isEqualTo(newIdentity);
+
+ mManager.setRealProvider(null);
+ assertThat(mManager.hasProvider()).isFalse();
+ }
+
+ @Test
+ public void testRemoveProvider() {
+ mManager.setRealProvider(null);
+ assertThat(mManager.hasProvider()).isFalse();
+ }
+
+ @Test
+ public void testIsEnabled() {
+ assertThat(mManager.isEnabled(CURRENT_USER)).isTrue();
+
+ mInjector.getSettingsHelper().setLocationEnabled(false, CURRENT_USER);
+ assertThat(mManager.isEnabled(CURRENT_USER)).isFalse();
+
+ mInjector.getSettingsHelper().setLocationEnabled(true, CURRENT_USER);
+ mProvider.setAllowed(false);
+ assertThat(mManager.isEnabled(CURRENT_USER)).isFalse();
+
+ mProvider.setAllowed(true);
+ mInjector.getUserInfoHelper().setCurrentUserId(OTHER_USER);
+ assertThat(mManager.isEnabled(CURRENT_USER)).isFalse();
+ assertThat(mManager.isEnabled(OTHER_USER)).isTrue();
+
+ mInjector.getUserInfoHelper().setCurrentUserId(CURRENT_USER);
+ assertThat(mManager.isEnabled(CURRENT_USER)).isTrue();
+ assertThat(mManager.isEnabled(OTHER_USER)).isFalse();
+ }
+
+ @Test
+ public void testIsEnabledListener() {
+ ProviderEnabledListener listener = mock(ProviderEnabledListener.class);
+ mManager.addEnabledListener(listener);
+ verify(listener, never()).onProviderEnabledChanged(anyString(), anyInt(), anyBoolean());
+
+ mInjector.getSettingsHelper().setLocationEnabled(false, CURRENT_USER);
+ verify(listener, timeout(TIMEOUT_MS).times(1)).onProviderEnabledChanged(NAME, CURRENT_USER,
+ false);
+
+ mInjector.getSettingsHelper().setLocationEnabled(true, CURRENT_USER);
+ verify(listener, timeout(TIMEOUT_MS).times(1)).onProviderEnabledChanged(NAME, CURRENT_USER,
+ true);
+
+ mProvider.setAllowed(false);
+ verify(listener, timeout(TIMEOUT_MS).times(2)).onProviderEnabledChanged(NAME, CURRENT_USER,
+ false);
+
+ mProvider.setAllowed(true);
+ verify(listener, timeout(TIMEOUT_MS).times(2)).onProviderEnabledChanged(NAME, CURRENT_USER,
+ true);
+
+ mInjector.getUserInfoHelper().setCurrentUserId(OTHER_USER);
+ verify(listener, timeout(TIMEOUT_MS).times(3)).onProviderEnabledChanged(NAME, CURRENT_USER,
+ false);
+ verify(listener, timeout(TIMEOUT_MS).times(1)).onProviderEnabledChanged(NAME, OTHER_USER,
+ true);
+
+ mInjector.getUserInfoHelper().setCurrentUserId(CURRENT_USER);
+ verify(listener, timeout(TIMEOUT_MS).times(3)).onProviderEnabledChanged(NAME, CURRENT_USER,
+ true);
+ verify(listener, timeout(TIMEOUT_MS).times(1)).onProviderEnabledChanged(NAME, OTHER_USER,
+ false);
+
+ mManager.removeEnabledListener(listener);
+ mInjector.getSettingsHelper().setLocationEnabled(false, CURRENT_USER);
+ verifyNoMoreInteractions(listener);
+ }
+
+ @Test
+ public void testGetLastLocation_Fine() {
+ LocationRequest request = LocationRequest.createFromDeprecatedProvider(NAME, 0, 0, false);
+ assertThat(mManager.getLastLocation(request, IDENTITY, PERMISSION_FINE)).isNull();
+
+ Location loc = createLocation(NAME, mRandom);
+ mProvider.setProviderLocation(loc);
+ assertThat(mManager.getLastLocation(request, IDENTITY, PERMISSION_FINE)).isEqualTo(loc);
+ }
+
+ @Test
+ public void testGetLastLocation_Coarse() {
+ LocationRequest request = LocationRequest.createFromDeprecatedProvider(NAME, 0, 0, false);
+ assertThat(mManager.getLastLocation(request, IDENTITY, PERMISSION_FINE)).isNull();
+
+ Location loc = createLocation(NAME, mRandom);
+ mProvider.setProviderLocation(loc);
+ Location coarse = mManager.getLastLocation(request, IDENTITY, PERMISSION_COARSE);
+ assertThat(coarse).isNotEqualTo(loc);
+ assertThat(coarse).isNearby(loc, 5000);
+ }
+
+ @Test
+ public void testGetLastLocation_Bypass() {
+ LocationRequest request = LocationRequest.createFromDeprecatedProvider(NAME, 0, 0, false);
+ LocationRequest bypassRequest = LocationRequest.createFromDeprecatedProvider(NAME, 0, 0,
+ false).setLocationSettingsIgnored(true);
+ assertThat(mManager.getLastLocation(request, IDENTITY, PERMISSION_FINE)).isNull();
+ assertThat(mManager.getLastLocation(bypassRequest, IDENTITY, PERMISSION_FINE)).isNull();
+
+ Location loc = createLocation(NAME, mRandom);
+ mProvider.setProviderLocation(loc);
+ assertThat(mManager.getLastLocation(request, IDENTITY, PERMISSION_FINE)).isEqualTo(loc);
+ assertThat(mManager.getLastLocation(bypassRequest, IDENTITY, PERMISSION_FINE)).isEqualTo(
+ loc);
+
+ mProvider.setProviderAllowed(false);
+ assertThat(mManager.getLastLocation(request, IDENTITY, PERMISSION_FINE)).isNull();
+ assertThat(mManager.getLastLocation(bypassRequest, IDENTITY, PERMISSION_FINE)).isEqualTo(
+ loc);
+
+ loc = createLocation(NAME, mRandom);
+ mProvider.setProviderLocation(loc);
+ assertThat(mManager.getLastLocation(request, IDENTITY, PERMISSION_FINE)).isNull();
+ assertThat(mManager.getLastLocation(bypassRequest, IDENTITY, PERMISSION_FINE)).isEqualTo(
+ loc);
+
+ mProvider.setProviderAllowed(true);
+ assertThat(mManager.getLastLocation(request, IDENTITY, PERMISSION_FINE)).isNull();
+ assertThat(mManager.getLastLocation(bypassRequest, IDENTITY, PERMISSION_FINE)).isEqualTo(
+ loc);
+
+ loc = createLocation(NAME, mRandom);
+ mProvider.setProviderLocation(loc);
+ assertThat(mManager.getLastLocation(request, IDENTITY, PERMISSION_FINE)).isEqualTo(loc);
+ assertThat(mManager.getLastLocation(bypassRequest, IDENTITY, PERMISSION_FINE)).isEqualTo(
+ loc);
+ }
+
+ @Test
+ public void testGetLastLocation_ClearOnMockRemoval() {
+ MockProvider mockProvider = new MockProvider(PROPERTIES, IDENTITY);
+ mockProvider.setAllowed(true);
+ mManager.setMockProvider(mockProvider);
+
+ LocationRequest request = LocationRequest.createFromDeprecatedProvider(NAME, 0, 0, false);
+ Location loc = createLocation(NAME, mRandom);
+ mockProvider.setProviderLocation(loc);
+ assertThat(mManager.getLastLocation(request, IDENTITY, PERMISSION_FINE)).isEqualTo(loc);
+
+ mManager.setMockProvider(null);
+ assertThat(mManager.getLastLocation(request, IDENTITY, PERMISSION_FINE)).isNull();
+ }
+
+ @Test
+ public void testInjectLastLocation() {
+ Location loc1 = createLocation(NAME, mRandom);
+ mManager.injectLastLocation(loc1, CURRENT_USER);
+
+ LocationRequest request = LocationRequest.createFromDeprecatedProvider(NAME, 0, 0, false);
+ assertThat(mManager.getLastLocation(request, IDENTITY, PERMISSION_FINE)).isEqualTo(loc1);
+
+ Location loc2 = createLocation(NAME, mRandom);
+ mManager.injectLastLocation(loc2, CURRENT_USER);
+
+ assertThat(mManager.getLastLocation(request, IDENTITY, PERMISSION_FINE)).isEqualTo(loc1);
+ }
+
+ @Test
+ public void testPassive_Listener() throws Exception {
+ ILocationListener listener = createMockLocationListener();
+ LocationRequest request = LocationRequest.createFromDeprecatedProvider(PASSIVE_PROVIDER, 0,
+ 0, false);
+ mPassive.registerLocationRequest(request, IDENTITY, PERMISSION_FINE, listener);
+
+ Location loc = createLocation(NAME, mRandom);
+ mProvider.setProviderLocation(loc);
+
+ ArgumentCaptor<Location> locationCaptor = ArgumentCaptor.forClass(Location.class);
+ verify(listener).onLocationChanged(locationCaptor.capture(),
+ nullable(IRemoteCallback.class));
+ assertThat(locationCaptor.getValue()).isEqualTo(loc);
+ }
+
+ @Test
+ public void testPassive_LastLocation() {
+ Location loc = createLocation(NAME, mRandom);
+ mProvider.setProviderLocation(loc);
+
+ LocationRequest request = LocationRequest.createFromDeprecatedProvider(PASSIVE_PROVIDER, 0,
+ 0, false);
+ assertThat(mPassive.getLastLocation(request, IDENTITY, PERMISSION_FINE)).isEqualTo(loc);
+ }
+
+ @Test
+ public void testRegisterListener() throws Exception {
+ ArgumentCaptor<Location> locationCaptor = ArgumentCaptor.forClass(Location.class);
+
+ ILocationListener listener = createMockLocationListener();
+ mManager.registerLocationRequest(
+ LocationRequest.createFromDeprecatedProvider(NAME, 0, 0, false), IDENTITY,
+ PERMISSION_FINE, listener);
+
+ Location loc = createLocation(NAME, mRandom);
+ mProvider.setProviderLocation(loc);
+ verify(listener, times(1)).onLocationChanged(locationCaptor.capture(),
+ nullable(IRemoteCallback.class));
+ assertThat(locationCaptor.getValue()).isEqualTo(loc);
+
+ mInjector.getSettingsHelper().setLocationEnabled(false, CURRENT_USER);
+ verify(listener, timeout(TIMEOUT_MS).times(1)).onProviderEnabledChanged(NAME, false);
+ loc = createLocation(NAME, mRandom);
+ mProvider.setProviderLocation(loc);
+ verify(listener, times(1)).onLocationChanged(any(Location.class),
+ nullable(IRemoteCallback.class));
+
+ mInjector.getSettingsHelper().setLocationEnabled(true, CURRENT_USER);
+ verify(listener, timeout(TIMEOUT_MS).times(1)).onProviderEnabledChanged(NAME, true);
+
+ mProvider.setAllowed(false);
+ verify(listener, timeout(TIMEOUT_MS).times(2)).onProviderEnabledChanged(NAME, false);
+ loc = createLocation(NAME, mRandom);
+ mProvider.setProviderLocation(loc);
+ verify(listener, times(1)).onLocationChanged(any(Location.class),
+ nullable(IRemoteCallback.class));
+
+ mProvider.setAllowed(true);
+ verify(listener, timeout(TIMEOUT_MS).times(2)).onProviderEnabledChanged(NAME, true);
+
+ mInjector.getUserInfoHelper().setCurrentUserId(OTHER_USER);
+ verify(listener, timeout(TIMEOUT_MS).times(3)).onProviderEnabledChanged(NAME, false);
+ loc = createLocation(NAME, mRandom);
+ mProvider.setProviderLocation(loc);
+ verify(listener, times(1)).onLocationChanged(any(Location.class),
+ nullable(IRemoteCallback.class));
+
+ mInjector.getUserInfoHelper().setCurrentUserId(CURRENT_USER);
+ verify(listener, timeout(TIMEOUT_MS).times(3)).onProviderEnabledChanged(NAME, true);
+
+ loc = createLocation(NAME, mRandom);
+ mProvider.setProviderLocation(loc);
+ verify(listener, times(2)).onLocationChanged(locationCaptor.capture(),
+ nullable(IRemoteCallback.class));
+ assertThat(locationCaptor.getValue()).isEqualTo(loc);
+ }
+
+ @Test
+ public void testRegisterListener_SameProcess() throws Exception {
+ ArgumentCaptor<Location> locationCaptor = ArgumentCaptor.forClass(Location.class);
+
+ CallerIdentity identity = CallerIdentity.forTest(CURRENT_USER, Process.myPid(), "mypackage",
+ "attribution");
+
+ ILocationListener listener = createMockLocationListener();
+ mManager.registerLocationRequest(
+ LocationRequest.createFromDeprecatedProvider(NAME, 0, 0, false), identity,
+ PERMISSION_FINE, listener);
+
+ Location loc = createLocation(NAME, mRandom);
+ mProvider.setProviderLocation(loc);
+ verify(listener, timeout(TIMEOUT_MS).times(1)).onLocationChanged(locationCaptor.capture(),
+ nullable(IRemoteCallback.class));
+ assertThat(locationCaptor.getValue()).isEqualTo(loc);
+ }
+
+ @Test
+ public void testRegisterListener_Unregister() throws Exception {
+ ILocationListener listener = createMockLocationListener();
+ mManager.registerLocationRequest(
+ LocationRequest.createFromDeprecatedProvider(NAME, 0, 0, false), IDENTITY,
+ PERMISSION_FINE, listener);
+ mManager.unregisterLocationRequest(listener);
+
+ mProvider.setProviderLocation(createLocation(NAME, mRandom));
+ verify(listener, never()).onLocationChanged(any(Location.class),
+ nullable(IRemoteCallback.class));
+
+ mInjector.getSettingsHelper().setLocationEnabled(false, CURRENT_USER);
+ verify(listener, after(TIMEOUT_MS).never()).onProviderEnabledChanged(NAME, false);
+ }
+
+ @Test
+ public void testRegisterListener_Unregister_SameProcess() throws Exception {
+ CallerIdentity identity = CallerIdentity.forTest(CURRENT_USER, Process.myPid(), "mypackage",
+ "attribution");
+
+ ILocationListener listener = createMockLocationListener();
+ mManager.registerLocationRequest(
+ LocationRequest.createFromDeprecatedProvider(NAME, 0, 0, false), identity,
+ PERMISSION_FINE, listener);
+
+ CountDownLatch blocker = new CountDownLatch(1);
+ ListenerRegistration.IN_PROCESS_EXECUTOR.execute(() -> {
+ try {
+ blocker.await();
+ } catch (InterruptedException e) {
+ // do nothing
+ }
+ });
+
+ mProvider.setProviderLocation(createLocation(NAME, mRandom));
+ mManager.unregisterLocationRequest(listener);
+ blocker.countDown();
+ verify(listener, after(TIMEOUT_MS).never()).onLocationChanged(any(Location.class),
+ nullable(IRemoteCallback.class));
+ }
+
+ @Test
+ public void testRegisterListener_NumUpdates() throws Exception {
+ ILocationListener listener = createMockLocationListener();
+ LocationRequest request = LocationRequest.createFromDeprecatedProvider(NAME, 0, 0,
+ false).setNumUpdates(5);
+ mManager.registerLocationRequest(request, IDENTITY, PERMISSION_FINE, listener);
+
+ mProvider.setProviderLocation(createLocation(NAME, mRandom));
+ mProvider.setProviderLocation(createLocation(NAME, mRandom));
+ mProvider.setProviderLocation(createLocation(NAME, mRandom));
+ mProvider.setProviderLocation(createLocation(NAME, mRandom));
+ mProvider.setProviderLocation(createLocation(NAME, mRandom));
+ mProvider.setProviderLocation(createLocation(NAME, mRandom));
+
+ verify(listener, times(5)).onLocationChanged(any(Location.class),
+ nullable(IRemoteCallback.class));
+ }
+
+ @Test
+ public void testRegisterListener_ExpiringAlarm() throws Exception {
+ ILocationListener listener = createMockLocationListener();
+ LocationRequest request = LocationRequest.createFromDeprecatedProvider(NAME, 0, 0,
+ false).setExpireIn(5000);
+ mManager.registerLocationRequest(request, IDENTITY, PERMISSION_FINE, listener);
+ long baseTimeMs = SystemClock.elapsedRealtime();
+
+ ArgumentCaptor<Long> timeoutCapture = ArgumentCaptor.forClass(Long.class);
+ ArgumentCaptor<OnAlarmListener> listenerCapture = ArgumentCaptor.forClass(
+ OnAlarmListener.class);
+ verify(mAlarmManager).set(eq(ELAPSED_REALTIME_WAKEUP), timeoutCapture.capture(),
+ eq(WINDOW_EXACT), eq(0L), listenerCapture.capture(), any(Handler.class),
+ any(WorkSource.class));
+
+ assertThat(timeoutCapture.getValue()).isAtLeast(baseTimeMs + 4000);
+ assertThat(timeoutCapture.getValue()).isAtMost(baseTimeMs + 5000);
+ listenerCapture.getValue().onAlarm();
+
+ mProvider.setProviderLocation(createLocation(NAME, mRandom));
+ verify(listener, never()).onLocationChanged(any(Location.class),
+ nullable(IRemoteCallback.class));
+ }
+
+ @Test
+ public void testRegisterListener_ExpiringNoAlarm() throws Exception {
+ ILocationListener listener = createMockLocationListener();
+ LocationRequest request = LocationRequest.createFromDeprecatedProvider(NAME, 0, 0,
+ false).setExpireIn(25);
+ mManager.registerLocationRequest(request, IDENTITY, PERMISSION_FINE, listener);
+
+ Thread.sleep(25);
+
+ mProvider.setProviderLocation(createLocation(NAME, mRandom));
+ verify(listener, never()).onLocationChanged(any(Location.class),
+ nullable(IRemoteCallback.class));
+ }
+
+ @Test
+ public void testRegisterListener_AlreadyExpired() throws Exception {
+ ILocationListener listener = createMockLocationListener();
+ LocationRequest request = LocationRequest.createFromDeprecatedProvider(NAME, 0, 0,
+ false).setExpireIn(-1);
+ mManager.registerLocationRequest(request, IDENTITY, PERMISSION_FINE, listener);
+
+ mProvider.setProviderLocation(createLocation(NAME, mRandom));
+ verify(listener, never()).onLocationChanged(any(Location.class),
+ nullable(IRemoteCallback.class));
+ }
+
+ @Test
+ public void testRegisterListener_FastestInterval() throws Exception {
+ ILocationListener listener = createMockLocationListener();
+ LocationRequest request = LocationRequest.createFromDeprecatedProvider(NAME, 5000, 0,
+ false).setFastestInterval(5000);
+ mManager.registerLocationRequest(request, IDENTITY, PERMISSION_FINE, listener);
+
+ mProvider.setProviderLocation(createLocation(NAME, mRandom));
+ mProvider.setProviderLocation(createLocation(NAME, mRandom));
+
+ verify(listener, times(1)).onLocationChanged(any(Location.class),
+ nullable(IRemoteCallback.class));
+ }
+
+ @Test
+ public void testRegisterListener_SmallestDisplacement() throws Exception {
+ ILocationListener listener = createMockLocationListener();
+ LocationRequest request = LocationRequest.createFromDeprecatedProvider(NAME, 5000, 0,
+ false).setSmallestDisplacement(1f);
+ mManager.registerLocationRequest(request, IDENTITY, PERMISSION_FINE, listener);
+
+ Location loc = createLocation(NAME, mRandom);
+ mProvider.setProviderLocation(loc);
+ mProvider.setProviderLocation(loc);
+
+ verify(listener, times(1)).onLocationChanged(any(Location.class),
+ nullable(IRemoteCallback.class));
+ }
+
+ @Test
+ public void testRegisterListener_NoteOpFailure() throws Exception {
+ ILocationListener listener = createMockLocationListener();
+ LocationRequest request = LocationRequest.createFromDeprecatedProvider(NAME, 0, 0, false);
+ mManager.registerLocationRequest(request, IDENTITY, PERMISSION_FINE, listener);
+
+ mInjector.getAppOpsHelper().setAppOpAllowed(OP_FINE_LOCATION, IDENTITY.getPackageName(),
+ false);
+
+ mProvider.setProviderLocation(createLocation(NAME, mRandom));
+
+ verify(listener, never()).onLocationChanged(any(Location.class),
+ nullable(IRemoteCallback.class));
+ }
+
+ @Test
+ public void testRegisterListener_Wakelock() throws Exception {
+ CallerIdentity identity = CallerIdentity.forTest(CURRENT_USER, Process.myPid(), "mypackage",
+ "attribution");
+
+ ILocationListener listener = createMockLocationListener();
+ mManager.registerLocationRequest(
+ LocationRequest.createFromDeprecatedProvider(NAME, 0, 0, false), identity,
+ PERMISSION_FINE, listener);
+
+ CountDownLatch blocker = new CountDownLatch(1);
+ ListenerRegistration.IN_PROCESS_EXECUTOR.execute(() -> {
+ try {
+ blocker.await();
+ } catch (InterruptedException e) {
+ // do nothing
+ }
+ });
+
+ mProvider.setProviderLocation(createLocation(NAME, mRandom));
+ verify(mWakeLock).acquire(anyLong());
+ verify(mWakeLock, never()).release();
+
+ blocker.countDown();
+ verify(listener, timeout(TIMEOUT_MS)).onLocationChanged(any(Location.class),
+ nullable(IRemoteCallback.class));
+ verify(mWakeLock).acquire(anyLong());
+ verify(mWakeLock, timeout(TIMEOUT_MS)).release();
+ }
+
+ @Test
+ public void testGetCurrentLocation() throws Exception {
+ ArgumentCaptor<Location> locationCaptor = ArgumentCaptor.forClass(Location.class);
+
+ ILocationCallback listener = createMockGetCurrentLocationListener();
+ LocationRequest locationRequest = LocationRequest.createFromDeprecatedProvider(NAME, 0, 0,
+ false);
+ ICancellationSignal cancellationSignal = CancellationSignal.createTransport();
+ mManager.getCurrentLocation(locationRequest, IDENTITY,
+ PERMISSION_FINE, cancellationSignal, listener);
+
+ Location loc = createLocation(NAME, mRandom);
+ mProvider.setProviderLocation(loc);
+ mProvider.setProviderLocation(createLocation(NAME, mRandom));
+
+ verify(listener, times(1)).onLocation(locationCaptor.capture());
+ assertThat(locationCaptor.getValue()).isEqualTo(loc);
+ }
+
+ @Test
+ public void testGetCurrentLocation_Cancel() throws Exception {
+ ILocationCallback listener = createMockGetCurrentLocationListener();
+ LocationRequest locationRequest = LocationRequest.createFromDeprecatedProvider(NAME, 0, 0,
+ false);
+ ICancellationSignal cancellationSignal = CancellationSignal.createTransport();
+ mManager.getCurrentLocation(locationRequest, IDENTITY,
+ PERMISSION_FINE, cancellationSignal, listener);
+
+ cancellationSignal.cancel();
+ mProvider.setProviderLocation(createLocation(NAME, mRandom));
+
+ verify(listener, never()).onLocation(nullable(Location.class));
+ }
+
+ @Test
+ public void testGetCurrentLocation_ProviderDisabled() throws Exception {
+ ILocationCallback listener = createMockGetCurrentLocationListener();
+ LocationRequest locationRequest = LocationRequest.createFromDeprecatedProvider(NAME, 0, 0,
+ false);
+ ICancellationSignal cancellationSignal = CancellationSignal.createTransport();
+ mManager.getCurrentLocation(locationRequest, IDENTITY,
+ PERMISSION_FINE, cancellationSignal, listener);
+
+ mProvider.setProviderAllowed(false);
+ mProvider.setProviderAllowed(true);
+ mProvider.setProviderLocation(createLocation(NAME, mRandom));
+ verify(listener, times(1)).onLocation(isNull());
+ }
+
+ @Test
+ public void testGetCurrentLocation_ProviderAlreadyDisabled() throws Exception {
+ mProvider.setProviderAllowed(false);
+
+ ILocationCallback listener = createMockGetCurrentLocationListener();
+ LocationRequest locationRequest = LocationRequest.createFromDeprecatedProvider(NAME, 0, 0,
+ false);
+ ICancellationSignal cancellationSignal = CancellationSignal.createTransport();
+ mManager.getCurrentLocation(locationRequest, IDENTITY,
+ PERMISSION_FINE, cancellationSignal, listener);
+
+ mProvider.setProviderAllowed(true);
+ mProvider.setProviderLocation(createLocation(NAME, mRandom));
+ verify(listener, times(1)).onLocation(isNull());
+ }
+
+ @Test
+ public void testGetCurrentLocation_LastLocation() throws Exception {
+ ArgumentCaptor<Location> locationCaptor = ArgumentCaptor.forClass(Location.class);
+
+ Location loc = createLocation(NAME, mRandom);
+ mProvider.setProviderLocation(loc);
+
+ ILocationCallback listener = createMockGetCurrentLocationListener();
+ LocationRequest locationRequest = LocationRequest.createFromDeprecatedProvider(NAME, 0, 0,
+ false);
+ ICancellationSignal cancellationSignal = CancellationSignal.createTransport();
+ mManager.getCurrentLocation(locationRequest, IDENTITY,
+ PERMISSION_FINE, cancellationSignal, listener);
+
+ verify(listener, times(1)).onLocation(locationCaptor.capture());
+ assertThat(locationCaptor.getValue()).isEqualTo(loc);
+ }
+
+ @Test
+ public void testGetCurrentLocation_Timeout() throws Exception {
+ ILocationCallback listener = createMockGetCurrentLocationListener();
+ LocationRequest locationRequest = LocationRequest.createFromDeprecatedProvider(NAME, 0, 0,
+ false);
+ ICancellationSignal cancellationSignal = CancellationSignal.createTransport();
+ mManager.getCurrentLocation(locationRequest, IDENTITY,
+ PERMISSION_FINE, cancellationSignal, listener);
+
+ ArgumentCaptor<OnAlarmListener> listenerCapture = ArgumentCaptor.forClass(
+ OnAlarmListener.class);
+ verify(mAlarmManager).set(eq(ELAPSED_REALTIME_WAKEUP), anyLong(),
+ eq(WINDOW_EXACT), eq(0L), listenerCapture.capture(), any(Handler.class),
+ any(WorkSource.class));
+ listenerCapture.getValue().onAlarm();
+
+ verify(listener, times(1)).onLocation(isNull());
+ }
+
+ @Test
+ public void testLocationMonitoring() {
+ assertThat(mInjector.getAppOpsHelper().isAppOpStarted(OP_MONITOR_LOCATION,
+ IDENTITY.getPackageName())).isFalse();
+ assertThat(mInjector.getAppOpsHelper().isAppOpStarted(OP_MONITOR_HIGH_POWER_LOCATION,
+ IDENTITY.getPackageName())).isFalse();
+
+ ILocationListener listener = createMockLocationListener();
+ LocationRequest request = LocationRequest.createFromDeprecatedProvider(NAME, 0, 0, false);
+ mManager.registerLocationRequest(request, IDENTITY, PERMISSION_FINE, listener);
+
+ assertThat(mInjector.getAppOpsHelper().isAppOpStarted(OP_MONITOR_LOCATION,
+ IDENTITY.getPackageName())).isTrue();
+ assertThat(mInjector.getAppOpsHelper().isAppOpStarted(OP_MONITOR_HIGH_POWER_LOCATION,
+ IDENTITY.getPackageName())).isTrue();
+
+ mInjector.getAppForegroundHelper().setAppForeground(IDENTITY.getUid(), false);
+
+ assertThat(mInjector.getAppOpsHelper().isAppOpStarted(OP_MONITOR_LOCATION,
+ IDENTITY.getPackageName())).isTrue();
+ assertThat(mInjector.getAppOpsHelper().isAppOpStarted(OP_MONITOR_HIGH_POWER_LOCATION,
+ IDENTITY.getPackageName())).isFalse();
+
+ mManager.unregisterLocationRequest(listener);
+
+ assertThat(mInjector.getAppOpsHelper().isAppOpStarted(OP_MONITOR_LOCATION,
+ IDENTITY.getPackageName())).isFalse();
+ assertThat(mInjector.getAppOpsHelper().isAppOpStarted(OP_MONITOR_HIGH_POWER_LOCATION,
+ IDENTITY.getPackageName())).isFalse();
+ }
+
+ @Test
+ public void testProviderRequest() {
+ assertThat(mProvider.getRequest().reportLocation).isFalse();
+ assertThat(mProvider.getRequest().locationRequests).isEmpty();
+
+ ILocationListener listener1 = createMockLocationListener();
+ LocationRequest request1 = LocationRequest.createFromDeprecatedProvider(NAME, 5, 0, false);
+ mManager.registerLocationRequest(request1, IDENTITY, PERMISSION_FINE, listener1);
+
+ assertThat(mProvider.getRequest().reportLocation).isTrue();
+ assertThat(mProvider.getRequest().locationRequests).containsExactly(request1);
+ assertThat(mProvider.getRequest().locationSettingsIgnored).isFalse();
+ assertThat(mProvider.getRequest().interval).isEqualTo(5);
+ assertThat(mProvider.getRequest().lowPowerMode).isFalse();
+ assertThat(mProvider.getRequest().workSource).isNotNull();
+
+ ILocationListener listener2 = createMockLocationListener();
+ LocationRequest request2 = LocationRequest.createFromDeprecatedProvider(NAME, 1, 0,
+ false).setLowPowerMode(true);
+ mManager.registerLocationRequest(request2, IDENTITY, PERMISSION_FINE, listener2);
+
+ assertThat(mProvider.getRequest().reportLocation).isTrue();
+ assertThat(mProvider.getRequest().locationRequests).containsExactly(request1, request2);
+ assertThat(mProvider.getRequest().locationSettingsIgnored).isFalse();
+ assertThat(mProvider.getRequest().interval).isEqualTo(1);
+ assertThat(mProvider.getRequest().lowPowerMode).isFalse();
+ assertThat(mProvider.getRequest().workSource).isNotNull();
+
+ mManager.unregisterLocationRequest(listener1);
+
+ assertThat(mProvider.getRequest().reportLocation).isTrue();
+ assertThat(mProvider.getRequest().locationRequests).containsExactly(request2);
+ assertThat(mProvider.getRequest().locationSettingsIgnored).isFalse();
+ assertThat(mProvider.getRequest().interval).isEqualTo(1);
+ assertThat(mProvider.getRequest().lowPowerMode).isTrue();
+ assertThat(mProvider.getRequest().workSource).isNotNull();
+
+ mManager.unregisterLocationRequest(listener2);
+
+ assertThat(mProvider.getRequest().reportLocation).isFalse();
+ assertThat(mProvider.getRequest().locationRequests).isEmpty();
+ }
+
+ @Test
+ public void testProviderRequest_BackgroundThrottle() {
+ ILocationListener listener1 = createMockLocationListener();
+ LocationRequest request1 = LocationRequest.createFromDeprecatedProvider(NAME, 5, 0, false);
+ mManager.registerLocationRequest(request1, IDENTITY, PERMISSION_FINE, listener1);
+
+ assertThat(mProvider.getRequest().interval).isEqualTo(5);
+
+ mInjector.getAppForegroundHelper().setAppForeground(IDENTITY.getUid(), false);
+ assertThat(mProvider.getRequest().interval).isEqualTo(
+ mInjector.getSettingsHelper().getBackgroundThrottleIntervalMs());
+ }
+
+ @Test
+ public void testProviderRequest_IgnoreLocationSettings() {
+ mInjector.getSettingsHelper().setIgnoreSettingsPackageWhitelist(
+ Collections.singleton(IDENTITY.getPackageName()));
+
+ ILocationListener listener1 = createMockLocationListener();
+ LocationRequest request1 = LocationRequest.createFromDeprecatedProvider(NAME, 5, 0, false);
+ mManager.registerLocationRequest(request1, IDENTITY, PERMISSION_FINE, listener1);
+
+ assertThat(mProvider.getRequest().reportLocation).isTrue();
+ assertThat(mProvider.getRequest().interval).isEqualTo(5);
+ assertThat(mProvider.getRequest().locationSettingsIgnored).isFalse();
+
+ ILocationListener listener2 = createMockLocationListener();
+ LocationRequest request2 = LocationRequest.createFromDeprecatedProvider(NAME, 1, 0,
+ false).setLocationSettingsIgnored(true);
+ mManager.registerLocationRequest(request2, IDENTITY, PERMISSION_FINE, listener2);
+
+ assertThat(mProvider.getRequest().reportLocation).isTrue();
+ assertThat(mProvider.getRequest().interval).isEqualTo(1);
+ assertThat(mProvider.getRequest().locationSettingsIgnored).isTrue();
+ }
+
+ @Test
+ public void testProviderRequest_IgnoreLocationSettings_ProviderDisabled() {
+ mInjector.getSettingsHelper().setIgnoreSettingsPackageWhitelist(
+ Collections.singleton(IDENTITY.getPackageName()));
+
+ ILocationListener listener1 = createMockLocationListener();
+ LocationRequest request1 = LocationRequest.createFromDeprecatedProvider(NAME, 1, 0, false);
+ mManager.registerLocationRequest(request1, IDENTITY, PERMISSION_FINE, listener1);
+
+ ILocationListener listener2 = createMockLocationListener();
+ LocationRequest request2 = LocationRequest.createFromDeprecatedProvider(NAME, 5, 0,
+ false).setLocationSettingsIgnored(true);
+ mManager.registerLocationRequest(request2, IDENTITY, PERMISSION_FINE, listener2);
+
+ mInjector.getSettingsHelper().setLocationEnabled(false, IDENTITY.getUserId());
+
+ assertThat(mProvider.getRequest().reportLocation).isTrue();
+ assertThat(mProvider.getRequest().locationRequests).containsExactly(request2);
+ assertThat(mProvider.getRequest().interval).isEqualTo(5);
+ assertThat(mProvider.getRequest().locationSettingsIgnored).isTrue();
+ }
+
+ @Test
+ public void testProviderRequest_IgnoreLocationSettings_NoAllowlist() {
+ mInjector.getSettingsHelper().setIgnoreSettingsPackageWhitelist(
+ Collections.singleton(IDENTITY.getPackageName()));
+
+ ILocationListener listener = createMockLocationListener();
+ LocationRequest request = LocationRequest.createFromDeprecatedProvider(NAME, 1, 0,
+ false).setLocationSettingsIgnored(true);
+ mManager.registerLocationRequest(request, IDENTITY, PERMISSION_FINE, listener);
+
+ mInjector.getSettingsHelper().setIgnoreSettingsPackageWhitelist(Collections.emptySet());
+
+ assertThat(mProvider.getRequest().reportLocation).isTrue();
+ assertThat(mProvider.getRequest().interval).isEqualTo(1);
+ assertThat(mProvider.getRequest().locationSettingsIgnored).isFalse();
+ }
+
+ @Test
+ public void testProviderRequest_BackgroundThrottle_IgnoreLocationSettings() {
+ mInjector.getSettingsHelper().setIgnoreSettingsPackageWhitelist(
+ Collections.singleton(IDENTITY.getPackageName()));
+
+ ILocationListener listener1 = createMockLocationListener();
+ LocationRequest request1 = LocationRequest.createFromDeprecatedProvider(NAME, 5, 0,
+ false).setLocationSettingsIgnored(true);
+ mManager.registerLocationRequest(request1, IDENTITY, PERMISSION_FINE, listener1);
+
+ assertThat(mProvider.getRequest().interval).isEqualTo(5);
+
+ mInjector.getAppForegroundHelper().setAppForeground(IDENTITY.getUid(), false);
+ assertThat(mProvider.getRequest().interval).isEqualTo(5);
+ }
+
+ private ILocationListener createMockLocationListener() {
+ return spy(new ILocationListener.Stub() {
+ @Override
+ public void onLocationChanged(Location location, IRemoteCallback onCompleteCallback) {
+ if (onCompleteCallback != null) {
+ try {
+ onCompleteCallback.sendResult(null);
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ }
+ }
+
+ @Override
+ public void onProviderEnabledChanged(String provider, boolean enabled) {
+ }
+ });
+ }
+
+ private ILocationCallback createMockGetCurrentLocationListener() {
+ return spy(new ILocationCallback.Stub() {
+ @Override
+ public void onLocation(Location location) {
+ }
+ });
+ }
+
+ private static class TestProvider extends AbstractLocationProvider {
+
+ private ProviderRequest mProviderRequest = ProviderRequest.EMPTY_REQUEST;
+
+ TestProvider(ProviderProperties properties, CallerIdentity identity) {
+ super(DIRECT_EXECUTOR, identity);
+ setProperties(properties);
+ }
+
+ public void setProviderAllowed(boolean allowed) {
+ setAllowed(allowed);
+ }
+
+ public void setProviderLocation(Location l) {
+ reportLocation(new Location(l));
+ }
+
+ public ProviderRequest getRequest() {
+ return mProviderRequest;
+ }
+
+ @Override
+ public void onSetRequest(ProviderRequest request) {
+ mProviderRequest = request;
+ }
+
+ @Override
+ protected void onExtraCommand(int uid, int pid, String command, Bundle extras) {
+ }
+
+ @Override
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ }
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/VibratorServiceTest.java b/services/tests/servicestests/src/com/android/server/VibratorServiceTest.java
index c6922536f61a..1b6ac3c84210 100644
--- a/services/tests/servicestests/src/com/android/server/VibratorServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/VibratorServiceTest.java
@@ -183,13 +183,12 @@ public class VibratorServiceTest {
@Test
public void hasAmplitudeControl_withAmplitudeControlSupport_returnsTrue() {
- when(mNativeWrapperMock.vibratorSupportsAmplitudeControl()).thenReturn(true);
+ mockVibratorCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
assertTrue(createService().hasAmplitudeControl());
}
@Test
public void hasAmplitudeControl_withNoAmplitudeControlSupport_returnsFalse() {
- when(mNativeWrapperMock.vibratorSupportsAmplitudeControl()).thenReturn(false);
assertFalse(createService().hasAmplitudeControl());
}
@@ -270,7 +269,7 @@ public class VibratorServiceTest {
@Test
public void vibrate_withOneShotAndAmplitudeControl_turnsVibratorOnAndSetsAmplitude() {
- when(mNativeWrapperMock.vibratorSupportsAmplitudeControl()).thenReturn(true);
+ mockVibratorCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
VibratorService service = createService();
Mockito.clearInvocations(mNativeWrapperMock);
@@ -340,7 +339,7 @@ public class VibratorServiceTest {
@Test
public void vibrate_withWaveform_controlsVibratorAmplitudeDuringTotalVibrationTime()
throws Exception {
- when(mNativeWrapperMock.vibratorSupportsAmplitudeControl()).thenReturn(true);
+ mockVibratorCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
VibratorService service = createService();
Mockito.clearInvocations(mNativeWrapperMock);
@@ -511,7 +510,7 @@ public class VibratorServiceTest {
setVibrationIntensityUserSetting(Settings.System.RING_VIBRATION_INTENSITY,
Vibrator.VIBRATION_INTENSITY_OFF);
- when(mNativeWrapperMock.vibratorSupportsAmplitudeControl()).thenReturn(true);
+ mockVibratorCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
VibratorService service = createService();
service.systemReady();
diff --git a/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java b/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java
index f991dff2797f..db56657e208c 100644
--- a/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java
@@ -550,7 +550,6 @@ public class AppsFilterTest {
.setAppId(DUMMY_TARGET_APPID)
.setName("com.some.package")
.setCodePath("/")
- .setResourcePath("/")
.setPVersionCode(1L)
.build();
PackageSetting calling = simulateAddPackage(appsFilter,
@@ -874,7 +873,6 @@ public class AppsFilterTest {
.setAppId(appId)
.setName(newPkg.getPackageName())
.setCodePath("/")
- .setResourcePath("/")
.setPVersionCode(1L);
final PackageSetting setting =
(action == null ? settingBuilder : action.withBuilder(settingBuilder)).build();
diff --git a/services/tests/servicestests/src/com/android/server/pm/KeySetManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/pm/KeySetManagerServiceTest.java
index 164bd725dd66..90edaef4294f 100644
--- a/services/tests/servicestests/src/com/android/server/pm/KeySetManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/KeySetManagerServiceTest.java
@@ -38,8 +38,7 @@ public class KeySetManagerServiceTest extends AndroidTestCase {
public PackageSetting generateFakePackageSetting(String name) {
return new PackageSetting(name, name, new File(mContext.getCacheDir(), "fakeCodePath"),
- new File(mContext.getCacheDir(), "fakeResPath"), "", "", "",
- "", 1, 0, 0, 0 /*sharedUserId*/, null /*usesStaticLibraries*/,
+ "", "", "", "", 1, 0, 0, 0 /*sharedUserId*/, null /*usesStaticLibraries*/,
null /*usesStaticLibrariesVersions*/, null /*mimeGroups*/);
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java
index c4e25b53d5d5..80f145b16147 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java
@@ -86,8 +86,7 @@ public class PackageManagerServiceTest {
// Create a real (non-null) PackageSetting and confirm that the removed
// users are copied properly
setting = new PackageSetting("name", "realName", new File("codePath"),
- new File("resourcePath"), "legacyNativeLibraryPathString",
- "primaryCpuAbiString", "secondaryCpuAbiString",
+ "legacyNativeLibraryPathString", "primaryCpuAbiString", "secondaryCpuAbiString",
"cpuAbiOverrideString", 0, 0, 0, 0,
null, null, null);
pri.populateUsers(new int[] {
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
index aa92ba49d190..0bf06bb4dda7 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
@@ -439,7 +439,6 @@ public class PackageManagerSettingsTests {
PACKAGE_NAME,
REAL_PACKAGE_NAME,
INITIAL_CODE_PATH /*codePath*/,
- INITIAL_CODE_PATH /*resourcePath*/,
null /*legacyNativeLibraryPathString*/,
"x86_64" /*primaryCpuAbiString*/,
"x86" /*secondaryCpuAbiString*/,
@@ -461,7 +460,6 @@ public class PackageManagerSettingsTests {
PACKAGE_NAME /*pkgName*/,
REAL_PACKAGE_NAME /*realPkgName*/,
INITIAL_CODE_PATH /*codePath*/,
- INITIAL_CODE_PATH /*resourcePath*/,
null /*legacyNativeLibraryPathString*/,
"x86_64" /*primaryCpuAbiString*/,
"x86" /*secondaryCpuAbiString*/,
@@ -477,7 +475,6 @@ public class PackageManagerSettingsTests {
PACKAGE_NAME /*pkgName*/,
REAL_PACKAGE_NAME /*realPkgName*/,
UPDATED_CODE_PATH /*codePath*/,
- UPDATED_CODE_PATH /*resourcePath*/,
null /*legacyNativeLibraryPathString*/,
null /*primaryCpuAbiString*/,
null /*secondaryCpuAbiString*/,
@@ -507,7 +504,6 @@ public class PackageManagerSettingsTests {
null /*disabledPkg*/,
null /*sharedUser*/,
UPDATED_CODE_PATH /*codePath*/,
- UPDATED_CODE_PATH /*resourcePath*/,
null /*legacyNativeLibraryPath*/,
"arm64-v8a" /*primaryCpuAbi*/,
"armeabi" /*secondaryCpuAbi*/,
@@ -541,7 +537,6 @@ public class PackageManagerSettingsTests {
null /*disabledPkg*/,
null /*sharedUser*/,
UPDATED_CODE_PATH /*codePath*/,
- UPDATED_CODE_PATH /*resourcePath*/,
null /*legacyNativeLibraryPath*/,
"arm64-v8a" /*primaryCpuAbi*/,
"armeabi" /*secondaryCpuAbi*/,
@@ -581,7 +576,6 @@ public class PackageManagerSettingsTests {
null /*disabledPkg*/,
testUserSetting01 /*sharedUser*/,
UPDATED_CODE_PATH /*codePath*/,
- null /*resourcePath*/,
null /*legacyNativeLibraryPath*/,
"arm64-v8a" /*primaryCpuAbi*/,
"armeabi" /*secondaryCpuAbi*/,
@@ -609,7 +603,6 @@ public class PackageManagerSettingsTests {
null /*realPkgName*/,
null /*sharedUser*/,
UPDATED_CODE_PATH /*codePath*/,
- UPDATED_CODE_PATH /*resourcePath*/,
null /*legacyNativeLibraryPath*/,
"arm64-v8a" /*primaryCpuAbi*/,
"armeabi" /*secondaryCpuAbi*/,
@@ -624,12 +617,11 @@ public class PackageManagerSettingsTests {
null /*usesStaticLibraries*/,
null /*usesStaticLibrariesVersions*/,
null /*mimeGroups*/);
- assertThat(testPkgSetting01.codePath, is(UPDATED_CODE_PATH));
+ assertThat(testPkgSetting01.getCodePath(), is(UPDATED_CODE_PATH));
assertThat(testPkgSetting01.name, is(PACKAGE_NAME));
assertThat(testPkgSetting01.pkgFlags, is(ApplicationInfo.FLAG_SYSTEM));
assertThat(testPkgSetting01.pkgPrivateFlags, is(ApplicationInfo.PRIVATE_FLAG_PRIVILEGED));
assertThat(testPkgSetting01.primaryCpuAbiString, is("arm64-v8a"));
- assertThat(testPkgSetting01.resourcePath, is(UPDATED_CODE_PATH));
assertThat(testPkgSetting01.secondaryCpuAbiString, is("armeabi"));
// signatures object must be different
assertNotSame(testPkgSetting01.signatures, originalSignatures);
@@ -649,7 +641,6 @@ public class PackageManagerSettingsTests {
null /*realPkgName*/,
null /*sharedUser*/,
INITIAL_CODE_PATH /*codePath*/,
- INITIAL_CODE_PATH /*resourcePath*/,
null /*legacyNativeLibraryPath*/,
"x86_64" /*primaryCpuAbiString*/,
"x86" /*secondaryCpuAbiString*/,
@@ -665,12 +656,11 @@ public class PackageManagerSettingsTests {
null /*usesStaticLibrariesVersions*/,
null /*mimeGroups*/);
assertThat(testPkgSetting01.appId, is(0));
- assertThat(testPkgSetting01.codePath, is(INITIAL_CODE_PATH));
+ assertThat(testPkgSetting01.getCodePath(), is(INITIAL_CODE_PATH));
assertThat(testPkgSetting01.name, is(PACKAGE_NAME));
assertThat(testPkgSetting01.pkgFlags, is(0));
assertThat(testPkgSetting01.pkgPrivateFlags, is(0));
assertThat(testPkgSetting01.primaryCpuAbiString, is("x86_64"));
- assertThat(testPkgSetting01.resourcePath, is(INITIAL_CODE_PATH));
assertThat(testPkgSetting01.secondaryCpuAbiString, is("x86"));
assertThat(testPkgSetting01.versionCode, is(INITIAL_VERSION_CODE));
// by default, the package is considered stopped
@@ -695,7 +685,6 @@ public class PackageManagerSettingsTests {
null /*realPkgName*/,
testUserSetting01 /*sharedUser*/,
INITIAL_CODE_PATH /*codePath*/,
- INITIAL_CODE_PATH /*resourcePath*/,
null /*legacyNativeLibraryPath*/,
"x86_64" /*primaryCpuAbiString*/,
"x86" /*secondaryCpuAbiString*/,
@@ -711,12 +700,11 @@ public class PackageManagerSettingsTests {
null /*usesStaticLibrariesVersions*/,
null /*mimeGroups*/);
assertThat(testPkgSetting01.appId, is(10064));
- assertThat(testPkgSetting01.codePath, is(INITIAL_CODE_PATH));
+ assertThat(testPkgSetting01.getCodePath(), is(INITIAL_CODE_PATH));
assertThat(testPkgSetting01.name, is(PACKAGE_NAME));
assertThat(testPkgSetting01.pkgFlags, is(0));
assertThat(testPkgSetting01.pkgPrivateFlags, is(0));
assertThat(testPkgSetting01.primaryCpuAbiString, is("x86_64"));
- assertThat(testPkgSetting01.resourcePath, is(INITIAL_CODE_PATH));
assertThat(testPkgSetting01.secondaryCpuAbiString, is("x86"));
assertThat(testPkgSetting01.versionCode, is(INITIAL_VERSION_CODE));
final PackageUserState userState = testPkgSetting01.readUserState(0);
@@ -738,7 +726,6 @@ public class PackageManagerSettingsTests {
null /*realPkgName*/,
null /*sharedUser*/,
UPDATED_CODE_PATH /*codePath*/,
- UPDATED_CODE_PATH /*resourcePath*/,
null /*legacyNativeLibraryPath*/,
"arm64-v8a" /*primaryCpuAbi*/,
"armeabi" /*secondaryCpuAbi*/,
@@ -754,12 +741,11 @@ public class PackageManagerSettingsTests {
null /*usesStaticLibrariesVersions*/,
null /*mimeGroups*/);
assertThat(testPkgSetting01.appId, is(10064));
- assertThat(testPkgSetting01.codePath, is(UPDATED_CODE_PATH));
+ assertThat(testPkgSetting01.getCodePath(), is(UPDATED_CODE_PATH));
assertThat(testPkgSetting01.name, is(PACKAGE_NAME));
assertThat(testPkgSetting01.pkgFlags, is(0));
assertThat(testPkgSetting01.pkgPrivateFlags, is(0));
assertThat(testPkgSetting01.primaryCpuAbiString, is("arm64-v8a"));
- assertThat(testPkgSetting01.resourcePath, is(UPDATED_CODE_PATH));
assertThat(testPkgSetting01.secondaryCpuAbiString, is("armeabi"));
assertNotSame(testPkgSetting01.signatures, disabledSignatures);
assertThat(testPkgSetting01.versionCode, is(UPDATED_VERSION_CODE));
@@ -806,10 +792,10 @@ public class PackageManagerSettingsTests {
private void verifySettingCopy(PackageSetting origPkgSetting, PackageSetting testPkgSetting) {
assertThat(origPkgSetting, is(not(testPkgSetting)));
assertThat(origPkgSetting.appId, is(testPkgSetting.appId));
- assertSame(origPkgSetting.codePath, testPkgSetting.codePath);
- assertThat(origPkgSetting.codePath, is(testPkgSetting.codePath));
- assertSame(origPkgSetting.codePathString, testPkgSetting.codePathString);
- assertThat(origPkgSetting.codePathString, is(testPkgSetting.codePathString));
+ assertSame(origPkgSetting.getCodePath(), testPkgSetting.getCodePath());
+ assertThat(origPkgSetting.getCodePath(), is(testPkgSetting.getCodePath()));
+ assertSame(origPkgSetting.getCodePathString(), testPkgSetting.getCodePathString());
+ assertThat(origPkgSetting.getCodePathString(), is(testPkgSetting.getCodePathString()));
assertSame(origPkgSetting.cpuAbiOverrideString, testPkgSetting.cpuAbiOverrideString);
assertThat(origPkgSetting.cpuAbiOverrideString, is(testPkgSetting.cpuAbiOverrideString));
assertThat(origPkgSetting.firstInstallTime, is(testPkgSetting.firstInstallTime));
@@ -823,7 +809,9 @@ public class PackageManagerSettingsTests {
testPkgSetting.legacyNativeLibraryPathString);
assertThat(origPkgSetting.legacyNativeLibraryPathString,
is(testPkgSetting.legacyNativeLibraryPathString));
- assertNotSame(origPkgSetting.mimeGroups, testPkgSetting.mimeGroups);
+ if (origPkgSetting.mimeGroups != null) {
+ assertNotSame(origPkgSetting.mimeGroups, testPkgSetting.mimeGroups);
+ }
assertThat(origPkgSetting.mimeGroups, is(testPkgSetting.mimeGroups));
assertNotSame(origPkgSetting.mPermissionsState, testPkgSetting.mPermissionsState);
assertThat(origPkgSetting.mPermissionsState, is(testPkgSetting.mPermissionsState));
@@ -839,10 +827,6 @@ public class PackageManagerSettingsTests {
assertSame(origPkgSetting.primaryCpuAbiString, testPkgSetting.primaryCpuAbiString);
assertThat(origPkgSetting.primaryCpuAbiString, is(testPkgSetting.primaryCpuAbiString));
assertThat(origPkgSetting.realName, is(testPkgSetting.realName));
- assertSame(origPkgSetting.resourcePath, testPkgSetting.resourcePath);
- assertThat(origPkgSetting.resourcePath, is(testPkgSetting.resourcePath));
- assertSame(origPkgSetting.resourcePathString, testPkgSetting.resourcePathString);
- assertThat(origPkgSetting.resourcePathString, is(testPkgSetting.resourcePathString));
assertSame(origPkgSetting.secondaryCpuAbiString, testPkgSetting.secondaryCpuAbiString);
assertThat(origPkgSetting.secondaryCpuAbiString, is(testPkgSetting.secondaryCpuAbiString));
assertSame(origPkgSetting.sharedUser, testPkgSetting.sharedUser);
@@ -874,7 +858,6 @@ public class PackageManagerSettingsTests {
PACKAGE_NAME,
REAL_PACKAGE_NAME,
INITIAL_CODE_PATH /*codePath*/,
- INITIAL_CODE_PATH /*resourcePath*/,
null /*legacyNativeLibraryPathString*/,
"x86_64" /*primaryCpuAbiString*/,
"x86" /*secondaryCpuAbiString*/,
@@ -893,7 +876,6 @@ public class PackageManagerSettingsTests {
packageName,
packageName,
INITIAL_CODE_PATH /*codePath*/,
- INITIAL_CODE_PATH /*resourcePath*/,
null /*legacyNativeLibraryPathString*/,
"x86_64" /*primaryCpuAbiString*/,
"x86" /*secondaryCpuAbiString*/,
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
index b0b5386a49bd..2651cfa5449b 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
@@ -312,8 +312,7 @@ public class PackageParserTest {
private static PackageSetting mockPkgSetting(AndroidPackage pkg) {
return new PackageSetting(pkg.getPackageName(), pkg.getRealPackage(),
- new File(pkg.getCodePath()), new File(pkg.getCodePath()), null,
- pkg.getPrimaryCpuAbi(), pkg.getSecondaryCpuAbi(),
+ new File(pkg.getCodePath()), null, pkg.getPrimaryCpuAbi(), pkg.getSecondaryCpuAbi(),
null, pkg.getVersionCode(),
PackageInfoUtils.appInfoFlags(pkg, null),
PackageInfoUtils.appInfoPrivateFlags(pkg, null),
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageSettingBuilder.java b/services/tests/servicestests/src/com/android/server/pm/PackageSettingBuilder.java
index d12ea89469b7..f8e92ad71d8e 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageSettingBuilder.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageSettingBuilder.java
@@ -30,7 +30,6 @@ public class PackageSettingBuilder {
private String mName;
private String mRealName;
private String mCodePath;
- private String mResourcePath;
private String mLegacyNativeLibraryPathString;
private String mPrimaryCpuAbiString;
private String mSecondaryCpuAbiString;
@@ -74,11 +73,6 @@ public class PackageSettingBuilder {
return this;
}
- public PackageSettingBuilder setResourcePath(String resourcePath) {
- this.mResourcePath = resourcePath;
- return this;
- }
-
public PackageSettingBuilder setLegacyNativeLibraryPathString(
String legacyNativeLibraryPathString) {
this.mLegacyNativeLibraryPathString = legacyNativeLibraryPathString;
@@ -162,10 +156,10 @@ public class PackageSettingBuilder {
public PackageSetting build() {
final PackageSetting packageSetting = new PackageSetting(mName, mRealName,
- new File(mCodePath), new File(mResourcePath),
- mLegacyNativeLibraryPathString, mPrimaryCpuAbiString, mSecondaryCpuAbiString,
- mCpuAbiOverrideString, mPVersionCode, mPkgFlags, mPrivateFlags, mSharedUserId,
- mUsesStaticLibraries, mUsesStaticLibrariesVersions, mMimeGroups);
+ new File(mCodePath), mLegacyNativeLibraryPathString, mPrimaryCpuAbiString,
+ mSecondaryCpuAbiString, mCpuAbiOverrideString, mPVersionCode, mPkgFlags,
+ mPrivateFlags, mSharedUserId, mUsesStaticLibraries, mUsesStaticLibrariesVersions,
+ mMimeGroups);
packageSetting.signatures = mSigningDetails != null
? new PackageSignatures(mSigningDetails)
: new PackageSignatures();
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageSignaturesTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageSignaturesTest.java
index 55bc6812328a..7108490f80f8 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageSignaturesTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageSignaturesTest.java
@@ -465,9 +465,9 @@ public class PackageSignaturesTest {
// Generic PackageSetting object with values from a test app installed on a device to be
// used to test the methods under the PackageSignatures signatures data member.
File appPath = new File("/data/app/app");
- PackageSetting result = new PackageSetting("test.app", null, appPath, appPath,
- "/data/app/app", null, null, null,
- 1, 940097092, 0, 0 /*userId*/, null, null, null /*mimeGroups*/);
+ PackageSetting result = new PackageSetting("test.app", null, appPath,
+ "/data/app/app", null, null, null, 1, 940097092, 0, 0 /*userId*/, null, null,
+ null /*mimeGroups*/);
return result;
}
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/ScanTests.java b/services/tests/servicestests/src/com/android/server/pm/ScanTests.java
index e7eff00c472e..56dddb0a8112 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ScanTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ScanTests.java
@@ -484,8 +484,7 @@ public class ScanTests {
private static PackageSettingBuilder createBasicPackageSettingBuilder(String packageName) {
return new PackageSettingBuilder()
.setName(packageName)
- .setCodePath(createCodePath(packageName))
- .setResourcePath(createCodePath(packageName));
+ .setCodePath(createCodePath(packageName));
}
private static ScanRequestBuilder createBasicScanRequestBuilder(ParsingPackage pkg) {
@@ -534,8 +533,7 @@ public class ScanTests {
arrayContaining("some.static.library", "some.other.static.library"));
assertThat(pkgSetting.usesStaticLibrariesVersions, is(new long[]{234L, 456L}));
assertThat(pkgSetting.pkg, is(scanResult.request.parsedPackage));
- assertThat(pkgSetting.codePath, is(new File(createCodePath(packageName))));
- assertThat(pkgSetting.resourcePath, is(new File(createCodePath(packageName))));
+ assertThat(pkgSetting.getCodePath(), is(new File(createCodePath(packageName))));
assertThat(pkgSetting.versionCode, is(PackageInfo.composeLongVersionCode(1, 2345)));
}
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorServiceTest.java b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorServiceTest.java
index 153634548c17..8034cacc6923 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorServiceTest.java
@@ -170,7 +170,7 @@ public class TimeZoneDetectorServiceTest {
ITimeZoneConfigurationListener mockListener = mock(ITimeZoneConfigurationListener.class);
try {
mTimeZoneDetectorService.removeConfigurationListener(mockListener);
- fail();
+ fail("Expected a SecurityException");
} finally {
verify(mMockContext).enforceCallingPermission(
eq(android.Manifest.permission.WRITE_SECURE_SETTINGS),
diff --git a/services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java
index 1d75967756c3..88b1d191dc4d 100644
--- a/services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java
@@ -16,6 +16,7 @@
package com.android.server;
+import android.Manifest;
import android.app.AlarmManager;
import android.app.IUiModeManager;
import android.content.BroadcastReceiver;
@@ -24,6 +25,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
+import android.content.pm.UserInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.os.Handler;
@@ -67,6 +69,7 @@ import static org.mockito.Mockito.atLeast;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -230,6 +233,17 @@ public class UiModeManagerServiceTest extends UiServiceTestCase {
}
@Test
+ public void setNightModeActivated_permissiontoChangeOtherUsers() throws RemoteException {
+ SystemService.TargetUser user = mock(SystemService.TargetUser.class);
+ doReturn(9).when(user).getUserIdentifier();
+ mUiManagerService.onUserSwitching(user, user);
+ when(mContext.checkCallingOrSelfPermission(
+ eq(Manifest.permission.INTERACT_ACROSS_USERS)))
+ .thenReturn(PackageManager.PERMISSION_DENIED);
+ assertFalse(mService.setNightModeActivated(true));
+ }
+
+ @Test
public void autoNightModeSwitch_batterySaverOn() throws RemoteException {
mService.setNightMode(MODE_NIGHT_NO);
when(mTwilightState.isNight()).thenReturn(false);
diff --git a/services/tests/wmtests/AndroidManifest.xml b/services/tests/wmtests/AndroidManifest.xml
index 4040fa6a675e..e3c795d03381 100644
--- a/services/tests/wmtests/AndroidManifest.xml
+++ b/services/tests/wmtests/AndroidManifest.xml
@@ -38,6 +38,7 @@
<uses-permission android:name="android.permission.REORDER_TASKS" />
<uses-permission android:name="android.permission.READ_DEVICE_CONFIG" />
<uses-permission android:name="android.permission.STATUS_BAR" />
+ <uses-permission android:name="android.permission.CAPTURE_VIDEO_OUTPUT" />
<!-- TODO: Remove largeHeap hack when memory leak is fixed (b/123984854) -->
<application android:debuggable="true"
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java
index addf1ffe40c2..96b970056c98 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java
@@ -38,7 +38,13 @@ import static org.mockito.ArgumentMatchers.eq;
import android.app.WaitResult;
import android.content.pm.ActivityInfo;
+import android.graphics.PixelFormat;
+import android.hardware.display.DisplayManager;
+import android.hardware.display.VirtualDisplay;
+import android.media.ImageReader;
import android.platform.test.annotations.Presubmit;
+import android.view.Display;
+import android.view.DisplayInfo;
import androidx.test.filters.MediumTest;
@@ -173,4 +179,50 @@ public class ActivityStackSupervisorTests extends WindowTestsBase {
verify(taskChangeNotifier).notifyTaskFocusChanged(eq(taskB.mTaskId) /* taskId */,
eq(true) /* focused */);
}
+
+ @Test
+ /** Ensures that a trusted virtual display can launch arbitrary activities. */
+ public void testTrustedVirtualDisplayCanLaunchActivities() {
+ final DisplayContent newDisplay = addNewDisplayContentAt(DisplayContent.POSITION_TOP);
+ final Task stack = new StackBuilder(mRootWindowContainer)
+ .setDisplay(newDisplay).build();
+ final ActivityRecord unresizableActivity = stack.getTopNonFinishingActivity();
+ VirtualDisplay virtualDisplay = createVirtualDisplay(true);
+ final boolean allowed = mSupervisor.isCallerAllowedToLaunchOnDisplay(1234, 1234,
+ virtualDisplay.getDisplay().getDisplayId(), unresizableActivity.info);
+
+ assertThat(allowed).isTrue();
+ }
+
+ @Test
+ /** Ensures that an untrusted virtual display cannot launch arbitrary activities. */
+ public void testUntrustedVirtualDisplayCannotLaunchActivities() {
+ final DisplayContent newDisplay = addNewDisplayContentAt(DisplayContent.POSITION_TOP);
+ final Task stack = new StackBuilder(mRootWindowContainer)
+ .setDisplay(newDisplay).build();
+ final ActivityRecord unresizableActivity = stack.getTopNonFinishingActivity();
+ VirtualDisplay virtualDisplay = createVirtualDisplay(false);
+ final boolean allowed = mSupervisor.isCallerAllowedToLaunchOnDisplay(1234, 1234,
+ virtualDisplay.getDisplay().getDisplayId(), unresizableActivity.info);
+
+ assertThat(allowed).isFalse();
+ }
+
+ private VirtualDisplay createVirtualDisplay(boolean trusted) {
+ final DisplayManager dm = mContext.getSystemService(DisplayManager.class);
+ final DisplayInfo displayInfo = new DisplayInfo();
+ final Display defaultDisplay = dm.getDisplay(Display.DEFAULT_DISPLAY);
+ defaultDisplay.getDisplayInfo(displayInfo);
+ int flags = DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC;
+ if (trusted) {
+ flags |= DisplayManager.VIRTUAL_DISPLAY_FLAG_TRUSTED;
+ }
+
+ final ImageReader imageReader = ImageReader.newInstance(
+ displayInfo.logicalWidth, displayInfo.logicalHeight, PixelFormat.RGBA_8888, 2);
+
+ return dm.createVirtualDisplay("virtualDisplay", displayInfo.logicalWidth,
+ displayInfo.logicalHeight,
+ displayInfo.logicalDensityDpi, imageReader.getSurface(), flags);
+ }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/LockTaskControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/LockTaskControllerTest.java
index a137cde2d351..044f81986517 100644
--- a/services/tests/wmtests/src/com/android/server/wm/LockTaskControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/LockTaskControllerTest.java
@@ -168,8 +168,8 @@ public class LockTaskControllerTest {
@Test
public void testStartLockTaskMode_once() throws Exception {
- // GIVEN a task record with whitelisted auth
- Task tr = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
+ // GIVEN a task record with allowlisted auth
+ Task tr = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
// WHEN calling setLockTaskMode for LOCKED mode without resuming
mLockTaskController.startLockTaskMode(tr, false, TEST_UID);
@@ -185,9 +185,9 @@ public class LockTaskControllerTest {
@Test
public void testStartLockTaskMode_twice() throws Exception {
- // GIVEN two task records with whitelisted auth
- Task tr1 = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
- Task tr2 = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
+ // GIVEN two task records with allowlisted auth
+ Task tr1 = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
+ Task tr2 = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
// WHEN calling setLockTaskMode for LOCKED mode on both tasks
mLockTaskController.startLockTaskMode(tr1, false, TEST_UID);
@@ -205,7 +205,7 @@ public class LockTaskControllerTest {
@Test
public void testStartLockTaskMode_pinningRequest() {
- // GIVEN a task record that is not whitelisted, i.e. with pinned auth
+ // GIVEN a task record that is not allowlisted, i.e. with pinned auth
Task tr = getTask(Task.LOCK_TASK_AUTH_PINNABLE);
// WHEN calling startLockTaskMode
@@ -236,23 +236,23 @@ public class LockTaskControllerTest {
@Test
public void testLockTaskViolation() {
- // GIVEN one task record with whitelisted auth that is in lock task mode
- Task tr = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
+ // GIVEN one task record with allowlisted auth that is in lock task mode
+ Task tr = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
mLockTaskController.startLockTaskMode(tr, false, TEST_UID);
// THEN it's not a lock task violation to try and launch this task without clearing
assertFalse(mLockTaskController.isLockTaskModeViolation(tr, false));
- // THEN it's a lock task violation to launch another task that is not whitelisted
+ // THEN it's a lock task violation to launch another task that is not allowlisted
assertTrue(mLockTaskController.isLockTaskModeViolation(getTask(
Task.LOCK_TASK_AUTH_PINNABLE)));
// THEN it's a lock task violation to launch another task that is disallowed from lock task
assertTrue(mLockTaskController.isLockTaskModeViolation(getTask(
Task.LOCK_TASK_AUTH_DONT_LOCK)));
- // THEN it's no a lock task violation to launch another task that is whitelisted
+ // THEN it's no a lock task violation to launch another task that is allowlisted
assertFalse(mLockTaskController.isLockTaskModeViolation(getTask(
- Task.LOCK_TASK_AUTH_WHITELISTED)));
+ Task.LOCK_TASK_AUTH_ALLOWLISTED)));
assertFalse(mLockTaskController.isLockTaskModeViolation(getTask(
Task.LOCK_TASK_AUTH_LAUNCHABLE)));
// THEN it's not a lock task violation to launch another task that is priv launchable
@@ -262,8 +262,8 @@ public class LockTaskControllerTest {
@Test
public void testLockTaskViolation_emergencyCall() {
- // GIVEN one task record with whitelisted auth that is in lock task mode
- Task tr = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
+ // GIVEN one task record with allowlisted auth that is in lock task mode
+ Task tr = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
mLockTaskController.startLockTaskMode(tr, false, TEST_UID);
// GIVEN tasks necessary for emergency calling
@@ -294,8 +294,8 @@ public class LockTaskControllerTest {
@Test
public void testStopLockTaskMode() throws Exception {
- // GIVEN one task record with whitelisted auth that is in lock task mode
- Task tr = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
+ // GIVEN one task record with allowlisted auth that is in lock task mode
+ Task tr = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
mLockTaskController.startLockTaskMode(tr, false, TEST_UID);
// WHEN the same caller calls stopLockTaskMode
@@ -311,8 +311,8 @@ public class LockTaskControllerTest {
@Test(expected = SecurityException.class)
public void testStopLockTaskMode_differentCaller() {
- // GIVEN one task record with whitelisted auth that is in lock task mode
- Task tr = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
+ // GIVEN one task record with allowlisted auth that is in lock task mode
+ Task tr = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
mLockTaskController.startLockTaskMode(tr, false, TEST_UID);
// WHEN a different caller calls stopLockTaskMode
@@ -323,8 +323,8 @@ public class LockTaskControllerTest {
@Test
public void testStopLockTaskMode_systemCaller() {
- // GIVEN one task record with whitelisted auth that is in lock task mode
- Task tr = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
+ // GIVEN one task record with allowlisted auth that is in lock task mode
+ Task tr = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
mLockTaskController.startLockTaskMode(tr, false, TEST_UID);
// WHEN system calls stopLockTaskMode
@@ -336,9 +336,9 @@ public class LockTaskControllerTest {
@Test
public void testStopLockTaskMode_twoTasks() throws Exception {
- // GIVEN two task records with whitelisted auth that is in lock task mode
- Task tr1 = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
- Task tr2 = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
+ // GIVEN two task records with allowlisted auth that is in lock task mode
+ Task tr1 = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
+ Task tr2 = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
mLockTaskController.startLockTaskMode(tr1, false, TEST_UID);
mLockTaskController.startLockTaskMode(tr2, false, TEST_UID);
@@ -357,9 +357,9 @@ public class LockTaskControllerTest {
@Test
public void testStopLockTaskMode_rootTask() throws Exception {
- // GIVEN two task records with whitelisted auth that is in lock task mode
- Task tr1 = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
- Task tr2 = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
+ // GIVEN two task records with allowlisted auth that is in lock task mode
+ Task tr1 = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
+ Task tr2 = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
mLockTaskController.startLockTaskMode(tr1, false, TEST_UID);
mLockTaskController.startLockTaskMode(tr2, false, TEST_UID);
@@ -405,9 +405,9 @@ public class LockTaskControllerTest {
@Test
public void testClearLockedTasks() throws Exception {
- // GIVEN two task records with whitelisted auth that is in lock task mode
- Task tr1 = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
- Task tr2 = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
+ // GIVEN two task records with allowlisted auth that is in lock task mode
+ Task tr1 = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
+ Task tr2 = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
mLockTaskController.startLockTaskMode(tr1, false, TEST_UID);
mLockTaskController.startLockTaskMode(tr2, false, TEST_UID);
@@ -434,7 +434,7 @@ public class LockTaskControllerTest {
.thenReturn(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED);
// AND there is a task record
- Task tr1 = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
+ Task tr1 = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
mLockTaskController.startLockTaskMode(tr1, true, TEST_UID);
// WHEN calling clearLockedTasks on the root task
@@ -454,7 +454,7 @@ public class LockTaskControllerTest {
.thenReturn(true);
// AND there is a task record
- Task tr1 = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
+ Task tr1 = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
mLockTaskController.startLockTaskMode(tr1, true, TEST_UID);
// WHEN calling clearLockedTasks on the root task
@@ -471,7 +471,7 @@ public class LockTaskControllerTest {
Settings.Secure.LOCK_TO_APP_EXIT_LOCKED, 1, mContext.getUserId());
// AND there is a task record
- Task tr1 = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
+ Task tr1 = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
mLockTaskController.startLockTaskMode(tr1, true, TEST_UID);
// WHEN calling clearLockedTasks on the root task
@@ -488,7 +488,7 @@ public class LockTaskControllerTest {
Settings.Secure.LOCK_TO_APP_EXIT_LOCKED, 0, mContext.getUserId());
// AND there is a task record
- Task tr1 = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
+ Task tr1 = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
mLockTaskController.startLockTaskMode(tr1, true, TEST_UID);
// WHEN calling clearLockedTasks on the root task
@@ -500,45 +500,45 @@ public class LockTaskControllerTest {
@Test
public void testUpdateLockTaskPackages() {
- String[] whitelist1 = {TEST_PACKAGE_NAME, TEST_PACKAGE_NAME_2};
- String[] whitelist2 = {TEST_PACKAGE_NAME};
-
- // No package is whitelisted initially
- for (String pkg : whitelist1) {
- assertFalse("Package shouldn't be whitelisted: " + pkg,
- mLockTaskController.isPackageWhitelisted(TEST_USER_ID, pkg));
- assertFalse("Package shouldn't be whitelisted for user 0: " + pkg,
- mLockTaskController.isPackageWhitelisted(0, pkg));
+ String[] allowlist1 = {TEST_PACKAGE_NAME, TEST_PACKAGE_NAME_2};
+ String[] allowlist2 = {TEST_PACKAGE_NAME};
+
+ // No package is allowlisted initially
+ for (String pkg : allowlist1) {
+ assertFalse("Package shouldn't be allowlisted: " + pkg,
+ mLockTaskController.isPackageAllowlisted(TEST_USER_ID, pkg));
+ assertFalse("Package shouldn't be allowlisted for user 0: " + pkg,
+ mLockTaskController.isPackageAllowlisted(0, pkg));
}
- // Apply whitelist
- mLockTaskController.updateLockTaskPackages(TEST_USER_ID, whitelist1);
+ // Apply allowlist
+ mLockTaskController.updateLockTaskPackages(TEST_USER_ID, allowlist1);
- // Assert the whitelist is applied to the correct user
- for (String pkg : whitelist1) {
- assertTrue("Package should be whitelisted: " + pkg,
- mLockTaskController.isPackageWhitelisted(TEST_USER_ID, pkg));
- assertFalse("Package shouldn't be whitelisted for user 0: " + pkg,
- mLockTaskController.isPackageWhitelisted(0, pkg));
+ // Assert the allowlist is applied to the correct user
+ for (String pkg : allowlist1) {
+ assertTrue("Package should be allowlisted: " + pkg,
+ mLockTaskController.isPackageAllowlisted(TEST_USER_ID, pkg));
+ assertFalse("Package shouldn't be allowlisted for user 0: " + pkg,
+ mLockTaskController.isPackageAllowlisted(0, pkg));
}
- // Update whitelist
- mLockTaskController.updateLockTaskPackages(TEST_USER_ID, whitelist2);
+ // Update allowlist
+ mLockTaskController.updateLockTaskPackages(TEST_USER_ID, allowlist2);
- // Assert the new whitelist is applied
- assertTrue("Package should remain whitelisted: " + TEST_PACKAGE_NAME,
- mLockTaskController.isPackageWhitelisted(TEST_USER_ID, TEST_PACKAGE_NAME));
- assertFalse("Package should no longer be whitelisted: " + TEST_PACKAGE_NAME_2,
- mLockTaskController.isPackageWhitelisted(TEST_USER_ID, TEST_PACKAGE_NAME_2));
+ // Assert the new allowlist is applied
+ assertTrue("Package should remain allowlisted: " + TEST_PACKAGE_NAME,
+ mLockTaskController.isPackageAllowlisted(TEST_USER_ID, TEST_PACKAGE_NAME));
+ assertFalse("Package should no longer be allowlisted: " + TEST_PACKAGE_NAME_2,
+ mLockTaskController.isPackageAllowlisted(TEST_USER_ID, TEST_PACKAGE_NAME_2));
}
@Test
public void testUpdateLockTaskPackages_taskRemoved() throws Exception {
- // GIVEN two tasks which are whitelisted initially
+ // GIVEN two tasks which are allowlisted initially
Task tr1 = getTaskForUpdate(TEST_PACKAGE_NAME, true);
Task tr2 = getTaskForUpdate(TEST_PACKAGE_NAME_2, false);
- String[] whitelist = {TEST_PACKAGE_NAME, TEST_PACKAGE_NAME_2};
- mLockTaskController.updateLockTaskPackages(TEST_USER_ID, whitelist);
+ String[] allowlist = {TEST_PACKAGE_NAME, TEST_PACKAGE_NAME_2};
+ mLockTaskController.updateLockTaskPackages(TEST_USER_ID, allowlist);
// GIVEN the tasks are launched into LockTask mode
mLockTaskController.startLockTaskMode(tr1, false, TEST_UID);
@@ -548,9 +548,9 @@ public class LockTaskControllerTest {
assertTrue(mLockTaskController.isTaskLocked(tr2));
verifyLockTaskStarted(STATUS_BAR_MASK_LOCKED, DISABLE2_MASK);
- // WHEN removing one package from whitelist
- whitelist = new String[] {TEST_PACKAGE_NAME};
- mLockTaskController.updateLockTaskPackages(TEST_USER_ID, whitelist);
+ // WHEN removing one package from allowlist
+ allowlist = new String[] {TEST_PACKAGE_NAME};
+ mLockTaskController.updateLockTaskPackages(TEST_USER_ID, allowlist);
// THEN the task running that package should be stopped
verify(tr2).performClearTaskLocked();
@@ -560,9 +560,9 @@ public class LockTaskControllerTest {
assertTrue(mLockTaskController.isTaskLocked(tr1));
verifyLockTaskStarted(STATUS_BAR_MASK_LOCKED, DISABLE2_MASK);
- // WHEN removing the last package from whitelist
- whitelist = new String[] {};
- mLockTaskController.updateLockTaskPackages(TEST_USER_ID, whitelist);
+ // WHEN removing the last package from allowlist
+ allowlist = new String[] {};
+ mLockTaskController.updateLockTaskPackages(TEST_USER_ID, allowlist);
// THEN the last task should be cleared, and the system should quit LockTask mode
verify(tr1).performClearTaskLocked();
@@ -574,7 +574,7 @@ public class LockTaskControllerTest {
@Test
public void testUpdateLockTaskFeatures() throws Exception {
// GIVEN a locked task
- Task tr = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
+ Task tr = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
mLockTaskController.startLockTaskMode(tr, false, TEST_UID);
// THEN lock task mode should be started with default status bar masks
@@ -616,7 +616,7 @@ public class LockTaskControllerTest {
@Test
public void testUpdateLockTaskFeatures_differentUser() throws Exception {
// GIVEN a locked task
- Task tr = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
+ Task tr = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
mLockTaskController.startLockTaskMode(tr, false, TEST_UID);
// THEN lock task mode should be started with default status bar masks
@@ -638,7 +638,7 @@ public class LockTaskControllerTest {
@Test
public void testUpdateLockTaskFeatures_keyguard() {
// GIVEN a locked task
- Task tr = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
+ Task tr = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
mLockTaskController.startLockTaskMode(tr, false, TEST_UID);
// THEN keyguard should be disabled
@@ -704,7 +704,7 @@ public class LockTaskControllerTest {
TEST_USER_ID, TEST_PACKAGE_NAME, LOCK_TASK_LAUNCH_MODE_DEFAULT));
// Start lock task mode
- Task tr = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
+ Task tr = getTask(Task.LOCK_TASK_AUTH_ALLOWLISTED);
mLockTaskController.startLockTaskMode(tr, false, TEST_UID);
// WHEN LOCK_TASK_FEATURE_BLOCK_ACTIVITY_START_IN_TASK is not enabled
@@ -719,15 +719,15 @@ public class LockTaskControllerTest {
assertTrue(mLockTaskController.isActivityAllowed(
TEST_USER_ID, TEST_PACKAGE_NAME, LOCK_TASK_LAUNCH_MODE_ALWAYS));
- // unwhitelisted package should not be allowed
+ // unallowlisted package should not be allowed
assertFalse(mLockTaskController.isActivityAllowed(
TEST_USER_ID, TEST_PACKAGE_NAME, LOCK_TASK_LAUNCH_MODE_DEFAULT));
- // update the whitelist
- String[] whitelist = new String[] { TEST_PACKAGE_NAME };
- mLockTaskController.updateLockTaskPackages(TEST_USER_ID, whitelist);
+ // update the allowlist
+ String[] allowlist = new String[] { TEST_PACKAGE_NAME };
+ mLockTaskController.updateLockTaskPackages(TEST_USER_ID, allowlist);
- // whitelisted package should be allowed
+ // allowlisted package should be allowed
assertTrue(mLockTaskController.isActivityAllowed(
TEST_USER_ID, TEST_PACKAGE_NAME, LOCK_TASK_LAUNCH_MODE_DEFAULT));
@@ -755,17 +755,17 @@ public class LockTaskControllerTest {
}
/**
- * @param isAppAware {@code true} if the app has marked if_whitelisted in its manifest
+ * @param isAppAware {@code true} if the app has marked if allowlisted in its manifest
*/
private Task getTaskForUpdate(String pkg, boolean isAppAware) {
- final int authIfWhitelisted = isAppAware
+ final int authIfAllowlisted = isAppAware
? Task.LOCK_TASK_AUTH_LAUNCHABLE
- : Task.LOCK_TASK_AUTH_WHITELISTED;
- Task tr = getTask(pkg, authIfWhitelisted);
+ : Task.LOCK_TASK_AUTH_ALLOWLISTED;
+ Task tr = getTask(pkg, authIfAllowlisted);
doAnswer((invocation) -> {
- boolean isWhitelisted =
- mLockTaskController.isPackageWhitelisted(TEST_USER_ID, pkg);
- tr.mLockTaskAuth = isWhitelisted ? authIfWhitelisted : Task.LOCK_TASK_AUTH_PINNABLE;
+ boolean isAllowlisted =
+ mLockTaskController.isPackageAllowlisted(TEST_USER_ID, pkg);
+ tr.mLockTaskAuth = isAllowlisted ? authIfAllowlisted : Task.LOCK_TASK_AUTH_PINNABLE;
return null;
}).when(tr).setLockTaskAuth();
return tr;
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java
index d950344538a0..b4a13375aeec 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java
@@ -16,6 +16,7 @@
package com.android.server.wm;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
@@ -87,7 +88,7 @@ public class TaskSnapshotSurfaceTest extends WindowTestsBase {
0 /* systemUiVisibility */, false /* isTranslucent */);
mSurface = new TaskSnapshotSurface(mWm, new Window(), new SurfaceControl(), snapshot, "Test",
createTaskDescription(Color.WHITE, Color.RED, Color.BLUE), sysuiVis, windowFlags, 0,
- taskBounds, ORIENTATION_PORTRAIT, new InsetsState());
+ taskBounds, ORIENTATION_PORTRAIT, ACTIVITY_TYPE_STANDARD, new InsetsState());
}
private static TaskDescription createTaskDescription(int background, int statusBar,
diff --git a/startop/OWNERS b/startop/OWNERS
index 3394be9779e3..2d1eb38952ed 100644
--- a/startop/OWNERS
+++ b/startop/OWNERS
@@ -1,7 +1,7 @@
# mailing list: startop-eng@google.com
+calin@google.com
chriswailes@google.com
eholk@google.com
iam@google.com
mathieuc@google.com
-sehr@google.com
yawanng@google.com
diff --git a/test-runner/src/android/test/AndroidTestRunner.java b/test-runner/src/android/test/AndroidTestRunner.java
index f898516a001b..b2fdc5084834 100644
--- a/test-runner/src/android/test/AndroidTestRunner.java
+++ b/test-runner/src/android/test/AndroidTestRunner.java
@@ -125,7 +125,7 @@ public class AndroidTestRunner extends BaseTestRunner {
} catch (IllegalArgumentException e) {
runFailed("Illegal argument passed to constructor. Class: " + testClass.getName());
} catch (InvocationTargetException e) {
- runFailed("Constructor thew an exception. Class: " + testClass.getName());
+ runFailed("Constructor threw an exception. Class: " + testClass.getName());
}
return null;
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt
index 2e4d390ceb60..c0658fe4422e 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt
@@ -84,7 +84,7 @@ class CloseImeAutoOpenWindowToHomeTest(
navBarLayerIsAlwaysVisible(bugId = 140855415)
statusBarLayerIsAlwaysVisible(bugId = 140855415)
noUncoveredRegions(rotation, Surface.ROTATION_0, allStates = false)
- navBarLayerRotatesAndScales(rotation, Surface.ROTATION_0)
+ navBarLayerRotatesAndScales(rotation, Surface.ROTATION_0, bugId = 140855415)
statusBarLayerRotatesScales(rotation, Surface.ROTATION_0)
imeLayerBecomesInvisible(bugId = 141458352)
imeAppLayerBecomesInvisible(testApp, bugId = 153739621)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt
index 1c0da4f920bb..dcf308533ee6 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt
@@ -92,7 +92,7 @@ open class CloseImeWindowToHomeTest(
navBarLayerIsAlwaysVisible(bugId = 140855415)
statusBarLayerIsAlwaysVisible(bugId = 140855415)
noUncoveredRegions(rotation, Surface.ROTATION_0, allStates = false)
- navBarLayerRotatesAndScales(rotation, Surface.ROTATION_0)
+ navBarLayerRotatesAndScales(rotation, Surface.ROTATION_0, bugId = 140855415)
statusBarLayerRotatesScales(rotation, Surface.ROTATION_0)
imeLayerBecomesInvisible(bugId = 153739621)
imeAppLayerBecomesInvisible(testApp, bugId = 153739621)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/OpenAppToSplitScreenTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/OpenAppToSplitScreenTest.kt
index e078f266e5ed..91ec211805f7 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/OpenAppToSplitScreenTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/OpenAppToSplitScreenTest.kt
@@ -90,7 +90,7 @@ class OpenAppToSplitScreenTest(
navBarLayerIsAlwaysVisible()
statusBarLayerIsAlwaysVisible()
noUncoveredRegions(rotation)
- navBarLayerRotatesAndScales(rotation)
+ navBarLayerRotatesAndScales(rotation, bugId = 140855415)
statusBarLayerRotatesScales(rotation)
all("dividerLayerBecomesVisible") {
@@ -102,7 +102,8 @@ class OpenAppToSplitScreenTest(
eventLog {
focusChanges(testApp.`package`,
- "recents_animation_input_consumer", "NexusLauncherActivity")
+ "recents_animation_input_consumer", "NexusLauncherActivity",
+ bugId = 151179149)
}
}
}
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/ColorFiltersMutateActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/ColorFiltersMutateActivity.java
index 51bae3af3e9c..08144c845555 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/ColorFiltersMutateActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/ColorFiltersMutateActivity.java
@@ -60,7 +60,7 @@ public class ColorFiltersMutateActivity extends Activity {
static final String sSkSL =
"uniform float param1;\n"
- + "void main(float x, float y, inout half4 color) {\n"
+ + "void main(float2 xy, inout half4 color) {\n"
+ "color = half4(color.r, half(param1), color.b, 1.0);\n"
+ "}\n";
diff --git a/tests/Input/Android.bp b/tests/Input/Android.bp
new file mode 100644
index 000000000000..9d35cbc3de7f
--- /dev/null
+++ b/tests/Input/Android.bp
@@ -0,0 +1,12 @@
+android_test {
+ name: "InputTests",
+ srcs: ["src/**/*.kt"],
+ platform_apis: true,
+ certificate: "platform",
+ static_libs: [
+ "androidx.test.ext.junit",
+ "androidx.test.rules",
+ "android-support-test",
+ "ub-uiautomator",
+ ],
+}
diff --git a/tests/Input/AndroidManifest.xml b/tests/Input/AndroidManifest.xml
new file mode 100644
index 000000000000..4195df72864c
--- /dev/null
+++ b/tests/Input/AndroidManifest.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT 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.test.input">
+ <uses-permission android:name="android.permission.MONITOR_INPUT"/>
+ <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS"/>
+ <uses-permission android:name="android.permission.INJECT_EVENTS"/>
+
+ <application android:label="InputTest">
+
+ <activity android:name=".UnresponsiveGestureMonitorActivity"
+ android:label="Unresponsive gesture monitor"
+ android:process=":externalProcess">
+ </activity>
+
+
+ </application>
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.test.input"
+ android:label="Input Tests"/>
+</manifest>
diff --git a/tests/Input/AndroidTest.xml b/tests/Input/AndroidTest.xml
new file mode 100644
index 000000000000..c62db1ea5ca9
--- /dev/null
+++ b/tests/Input/AndroidTest.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright 2020 Google Inc. All Rights Reserved.
+ -->
+<configuration description="Runs Input Tests">
+ <option name="test-tag" value="InputTests" />
+ <target_preparer class="com.android.tradefed.targetprep.DeviceSetup">
+ <!-- keeps the screen on during tests -->
+ <option name="screen-always-on" value="on" />
+ <!-- prevents the phone from restarting -->
+ <option name="force-skip-system-props" value="true" />
+ </target_preparer>
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true"/>
+ <option name="test-file-name" value="InputTests.apk"/>
+
+ </target_preparer>
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest">
+ <option name="package" value="com.android.test.input"/>
+ <option name="exclude-annotation" value="androidx.test.filters.FlakyTest" />
+ <option name="shell-timeout" value="660s" />
+ <option name="test-timeout" value="600s" />
+ <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
+ </test>
+</configuration>
diff --git a/tests/Input/src/com/android/test/input/AnrTest.kt b/tests/Input/src/com/android/test/input/AnrTest.kt
new file mode 100644
index 000000000000..4da3eca25ea0
--- /dev/null
+++ b/tests/Input/src/com/android/test/input/AnrTest.kt
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.test.input
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.filters.MediumTest
+
+import android.graphics.Rect
+import android.os.SystemClock
+import android.provider.Settings
+import android.provider.Settings.Global.HIDE_ERROR_DIALOGS
+import android.support.test.uiautomator.By
+import android.support.test.uiautomator.UiDevice
+import android.support.test.uiautomator.UiObject2
+import android.support.test.uiautomator.Until
+import android.view.InputDevice
+import android.view.MotionEvent
+
+import org.junit.After
+import org.junit.Assert.fail
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+/**
+ * This test makes sure that an unresponsive gesture monitor gets an ANR.
+ *
+ * The gesture monitor must be registered from a different process than the instrumented process.
+ * Otherwise, when the test runs, you will get:
+ * Test failed to run to completion.
+ * Reason: 'Instrumentation run failed due to 'keyDispatchingTimedOut''.
+ * Check device logcat for details
+ * RUNNER ERROR: Instrumentation run failed due to 'keyDispatchingTimedOut'
+ */
+@MediumTest
+@RunWith(AndroidJUnit4::class)
+class AnrTest {
+ companion object {
+ private const val TAG = "AnrTest"
+ }
+
+ val mInstrumentation = InstrumentationRegistry.getInstrumentation()
+ var mHideErrorDialogs = 0
+
+ @Before
+ fun setUp() {
+ val contentResolver = mInstrumentation.targetContext.contentResolver
+ mHideErrorDialogs = Settings.Global.getInt(contentResolver, HIDE_ERROR_DIALOGS, 0)
+ Settings.Global.putInt(contentResolver, HIDE_ERROR_DIALOGS, 0)
+ }
+
+ @After
+ fun tearDown() {
+ val contentResolver = mInstrumentation.targetContext.contentResolver
+ Settings.Global.putInt(contentResolver, HIDE_ERROR_DIALOGS, mHideErrorDialogs)
+ }
+
+ @Test
+ fun testGestureMonitorAnr() {
+ startUnresponsiveActivity()
+ val uiDevice: UiDevice = UiDevice.getInstance(mInstrumentation)
+ val obj: UiObject2? = uiDevice.wait(Until.findObject(
+ By.text("Unresponsive gesture monitor")), 10000)
+
+ if (obj == null) {
+ fail("Could not find unresponsive activity")
+ return
+ }
+
+ val rect: Rect = obj.visibleBounds
+ val downTime = SystemClock.uptimeMillis()
+ val downEvent = MotionEvent.obtain(downTime, downTime,
+ MotionEvent.ACTION_DOWN, rect.left.toFloat(), rect.top.toFloat(), 0 /* metaState */)
+ downEvent.source = InputDevice.SOURCE_TOUCHSCREEN
+
+ mInstrumentation.uiAutomation.injectInputEvent(downEvent, false /* sync*/)
+
+ // Todo: replace using timeout from android.hardware.input.IInputManager
+ SystemClock.sleep(5000) // default ANR timeout for gesture monitors
+
+ clickCloseAppOnAnrDialog()
+ }
+
+ private fun clickCloseAppOnAnrDialog() {
+ // Find anr dialog and kill app
+ val uiDevice: UiDevice = UiDevice.getInstance(mInstrumentation)
+ val closeAppButton: UiObject2? =
+ uiDevice.wait(Until.findObject(By.res("android:id/aerr_close")), 20000)
+ if (closeAppButton == null) {
+ fail("Could not find anr dialog")
+ return
+ }
+ closeAppButton.click()
+ }
+
+ private fun startUnresponsiveActivity() {
+ val flags = " -W -n "
+ val startCmd = "am start $flags com.android.test.input/.UnresponsiveGestureMonitorActivity"
+ mInstrumentation.uiAutomation.executeShellCommand(startCmd)
+ }
+} \ No newline at end of file
diff --git a/tests/Input/src/com/android/test/input/UnresponsiveGestureMonitorActivity.kt b/tests/Input/src/com/android/test/input/UnresponsiveGestureMonitorActivity.kt
new file mode 100644
index 000000000000..d83a4570fedc
--- /dev/null
+++ b/tests/Input/src/com/android/test/input/UnresponsiveGestureMonitorActivity.kt
@@ -0,0 +1,52 @@
+/**
+ * Copyright (c) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.test.input
+
+import android.app.Activity
+import android.hardware.input.InputManager
+import android.os.Bundle
+import android.os.Looper
+import android.util.Log
+import android.view.InputChannel
+import android.view.InputEvent
+import android.view.InputEventReceiver
+import android.view.InputMonitor
+
+class UnresponsiveReceiver(channel: InputChannel, looper: Looper) :
+ InputEventReceiver(channel, looper) {
+ companion object {
+ const val TAG = "UnresponsiveReceiver"
+ }
+ override fun onInputEvent(event: InputEvent) {
+ Log.i(TAG, "Received $event")
+ // Not calling 'finishInputEvent' in order to trigger the ANR
+ }
+}
+
+class UnresponsiveGestureMonitorActivity : Activity() {
+ companion object {
+ const val MONITOR_NAME = "unresponsive gesture monitor"
+ }
+ private lateinit var mInputEventReceiver: InputEventReceiver
+ private lateinit var mInputMonitor: InputMonitor
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ mInputMonitor = InputManager.getInstance().monitorGestureInput(MONITOR_NAME, displayId)
+ mInputEventReceiver = UnresponsiveReceiver(
+ mInputMonitor.getInputChannel(), Looper.myLooper())
+ }
+}
diff --git a/tests/StagedInstallTest/Android.bp b/tests/StagedInstallTest/Android.bp
index da6018e2e2c9..530d0e492f2e 100644
--- a/tests/StagedInstallTest/Android.bp
+++ b/tests/StagedInstallTest/Android.bp
@@ -29,6 +29,7 @@ java_test_host {
"compatibility-tradefed",
"frameworks-base-hostutils",
"module_test_util",
+ "cts-install-lib-host",
],
data: [
":com.android.apex.cts.shim.v2_prebuilt",
diff --git a/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java b/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java
index 7cfbdc2b5062..5285b04f67d7 100644
--- a/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java
+++ b/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java
@@ -22,6 +22,7 @@ import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.junit.Assume.assumeTrue;
+import com.android.cts.install.lib.host.InstallUtilsHost;
import com.android.ddmlib.Log;
import com.android.tests.rollback.host.AbandonSessionsRule;
import com.android.tests.util.ModuleTestUtils;
@@ -49,6 +50,7 @@ public class StagedInstallInternalTest extends BaseHostJUnit4Test {
private static final String APK_A = "TestAppAv1.apk";
private final ModuleTestUtils mTestUtils = new ModuleTestUtils(this);
+ private final InstallUtilsHost mHostUtils = new InstallUtilsHost(this);
/**
* Runs the given phase of a test by calling into the device.
@@ -93,7 +95,7 @@ public class StagedInstallInternalTest extends BaseHostJUnit4Test {
@Test
public void testAdbStagedInstallWaitForReadyFlagWorks() throws Exception {
assumeTrue("Device does not support updating APEX",
- mTestUtils.isApexUpdateSupported());
+ mHostUtils.isApexUpdateSupported());
File apexFile = mTestUtils.getTestFile(SHIM_V2);
String output = getDevice().executeAdbCommand("install", "--staged",
@@ -107,7 +109,7 @@ public class StagedInstallInternalTest extends BaseHostJUnit4Test {
@Test
public void testAdbStagedInstallNoWaitFlagWorks() throws Exception {
assumeTrue("Device does not support updating APEX",
- mTestUtils.isApexUpdateSupported());
+ mHostUtils.isApexUpdateSupported());
File apexFile = mTestUtils.getTestFile(SHIM_V2);
String output = getDevice().executeAdbCommand("install", "--staged",
@@ -122,7 +124,7 @@ public class StagedInstallInternalTest extends BaseHostJUnit4Test {
@Test
public void testAdbInstallMultiPackageCommandWorks() throws Exception {
assumeTrue("Device does not support updating APEX",
- mTestUtils.isApexUpdateSupported());
+ mHostUtils.isApexUpdateSupported());
File apexFile = mTestUtils.getTestFile(SHIM_V2);
File apkFile = mTestUtils.getTestFile(APK_A);
diff --git a/tests/net/java/com/android/server/connectivity/VpnTest.java b/tests/net/java/com/android/server/connectivity/VpnTest.java
index 4ccf79a0cb37..de1c5759ee87 100644
--- a/tests/net/java/com/android/server/connectivity/VpnTest.java
+++ b/tests/net/java/com/android/server/connectivity/VpnTest.java
@@ -30,6 +30,7 @@ import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
import static android.net.NetworkCapabilities.TRANSPORT_VPN;
import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
+import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
@@ -49,6 +50,7 @@ import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.annotation.NonNull;
import android.annotation.UserIdInt;
import android.app.AppOpsManager;
import android.app.NotificationManager;
@@ -65,6 +67,7 @@ import android.net.InetAddresses;
import android.net.IpPrefix;
import android.net.IpSecManager;
import android.net.LinkProperties;
+import android.net.LocalSocket;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkInfo.DetailedState;
@@ -74,6 +77,7 @@ import android.net.VpnManager;
import android.net.VpnService;
import android.os.Build.VERSION_CODES;
import android.os.Bundle;
+import android.os.ConditionVariable;
import android.os.INetworkManagementService;
import android.os.Looper;
import android.os.Process;
@@ -101,13 +105,20 @@ import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
import java.net.Inet4Address;
+import java.net.InetAddress;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.TimeUnit;
import java.util.stream.Stream;
/**
@@ -133,7 +144,8 @@ public class VpnTest {
managedProfileA.profileGroupId = primaryUser.id;
}
- static final String TEST_VPN_PKG = "com.dummy.vpn";
+ static final String EGRESS_IFACE = "wlan0";
+ static final String TEST_VPN_PKG = "com.testvpn.vpn";
private static final String TEST_VPN_SERVER = "1.2.3.4";
private static final String TEST_VPN_IDENTITY = "identity";
private static final byte[] TEST_VPN_PSK = "psk".getBytes();
@@ -1012,31 +1024,190 @@ public class VpnTest {
// a subsequent CL.
}
- @Test
- public void testStartLegacyVpn() throws Exception {
+ public Vpn startLegacyVpn(final VpnProfile vpnProfile) throws Exception {
final Vpn vpn = createVpn(primaryUser.id);
setMockedUsers(primaryUser);
// Dummy egress interface
- final String egressIface = "DUMMY0";
final LinkProperties lp = new LinkProperties();
- lp.setInterfaceName(egressIface);
+ lp.setInterfaceName(EGRESS_IFACE);
final RouteInfo defaultRoute = new RouteInfo(new IpPrefix(Inet4Address.ANY, 0),
- InetAddresses.parseNumericAddress("192.0.2.0"), egressIface);
+ InetAddresses.parseNumericAddress("192.0.2.0"), EGRESS_IFACE);
lp.addRoute(defaultRoute);
- vpn.startLegacyVpn(mVpnProfile, mKeyStore, lp);
+ vpn.startLegacyVpn(vpnProfile, mKeyStore, lp);
+ return vpn;
+ }
+ @Test
+ public void testStartPlatformVpn() throws Exception {
+ startLegacyVpn(mVpnProfile);
// TODO: Test the Ikev2VpnRunner started up properly. Relies on utility methods added in
- // a subsequent CL.
+ // a subsequent patch.
+ }
+
+ @Test
+ public void testStartRacoonNumericAddress() throws Exception {
+ startRacoon("1.2.3.4", "1.2.3.4");
+ }
+
+ @Test
+ public void testStartRacoonHostname() throws Exception {
+ startRacoon("hostname", "5.6.7.8"); // address returned by deps.resolve
+ }
+
+ public void startRacoon(final String serverAddr, final String expectedAddr)
+ throws Exception {
+ final ConditionVariable legacyRunnerReady = new ConditionVariable();
+ final VpnProfile profile = new VpnProfile("testProfile" /* key */);
+ profile.type = VpnProfile.TYPE_L2TP_IPSEC_PSK;
+ profile.name = "testProfileName";
+ profile.username = "userName";
+ profile.password = "thePassword";
+ profile.server = serverAddr;
+ profile.ipsecIdentifier = "id";
+ profile.ipsecSecret = "secret";
+ profile.l2tpSecret = "l2tpsecret";
+ when(mConnectivityManager.getAllNetworks())
+ .thenReturn(new Network[] { new Network(101) });
+ when(mConnectivityManager.registerNetworkAgent(any(), any(), any(), any(),
+ anyInt(), any(), anyInt())).thenAnswer(invocation -> {
+ // The runner has registered an agent and is now ready.
+ legacyRunnerReady.open();
+ return new Network(102);
+ });
+ final Vpn vpn = startLegacyVpn(profile);
+ final TestDeps deps = (TestDeps) vpn.mDeps;
+ try {
+ // udppsk and 1701 are the values for TYPE_L2TP_IPSEC_PSK
+ assertArrayEquals(
+ new String[] { EGRESS_IFACE, expectedAddr, "udppsk",
+ profile.ipsecIdentifier, profile.ipsecSecret, "1701" },
+ deps.racoonArgs.get(10, TimeUnit.SECONDS));
+ // literal values are hardcoded in Vpn.java for mtpd args
+ assertArrayEquals(
+ new String[] { EGRESS_IFACE, "l2tp", expectedAddr, "1701", profile.l2tpSecret,
+ "name", profile.username, "password", profile.password,
+ "linkname", "vpn", "refuse-eap", "nodefaultroute", "usepeerdns",
+ "idle", "1800", "mtu", "1400", "mru", "1400" },
+ deps.mtpdArgs.get(10, TimeUnit.SECONDS));
+ // Now wait for the runner to be ready before testing for the route.
+ legacyRunnerReady.block(10_000);
+ // In this test the expected address is always v4 so /32
+ final RouteInfo expectedRoute = new RouteInfo(new IpPrefix(expectedAddr + "/32"),
+ RouteInfo.RTN_THROW);
+ assertTrue("Routes lack the expected throw route (" + expectedRoute + ") : "
+ + vpn.mConfig.routes,
+ vpn.mConfig.routes.contains(expectedRoute));
+ } finally {
+ // Now interrupt the thread, unblock the runner and clean up.
+ vpn.mVpnRunner.exitVpnRunner();
+ deps.getStateFile().delete(); // set to delete on exit, but this deletes it earlier
+ vpn.mVpnRunner.join(10_000); // wait for up to 10s for the runner to die and cleanup
+ }
+ }
+
+ private static final class TestDeps extends Vpn.Dependencies {
+ public final CompletableFuture<String[]> racoonArgs = new CompletableFuture();
+ public final CompletableFuture<String[]> mtpdArgs = new CompletableFuture();
+ public final File mStateFile;
+
+ private final HashMap<String, Boolean> mRunningServices = new HashMap<>();
+
+ TestDeps() {
+ try {
+ mStateFile = File.createTempFile("vpnTest", ".tmp");
+ mStateFile.deleteOnExit();
+ } catch (final IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ public void startService(final String serviceName) {
+ mRunningServices.put(serviceName, true);
+ }
+
+ @Override
+ public void stopService(final String serviceName) {
+ mRunningServices.put(serviceName, false);
+ }
+
+ @Override
+ public boolean isServiceRunning(final String serviceName) {
+ return mRunningServices.getOrDefault(serviceName, false);
+ }
+
+ @Override
+ public boolean isServiceStopped(final String serviceName) {
+ return !isServiceRunning(serviceName);
+ }
+
+ @Override
+ public File getStateFile() {
+ return mStateFile;
+ }
+
+ @Override
+ public void sendArgumentsToDaemon(
+ final String daemon, final LocalSocket socket, final String[] arguments,
+ final Vpn.RetryScheduler interruptChecker) throws IOException {
+ if ("racoon".equals(daemon)) {
+ racoonArgs.complete(arguments);
+ } else if ("mtpd".equals(daemon)) {
+ writeStateFile(arguments);
+ mtpdArgs.complete(arguments);
+ } else {
+ throw new UnsupportedOperationException("Unsupported daemon : " + daemon);
+ }
+ }
+
+ private void writeStateFile(final String[] arguments) throws IOException {
+ mStateFile.delete();
+ mStateFile.createNewFile();
+ mStateFile.deleteOnExit();
+ final BufferedWriter writer = new BufferedWriter(
+ new FileWriter(mStateFile, false /* append */));
+ writer.write(EGRESS_IFACE);
+ writer.write("\n");
+ // addresses
+ writer.write("10.0.0.1/24\n");
+ // routes
+ writer.write("192.168.6.0/24\n");
+ // dns servers
+ writer.write("192.168.6.1\n");
+ // search domains
+ writer.write("vpn.searchdomains.com\n");
+ // endpoint - intentionally empty
+ writer.write("\n");
+ writer.flush();
+ writer.close();
+ }
+
+ @Override
+ @NonNull
+ public InetAddress resolve(final String endpoint) {
+ try {
+ // If a numeric IP address, return it.
+ return InetAddress.parseNumericAddress(endpoint);
+ } catch (IllegalArgumentException e) {
+ // Otherwise, return some token IP to test for.
+ return InetAddress.parseNumericAddress("5.6.7.8");
+ }
+ }
+
+ @Override
+ public boolean checkInterfacePresent(final Vpn vpn, final String iface) {
+ return true;
+ }
}
/**
* Mock some methods of vpn object.
*/
private Vpn createVpn(@UserIdInt int userId) {
- return new Vpn(Looper.myLooper(), mContext, mNetService,
+ return new Vpn(Looper.myLooper(), mContext, new TestDeps(), mNetService,
userId, mKeyStore, mSystemServices, mIkev2SessionCreator);
}
diff --git a/tests/utils/hostutils/src/com/android/internal/util/test/SystemPreparer.java b/tests/utils/hostutils/src/com/android/internal/util/test/SystemPreparer.java
index f30c35aca8da..c2a5459ae125 100644
--- a/tests/utils/hostutils/src/com/android/internal/util/test/SystemPreparer.java
+++ b/tests/utils/hostutils/src/com/android/internal/util/test/SystemPreparer.java
@@ -34,6 +34,8 @@ import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.nio.file.Path;
+import java.nio.file.Paths;
import java.util.ArrayList;
import javax.annotation.Nullable;
@@ -49,7 +51,7 @@ import javax.annotation.Nullable;
public class SystemPreparer extends ExternalResource {
private static final long OVERLAY_ENABLE_TIMEOUT_MS = 30000;
- // The paths of the files pushed onto the device through this rule.
+ // The paths of the files pushed onto the device through this rule to be removed after.
private ArrayList<String> mPushedFiles = new ArrayList<>();
// The package names of packages installed through this rule.
@@ -81,7 +83,7 @@ public class SystemPreparer extends ExternalResource {
final ITestDevice device = mDeviceProvider.getDevice();
remount();
assertTrue(device.pushFile(copyResourceToTemp(filePath), outputPath));
- mPushedFiles.add(outputPath);
+ addPushedFile(device, outputPath);
return this;
}
@@ -91,10 +93,23 @@ public class SystemPreparer extends ExternalResource {
final ITestDevice device = mDeviceProvider.getDevice();
remount();
assertTrue(device.pushFile(file, outputPath));
- mPushedFiles.add(outputPath);
+ addPushedFile(device, outputPath);
return this;
}
+ private void addPushedFile(ITestDevice device, String outputPath)
+ throws DeviceNotAvailableException {
+ Path pathCreated = Paths.get(outputPath);
+
+ // Find the top most parent that is new to the device
+ while (pathCreated.getParent() != null
+ && !device.doesFileExist(pathCreated.getParent().toString())) {
+ pathCreated = pathCreated.getParent();
+ }
+
+ mPushedFiles.add(pathCreated.toString());
+ }
+
/** Deletes the given path from the device */
public SystemPreparer deleteFile(String file) throws DeviceNotAvailableException {
final ITestDevice device = mDeviceProvider.getDevice();
@@ -203,7 +218,7 @@ public class SystemPreparer extends ExternalResource {
/** Removes installed packages and files that were pushed to the device. */
@Override
- protected void after() {
+ public void after() {
final ITestDevice device = mDeviceProvider.getDevice();
try {
remount();
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index 3cdfb00d288c..e4937892e2f7 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -122,7 +122,7 @@ interface IWifiManager
DhcpInfo getDhcpInfo();
- void setScanAlwaysAvailable(boolean isAvailable);
+ void setScanAlwaysAvailable(boolean isAvailable, String packageName);
boolean isScanAlwaysAvailable();
@@ -142,9 +142,9 @@ interface IWifiManager
void updateInterfaceIpState(String ifaceName, int mode);
- boolean startSoftAp(in WifiConfiguration wifiConfig);
+ boolean startSoftAp(in WifiConfiguration wifiConfig, String packageName);
- boolean startTetheredHotspot(in SoftApConfiguration softApConfig);
+ boolean startTetheredHotspot(in SoftApConfiguration softApConfig, String packageName);
boolean stopSoftAp();
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index ae834f929691..b28b902910bf 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -2802,7 +2802,7 @@ public class WifiManager {
@RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
public void setScanAlwaysAvailable(boolean isAvailable) {
try {
- mService.setScanAlwaysAvailable(isAvailable);
+ mService.setScanAlwaysAvailable(isAvailable, mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -3035,7 +3035,7 @@ public class WifiManager {
})
public boolean startSoftAp(@Nullable WifiConfiguration wifiConfig) {
try {
- return mService.startSoftAp(wifiConfig);
+ return mService.startSoftAp(wifiConfig, mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -3059,7 +3059,7 @@ public class WifiManager {
})
public boolean startTetheredHotspot(@Nullable SoftApConfiguration softApConfig) {
try {
- return mService.startTetheredHotspot(softApConfig);
+ return mService.startTetheredHotspot(softApConfig, mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/wifi/tests/src/android/net/wifi/WifiManagerTest.java b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
index cba1690ac635..e7f1916c9e82 100644
--- a/wifi/tests/src/android/net/wifi/WifiManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
@@ -218,10 +218,10 @@ public class WifiManagerTest {
*/
@Test
public void testStartSoftApCallsServiceWithWifiConfig() throws Exception {
- when(mWifiService.startSoftAp(eq(mApConfig))).thenReturn(true);
+ when(mWifiService.startSoftAp(mApConfig, TEST_PACKAGE_NAME)).thenReturn(true);
assertTrue(mWifiManager.startSoftAp(mApConfig));
- when(mWifiService.startSoftAp(eq(mApConfig))).thenReturn(false);
+ when(mWifiService.startSoftAp(mApConfig, TEST_PACKAGE_NAME)).thenReturn(false);
assertFalse(mWifiManager.startSoftAp(mApConfig));
}
@@ -231,10 +231,10 @@ public class WifiManagerTest {
*/
@Test
public void testStartSoftApCallsServiceWithNullConfig() throws Exception {
- when(mWifiService.startSoftAp(eq(null))).thenReturn(true);
+ when(mWifiService.startSoftAp(null, TEST_PACKAGE_NAME)).thenReturn(true);
assertTrue(mWifiManager.startSoftAp(null));
- when(mWifiService.startSoftAp(eq(null))).thenReturn(false);
+ when(mWifiService.startSoftAp(null, TEST_PACKAGE_NAME)).thenReturn(false);
assertFalse(mWifiManager.startSoftAp(null));
}
@@ -257,10 +257,12 @@ public class WifiManagerTest {
@Test
public void testStartTetheredHotspotCallsServiceWithSoftApConfig() throws Exception {
SoftApConfiguration softApConfig = generatorTestSoftApConfig();
- when(mWifiService.startTetheredHotspot(eq(softApConfig))).thenReturn(true);
+ when(mWifiService.startTetheredHotspot(softApConfig, TEST_PACKAGE_NAME))
+ .thenReturn(true);
assertTrue(mWifiManager.startTetheredHotspot(softApConfig));
- when(mWifiService.startTetheredHotspot(eq(softApConfig))).thenReturn(false);
+ when(mWifiService.startTetheredHotspot(softApConfig, TEST_PACKAGE_NAME))
+ .thenReturn(false);
assertFalse(mWifiManager.startTetheredHotspot(softApConfig));
}
@@ -270,10 +272,10 @@ public class WifiManagerTest {
*/
@Test
public void testStartTetheredHotspotCallsServiceWithNullConfig() throws Exception {
- when(mWifiService.startTetheredHotspot(eq(null))).thenReturn(true);
+ when(mWifiService.startTetheredHotspot(null, TEST_PACKAGE_NAME)).thenReturn(true);
assertTrue(mWifiManager.startTetheredHotspot(null));
- when(mWifiService.startTetheredHotspot(eq(null))).thenReturn(false);
+ when(mWifiService.startTetheredHotspot(null, TEST_PACKAGE_NAME)).thenReturn(false);
assertFalse(mWifiManager.startTetheredHotspot(null));
}
@@ -2375,7 +2377,7 @@ public class WifiManagerTest {
@Test
public void testScanAvailable() throws Exception {
mWifiManager.setScanAlwaysAvailable(true);
- verify(mWifiService).setScanAlwaysAvailable(true);
+ verify(mWifiService).setScanAlwaysAvailable(true, TEST_PACKAGE_NAME);
when(mWifiService.isScanAlwaysAvailable()).thenReturn(false);
assertFalse(mWifiManager.isScanAlwaysAvailable());