summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.bp8
-rw-r--r--ApiDocs.bp1
-rw-r--r--StubLibraries.bp104
-rw-r--r--apex/media/framework/Android.bp59
-rw-r--r--apex/permission/framework/Android.bp59
-rw-r--r--apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsPersistence.java3
-rw-r--r--apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsState.java3
-rw-r--r--apex/permission/service/java/com/android/role/persistence/RolesPersistence.java3
-rw-r--r--apex/permission/service/java/com/android/role/persistence/RolesState.java3
-rw-r--r--apex/sdkextensions/framework/Android.bp58
-rw-r--r--apex/statsd/framework/Android.bp73
-rw-r--r--apex/statsd/framework/java/android/os/StatsDimensionsValue.java (renamed from core/java/android/os/StatsDimensionsValue.java)3
-rw-r--r--api/current.txt2
-rw-r--r--api/module-app-current.txt1
-rw-r--r--api/module-app-removed.txt1
-rw-r--r--api/module-lib-current.txt4
-rwxr-xr-xapi/system-current.txt3
-rw-r--r--api/test-current.txt1
-rw-r--r--cmds/statsd/Android.bp2
-rw-r--r--cmds/statsd/src/atoms.proto39
-rw-r--r--cmds/statsd/src/metrics/GaugeMetricProducer.cpp9
-rw-r--r--cmds/statsd/src/metrics/ValueMetricProducer.cpp11
-rw-r--r--cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp39
-rw-r--r--core/java/android/app/ActivityManagerInternal.java2
-rw-r--r--core/java/android/app/AppOpsManagerInternal.java13
-rw-r--r--core/java/android/app/prediction/AppPredictionContext.java10
-rw-r--r--core/java/android/content/pm/PackageManager.java10
-rw-r--r--core/java/android/content/pm/PermissionInfo.java15
-rw-r--r--core/java/android/content/pm/parsing/ComponentParseUtils.java12
-rw-r--r--core/java/android/os/incremental/IncrementalFileStorages.java155
-rw-r--r--core/java/android/timezone/CountryTimeZones.java32
-rw-r--r--core/java/android/util/RotationUtils.java72
-rw-r--r--core/java/android/view/ImeFocusController.java8
-rw-r--r--core/java/android/view/View.java7
-rw-r--r--core/java/android/view/ViewRootImpl.java3
-rw-r--r--core/java/android/view/inputmethod/InputMethodManager.java5
-rw-r--r--core/java/android/widget/Magnifier.java60
-rw-r--r--core/java/com/android/ims/internal/uce/common/CapInfo.java36
-rw-r--r--core/java/com/android/internal/app/AccessibilityButtonChooserActivity.java43
-rw-r--r--core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java7
-rw-r--r--core/java/com/android/internal/util/ObjectUtils.java8
-rw-r--r--core/proto/android/server/connectivity/data_stall_event.proto6
-rw-r--r--core/res/AndroidManifest.xml7
-rw-r--r--core/res/res/drawable/ic_open_in_new.xml26
-rw-r--r--core/res/res/values-mcc334/config.xml23
-rw-r--r--core/res/res/values-mcc732/config.xml23
-rw-r--r--core/res/res/values-mcc740/config.xml23
-rw-r--r--core/res/res/values/attrs_manifest.xml3
-rw-r--r--core/res/res/values/config.xml19
-rw-r--r--core/res/res/values/dimens.xml6
-rw-r--r--core/res/res/values/symbols.xml7
-rw-r--r--data/etc/privapp-permissions-platform.xml2
-rw-r--r--libs/hwui/pipeline/skia/SkiaPipeline.cpp8
-rw-r--r--media/java/android/media/session/MediaSessionManager.java1
-rw-r--r--media/tests/MediaRouteProvider/Android.bp18
-rw-r--r--media/tests/MediaRouteProvider/AndroidManifest.xml30
-rw-r--r--media/tests/MediaRouteProvider/res/values/strings.xml5
-rw-r--r--media/tests/MediaRouter/AndroidManifest.xml8
-rw-r--r--media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java69
-rw-r--r--media/tests/MediaRouter/src/com/android/mediaroutertest/SampleMediaRoute2ProviderService.java (renamed from media/tests/MediaRouteProvider/src/com/android/mediarouteprovider/example/SampleMediaRoute2ProviderService.java)2
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java11
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java9
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java11
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/license/LicenseHtmlGeneratorFromXml.java48
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/license/LicenseHtmlGeneratorFromXmlTest.java35
-rw-r--r--packages/SystemUI/AndroidManifest.xml4
-rw-r--r--packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java20
-rw-r--r--packages/SystemUI/proguard.flags1
-rw-r--r--packages/SystemUI/res-keyguard/layout/controls_management.xml34
-rw-r--r--packages/SystemUI/res/drawable/auth_dialog_enterprise.xml25
-rw-r--r--packages/SystemUI/res/drawable/notif_dungeon_bg_gradient.xml25
-rw-r--r--packages/SystemUI/res/layout-land/auth_credential_pattern_view.xml67
-rw-r--r--packages/SystemUI/res/layout/app_item.xml70
-rw-r--r--packages/SystemUI/res/layout/auth_credential_password_view.xml30
-rw-r--r--packages/SystemUI/res/layout/auth_credential_pattern_view.xml69
-rw-r--r--packages/SystemUI/res/layout/control_item.xml72
-rw-r--r--packages/SystemUI/res/layout/controls_app_item.xml87
-rw-r--r--packages/SystemUI/res/layout/controls_base_item.xml32
-rw-r--r--packages/SystemUI/res/layout/controls_row.xml2
-rw-r--r--packages/SystemUI/res/layout/controls_with_favorites.xml2
-rw-r--r--packages/SystemUI/res/layout/foreground_service_dungeon.xml61
-rw-r--r--packages/SystemUI/res/layout/foreground_service_dungeon_row.xml43
-rw-r--r--packages/SystemUI/res/values-af/strings.xml1
-rw-r--r--packages/SystemUI/res/values-am/strings.xml1
-rw-r--r--packages/SystemUI/res/values-ar/strings.xml2
-rw-r--r--packages/SystemUI/res/values-as/strings.xml2
-rw-r--r--packages/SystemUI/res/values-az/strings.xml2
-rw-r--r--packages/SystemUI/res/values-b+sr+Latn/strings.xml1
-rw-r--r--packages/SystemUI/res/values-be/strings.xml2
-rw-r--r--packages/SystemUI/res/values-bg/strings.xml1
-rw-r--r--packages/SystemUI/res/values-bn/strings.xml2
-rw-r--r--packages/SystemUI/res/values-bs/strings.xml1
-rw-r--r--packages/SystemUI/res/values-ca/strings.xml1
-rw-r--r--packages/SystemUI/res/values-cs/strings.xml1
-rw-r--r--packages/SystemUI/res/values-da/strings.xml1
-rw-r--r--packages/SystemUI/res/values-de/strings.xml2
-rw-r--r--packages/SystemUI/res/values-el/strings.xml1
-rw-r--r--packages/SystemUI/res/values-en-rAU/strings.xml1
-rw-r--r--packages/SystemUI/res/values-en-rCA/strings.xml1
-rw-r--r--packages/SystemUI/res/values-en-rGB/strings.xml1
-rw-r--r--packages/SystemUI/res/values-en-rIN/strings.xml1
-rw-r--r--packages/SystemUI/res/values-en-rXC/strings.xml1
-rw-r--r--packages/SystemUI/res/values-es-rUS/strings.xml1
-rw-r--r--packages/SystemUI/res/values-es/strings.xml1
-rw-r--r--packages/SystemUI/res/values-et/strings.xml2
-rw-r--r--packages/SystemUI/res/values-eu/strings.xml1
-rw-r--r--packages/SystemUI/res/values-fa/strings.xml2
-rw-r--r--packages/SystemUI/res/values-fi/strings.xml1
-rw-r--r--packages/SystemUI/res/values-fr-rCA/strings.xml2
-rw-r--r--packages/SystemUI/res/values-fr/strings.xml2
-rw-r--r--packages/SystemUI/res/values-gl/strings.xml2
-rw-r--r--packages/SystemUI/res/values-gu/strings.xml2
-rw-r--r--packages/SystemUI/res/values-hi/strings.xml6
-rw-r--r--packages/SystemUI/res/values-hr/strings.xml1
-rw-r--r--packages/SystemUI/res/values-hu/strings.xml1
-rw-r--r--packages/SystemUI/res/values-hy/strings.xml1
-rw-r--r--packages/SystemUI/res/values-in/strings.xml1
-rw-r--r--packages/SystemUI/res/values-is/strings.xml1
-rw-r--r--packages/SystemUI/res/values-it/strings.xml1
-rw-r--r--packages/SystemUI/res/values-iw/strings.xml2
-rw-r--r--packages/SystemUI/res/values-ja/strings.xml1
-rw-r--r--packages/SystemUI/res/values-ka/strings.xml2
-rw-r--r--packages/SystemUI/res/values-kk/strings.xml2
-rw-r--r--packages/SystemUI/res/values-km/strings.xml1
-rw-r--r--packages/SystemUI/res/values-kn/strings.xml2
-rw-r--r--packages/SystemUI/res/values-ko/strings.xml2
-rw-r--r--packages/SystemUI/res/values-ky/strings.xml2
-rw-r--r--packages/SystemUI/res/values-lo/strings.xml1
-rw-r--r--packages/SystemUI/res/values-lt/strings.xml1
-rw-r--r--packages/SystemUI/res/values-lv/strings.xml2
-rw-r--r--packages/SystemUI/res/values-mk/strings.xml1
-rw-r--r--packages/SystemUI/res/values-ml/strings.xml2
-rw-r--r--packages/SystemUI/res/values-mn/strings.xml1
-rw-r--r--packages/SystemUI/res/values-mr/strings.xml2
-rw-r--r--packages/SystemUI/res/values-ms/strings.xml2
-rw-r--r--packages/SystemUI/res/values-my/strings.xml2
-rw-r--r--packages/SystemUI/res/values-nb/strings.xml1
-rw-r--r--packages/SystemUI/res/values-ne/strings.xml2
-rw-r--r--packages/SystemUI/res/values-nl/strings.xml1
-rw-r--r--packages/SystemUI/res/values-or/strings.xml2
-rw-r--r--packages/SystemUI/res/values-pa/strings.xml2
-rw-r--r--packages/SystemUI/res/values-pl/strings.xml3
-rw-r--r--packages/SystemUI/res/values-pt-rBR/strings.xml1
-rw-r--r--packages/SystemUI/res/values-pt-rPT/strings.xml1
-rw-r--r--packages/SystemUI/res/values-pt/strings.xml1
-rw-r--r--packages/SystemUI/res/values-ro/strings.xml1
-rw-r--r--packages/SystemUI/res/values-ru/strings.xml2
-rw-r--r--packages/SystemUI/res/values-si/strings.xml1
-rw-r--r--packages/SystemUI/res/values-sk/strings.xml1
-rw-r--r--packages/SystemUI/res/values-sl/strings.xml1
-rw-r--r--packages/SystemUI/res/values-sq/strings.xml2
-rw-r--r--packages/SystemUI/res/values-sr/strings.xml1
-rw-r--r--packages/SystemUI/res/values-sv/strings.xml1
-rw-r--r--packages/SystemUI/res/values-sw/strings.xml3
-rw-r--r--packages/SystemUI/res/values-ta/strings.xml2
-rw-r--r--packages/SystemUI/res/values-te/strings.xml6
-rw-r--r--packages/SystemUI/res/values-television/config.xml3
-rw-r--r--packages/SystemUI/res/values-th/strings.xml1
-rw-r--r--packages/SystemUI/res/values-tl/strings.xml1
-rw-r--r--packages/SystemUI/res/values-tr/strings.xml1
-rw-r--r--packages/SystemUI/res/values-uk/strings.xml1
-rw-r--r--packages/SystemUI/res/values-ur/strings.xml1
-rw-r--r--packages/SystemUI/res/values-uz/strings.xml7
-rw-r--r--packages/SystemUI/res/values-vi/strings.xml2
-rw-r--r--packages/SystemUI/res/values-zh-rCN/strings.xml2
-rw-r--r--packages/SystemUI/res/values-zh-rHK/strings.xml1
-rw-r--r--packages/SystemUI/res/values-zh-rTW/strings.xml1
-rw-r--r--packages/SystemUI/res/values-zu/strings.xml1
-rw-r--r--packages/SystemUI/res/values/dimens.xml26
-rw-r--r--packages/SystemUI/res/values/strings.xml20
-rw-r--r--packages/SystemUI/res/values/styles.xml65
-rw-r--r--packages/SystemUI/src/com/android/systemui/ForegroundServiceNotificationListener.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialView.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/controller/ControlsController.kt1
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/management/AppAdapter.kt28
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt58
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt24
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/management/ControlsProviderSelectorActivity.kt16
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/ui/RenderInfo.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/DefaultComponentBinder.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/SystemUIRootComponent.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSColorController.kt140
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java48
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileBaseView.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java43
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoveInterceptor.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/ForegroundServiceDismissalFeatureController.kt49
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java45
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListDumper.java17
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java230
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifInflaterImpl.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java124
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HideLocallyDismissedNotifsCoordinator.java41
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionListener.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionLogger.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/DungeonRow.kt43
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ForegroundServiceDungeonView.kt38
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ForegroundServiceSectionController.kt171
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java37
-rw-r--r--packages/SystemUI/src/com/android/systemui/tv/TvSystemUIBinder.java28
-rw-r--r--packages/SystemUI/src/com/android/systemui/tv/TvSystemUIFactory.java35
-rw-r--r--packages/SystemUI/src/com/android/systemui/tv/TvSystemUIRootComponent.java58
-rw-r--r--packages/SystemUI/src/com/android/systemui/wm/DisplayLayout.java106
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java15
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java11
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/TestableNotificationEntryManager.kt5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java290
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java15
-rw-r--r--packages/Tethering/res/values/config.xml1
-rw-r--r--packages/overlays/Android.mk1
-rw-r--r--packages/overlays/DisplayCutoutEmulationHoleOverlay/Android.mk14
-rw-r--r--packages/overlays/DisplayCutoutEmulationHoleOverlay/AndroidManifest.xml26
-rw-r--r--packages/overlays/DisplayCutoutEmulationHoleOverlay/res/values-land/config.xml22
-rw-r--r--packages/overlays/DisplayCutoutEmulationHoleOverlay/res/values/config.xml61
-rw-r--r--packages/overlays/DisplayCutoutEmulationHoleOverlay/res/values/strings.xml22
-rw-r--r--packages/overlays/IconShapePebbleOverlay/Android.mk29
-rw-r--r--packages/overlays/IconShapePebbleOverlay/AndroidManifest.xml29
-rw-r--r--packages/overlays/IconShapePebbleOverlay/res/values/config.xml30
-rw-r--r--packages/overlays/IconShapePebbleOverlay/res/values/strings.xml23
-rw-r--r--services/Android.bp2
-rw-r--r--services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java125
-rw-r--r--services/backup/backuplib/java/com/android/server/backup/transport/TransportClient.java5
-rw-r--r--services/core/java/android/content/pm/PackageManagerInternal.java2
-rw-r--r--services/core/java/com/android/server/ConnectivityService.java125
-rw-r--r--services/core/java/com/android/server/SystemService.java5
-rw-r--r--services/core/java/com/android/server/TelephonyRegistry.java3
-rw-r--r--services/core/java/com/android/server/VibratorService.java10
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java21
-rw-r--r--services/core/java/com/android/server/am/ProcessList.java5
-rw-r--r--services/core/java/com/android/server/am/ProcessRecord.java13
-rw-r--r--services/core/java/com/android/server/am/TEST_MAPPING8
-rw-r--r--services/core/java/com/android/server/appop/AppOpsService.java51
-rw-r--r--services/core/java/com/android/server/connectivity/LingerMonitor.java29
-rw-r--r--services/core/java/com/android/server/incremental/IncrementalManagerService.java12
-rw-r--r--services/core/java/com/android/server/media/MediaKeyDispatcher.java39
-rw-r--r--services/core/java/com/android/server/media/MediaSession2Record.java20
-rw-r--r--services/core/java/com/android/server/media/MediaSessionRecord.java23
-rw-r--r--services/core/java/com/android/server/media/MediaSessionRecordImpl.java14
-rw-r--r--services/core/java/com/android/server/media/MediaSessionService.java53
-rw-r--r--services/core/java/com/android/server/media/MediaSessionStack.java9
-rw-r--r--services/core/java/com/android/server/media/SessionPolicyProvider.java63
-rw-r--r--services/core/java/com/android/server/notification/NotificationRecordLoggerImpl.java4
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerSession.java47
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java81
-rw-r--r--services/core/java/com/android/server/pm/Settings.java26
-rw-r--r--services/core/java/com/android/server/pm/ShortcutService.java15
-rw-r--r--services/core/java/com/android/server/pm/permission/BasePermission.java4
-rw-r--r--services/core/java/com/android/server/pm/permission/PermissionManagerService.java19
-rw-r--r--services/core/java/com/android/server/policy/PermissionPolicyService.java23
-rw-r--r--services/core/java/com/android/server/policy/PhoneWindowManager.java22
-rw-r--r--services/core/java/com/android/server/power/AttentionDetector.java5
-rw-r--r--services/core/java/com/android/server/power/Notifier.java36
-rw-r--r--services/core/java/com/android/server/rollback/Rollback.java19
-rw-r--r--services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java85
-rw-r--r--services/core/java/com/android/server/rollback/WatchdogRollbackLogger.java23
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java2
-rw-r--r--services/core/java/com/android/server/wm/ActivityServiceConnectionsHolder.java59
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java10
-rw-r--r--services/core/java/com/android/server/wm/utils/WmDisplayCutout.java87
-rw-r--r--services/core/jni/com_android_server_incremental_IncrementalManagerService.cpp5
-rw-r--r--services/incremental/BinderIncrementalService.cpp18
-rw-r--r--services/incremental/IncrementalService.cpp133
-rw-r--r--services/incremental/IncrementalService.h13
-rw-r--r--services/incremental/ServiceWrappers.h2
-rw-r--r--services/incremental/include/incremental_service.h1
-rw-r--r--services/incremental/test/IncrementalServiceTest.cpp55
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/am/CachedAppOptimizerTest.java117
-rw-r--r--services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java41
-rw-r--r--services/tests/servicestests/src/com/android/server/rollback/RollbackUnitTest.java11
-rw-r--r--services/tests/servicestests/src/com/android/server/rollback/WatchdogRollbackLoggerTest.java13
-rwxr-xr-xservices/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java80
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/utils/WmDisplayCutoutTest.java184
-rw-r--r--startop/iorap/TEST_MAPPING3
-rw-r--r--telephony/java/android/telephony/SmsCbMessage.java1
-rw-r--r--tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java44
-rw-r--r--tests/net/java/com/android/server/ConnectivityServiceTest.java34
-rw-r--r--tools/aapt2/link/ManifestFixer.cpp6
-rw-r--r--tools/stats_log_api_gen/Android.bp1
-rw-r--r--wifi/java/android/net/wifi/IScoreChangeCallback.aidl4
-rw-r--r--wifi/java/android/net/wifi/WifiManager.java18
-rw-r--r--wifi/java/android/net/wifi/WifiScanner.java2
292 files changed, 4619 insertions, 1743 deletions
diff --git a/Android.bp b/Android.bp
index c89917975e8e..f48e6feb1c14 100644
--- a/Android.bp
+++ b/Android.bp
@@ -401,7 +401,7 @@ java_defaults {
"app-compat-annotations",
"ext",
"unsupportedappusage",
- "updatable_media_stubs",
+ "framework-media-stubs-systemapi",
"framework_mediaprovider_stubs",
"framework-tethering",
"framework-telephony-stubs",
@@ -469,7 +469,7 @@ java_library {
"framework-appsearch-stubs",
"framework-sdkextensions-stubs-systemapi",
"framework-statsd", // TODO(b/146167933): Use framework-statsd-stubs
- "framework-permission-stubs",
+ "framework-permission-stubs-systemapi",
"framework-wifi-stubs",
"ike-stubs",
],
@@ -517,10 +517,10 @@ java_library {
installable: false, // this lib is a build-only library
static_libs: [
"framework-minus-apex",
- "updatable_media_stubs",
+ "framework-media-stubs-systemapi",
"framework_mediaprovider_stubs",
"framework-appsearch", // TODO(b/146218515): should be framework-appsearch-stubs
- "framework-permission-stubs",
+ "framework-permission-stubs-systemapi",
"framework-sdkextensions-stubs-systemapi",
// TODO(b/146167933): Use framework-statsd-stubs instead.
"framework-statsd",
diff --git a/ApiDocs.bp b/ApiDocs.bp
index c40004cf8e5c..04ddc50a94c4 100644
--- a/ApiDocs.bp
+++ b/ApiDocs.bp
@@ -176,6 +176,7 @@ droiddoc {
hdf: [
"android.whichdoc offline",
],
+ compat_config: ":global-compat-config",
proofread_file: "offline-sdk-docs-proofrerad.txt",
args: framework_docs_only_args + " -offlinemode -title \"Android SDK\"",
static_doc_index_redirect: "docs/docs-preview-index.html",
diff --git a/StubLibraries.bp b/StubLibraries.bp
index 0f805655b33d..d4db7373504b 100644
--- a/StubLibraries.bp
+++ b/StubLibraries.bp
@@ -113,6 +113,16 @@ droidstubs {
jdiff_enabled: true,
}
+priv_apps = " " +
+ "--show-annotation android.annotation.SystemApi\\(" +
+ "client=android.annotation.SystemApi.Client.PRIVILEGED_APPS" +
+ "\\) "
+
+module_libs = " " +
+ " --show-annotation android.annotation.SystemApi\\(" +
+ "client=android.annotation.SystemApi.Client.MODULE_LIBRARIES" +
+ "\\) "
+
droidstubs {
name: "system-api-stubs-docs",
defaults: ["metalava-api-stubs-default"],
@@ -124,10 +134,7 @@ droidstubs {
arg_files: [
"core/res/AndroidManifest.xml",
],
- args: metalava_framework_docs_args +
- " --show-annotation android.annotation.SystemApi\\(" +
- "client=android.annotation.SystemApi.Client.PRIVILEGED_APPS," +
- "process=android.annotation.SystemApi.Process.ALL\\)",
+ args: metalava_framework_docs_args + priv_apps,
check_api: {
current: {
api_file: "api/system-current.txt",
@@ -175,49 +182,17 @@ droidstubs {
// @SystemApi(client=MODULE_APPS) and @SystemApi(client=MODULE_LIBRARIES)
/////////////////////////////////////////////////////////////////////
-// TODO(b/146727827) remove the *-api modules when we can teach metalava
+// TODO(b/146727827) remove the *-api module when we can teach metalava
// about the relationship among the API surfaces. Currently, these modules are only to generate
// the API signature files and ensure that the APIs evolve in a backwards compatible manner.
// They however are NOT used for building the API stub.
-droidstubs {
- name: "module-app-api",
- defaults: ["metalava-api-stubs-default"],
- libs: ["framework-all"],
- arg_files: ["core/res/AndroidManifest.xml"],
- args: metalava_framework_docs_args +
- " --show-annotation android.annotation.SystemApi\\(" +
- "client=android.annotation.SystemApi.Client.MODULE_APPS," +
- "process=android.annotation.SystemApi.Process.ALL\\)",
- check_api: {
- current: {
- api_file: "api/module-app-current.txt",
- removed_api_file: "api/module-app-removed.txt",
- },
- // TODO(b/147559833) enable the compatibility check against the last release API
- // and the API lint
- //last_released: {
- // api_file: ":last-released-module-app-api",
- // removed_api_file: "api/module-app-removed.txt",
- // baseline_file: ":module-app-api-incompatibilities-with-last-released"
- //},
- //api_lint: {
- // enabled: true,
- // new_since: ":last-released-module-app-api",
- // baseline_file: "api/module-app-lint-baseline.txt",
- //},
- },
- //jdiff_enabled: true,
-}
droidstubs {
name: "module-lib-api",
defaults: ["metalava-api-stubs-default"],
libs: ["framework-all"],
arg_files: ["core/res/AndroidManifest.xml"],
- args: metalava_framework_docs_args +
- " --show-annotation android.annotation.SystemApi\\(" +
- "client=android.annotation.SystemApi.Client.MODULE_LIBRARIES," +
- "process=android.annotation.SystemApi.Process.ALL\\)",
+ args: metalava_framework_docs_args + module_libs,
check_api: {
current: {
api_file: "api/module-lib-current.txt",
@@ -239,39 +214,17 @@ droidstubs {
//jdiff_enabled: true,
}
-// The following two droidstubs modules generate source files for the API stub libraries for
-// modules. Note that they not only include their own APIs but also other APIs that have
-// narrower scope. For example, module-lib-api-stubs-docs includes all @SystemApis not just
-// the ones with 'client=MODULE_LIBRARIES'.
-droidstubs {
- name: "module-app-api-stubs-docs",
- defaults: ["metalava-api-stubs-default"],
- libs: ["framework-all"],
- arg_files: ["core/res/AndroidManifest.xml"],
- args: metalava_framework_docs_args +
- " --show-annotation android.annotation.SystemApi\\(" +
- "client=android.annotation.SystemApi.Client.PRIVILEGED_APPS," +
- "process=android.annotation.SystemApi.Process.ALL\\)" +
- " --show-annotation android.annotation.SystemApi\\(" +
- "client=android.annotation.SystemApi.Client.MODULE_APPS," +
- "process=android.annotation.SystemApi.Process.ALL\\)",
-}
+
+// The following droidstub module generates source files for the API stub library for
+// modules. Note that it not only includes its own APIs but also other APIs that have
+// narrower scope (all @SystemApis, not just the ones with 'client=MODULE_LIBRARIES').
droidstubs {
name: "module-lib-api-stubs-docs",
defaults: ["metalava-api-stubs-default"],
libs: ["framework-all"],
arg_files: ["core/res/AndroidManifest.xml"],
- args: metalava_framework_docs_args +
- " --show-annotation android.annotation.SystemApi\\(" +
- "client=android.annotation.SystemApi.Client.PRIVILEGED_APPS," +
- "process=android.annotation.SystemApi.Process.ALL\\)" +
- " --show-annotation android.annotation.SystemApi\\(" +
- "client=android.annotation.SystemApi.Client.MODULE_APPS," +
- "process=android.annotation.SystemApi.Process.ALL\\)" +
- " --show-annotation android.annotation.SystemApi\\(" +
- "client=android.annotation.SystemApi.Client.MODULE_LIBRARIES," +
- "process=android.annotation.SystemApi.Process.ALL\\)",
+ args: metalava_framework_docs_args + priv_apps + module_libs,
}
/////////////////////////////////////////////////////////////////////
@@ -340,21 +293,6 @@ java_library_static {
}
java_library_static {
- name: "android_module_app_stubs_current",
- srcs: [
- ":module-app-api-stubs-docs",
- ],
- libs: [
- "stub-annotations",
- "framework-all",
- ],
- static_libs: [
- "private-stub-annotations-jar",
- ],
- defaults: ["framework-stubs-default"],
-}
-
-java_library_static {
name: "android_module_lib_stubs_current",
srcs: [
":module-lib-api-stubs-docs",
@@ -401,7 +339,7 @@ droidstubs {
merge_annotations_dirs: [
"metalava-manual",
],
- args: " --show-annotation android.annotation.SystemApi\\(client=android.annotation.SystemApi.Client.PRIVILEGED_APPS,process=android.annotation.SystemApi.Process.ALL\\)",
+ args: priv_apps,
}
java_library_static {
@@ -427,7 +365,7 @@ droidstubs {
removed_dex_api_filename: "removed-dex.txt",
args: metalava_framework_docs_args +
" --show-unannotated " +
- " --show-annotation android.annotation.SystemApi\\(client=android.annotation.SystemApi.Client.PRIVILEGED_APPS,process=android.annotation.SystemApi.Process.ALL\\) " +
+ priv_apps +
" --show-annotation android.annotation.TestApi ",
}
@@ -446,7 +384,7 @@ droidstubs {
" --hide ReferencesHidden " +
" --hide UnhiddenSystemApi " +
" --show-unannotated " +
- " --show-annotation android.annotation.SystemApi\\(client=android.annotation.SystemApi.Client.PRIVILEGED_APPS,process=android.annotation.SystemApi.Process.ALL\\) " +
+ priv_apps +
" --show-annotation android.annotation.TestApi ",
}
diff --git a/apex/media/framework/Android.bp b/apex/media/framework/Android.bp
index 2266d049d70a..91df09865037 100644
--- a/apex/media/framework/Android.bp
+++ b/apex/media/framework/Android.bp
@@ -99,13 +99,10 @@ filegroup {
path: "java"
}
-droidstubs {
- name: "updatable-media-stubs",
- srcs: [
- ":updatable-media-srcs",
- ":framework-media-annotation-srcs",
- ],
- defaults: [ "framework-module-stubs-defaults-systemapi" ],
+stubs_defaults {
+ name: "framework-media-stubs-srcs-defaults",
+ srcs: [ ":updatable-media-srcs" ],
+ libs: [ "framework_media_annotation" ],
aidl: {
// TODO(b/135922046) remove this
include_dirs: ["frameworks/base/core/java"],
@@ -113,9 +110,53 @@ droidstubs {
sdk_version: "system_current",
}
+droidstubs {
+ name: "framework-media-stubs-srcs-publicapi",
+ defaults: [
+ "framework-media-stubs-srcs-defaults",
+ "framework-module-stubs-defaults-publicapi",
+ ],
+}
+
+droidstubs {
+ name: "framework-media-stubs-srcs-systemapi",
+ defaults: [
+ "framework-media-stubs-srcs-defaults",
+ "framework-module-stubs-defaults-systemapi",
+ ],
+}
+
+droidstubs {
+ name: "framework-media-api-module_libs_api",
+ defaults: [
+ "framework-media-stubs-srcs-defaults",
+ "framework-module-api-defaults-module_libs_api",
+ ],
+}
+
+droidstubs {
+ name: "framework-media-stubs-srcs-module_libs_api",
+ defaults: [
+ "framework-media-stubs-srcs-defaults",
+ "framework-module-stubs-defaults-module_libs_api",
+ ],
+}
+
+java_library {
+ name: "framework-media-stubs-publicapi",
+ srcs: [":framework-media-stubs-srcs-publicapi"],
+ sdk_version: "current",
+}
+
+java_library {
+ name: "framework-media-stubs-systemapi",
+ srcs: [":framework-media-stubs-srcs-systemapi"],
+ sdk_version: "system_current",
+}
+
java_library {
- name: "updatable_media_stubs",
- srcs: [":updatable-media-stubs"],
+ name: "framework-media-stubs-module_libs_api",
+ srcs: [":framework-media-stubs-srcs-module_libs_api"],
sdk_version: "system_current",
}
diff --git a/apex/permission/framework/Android.bp b/apex/permission/framework/Android.bp
index 09571a1cd111..126fa00a31f0 100644
--- a/apex/permission/framework/Android.bp
+++ b/apex/permission/framework/Android.bp
@@ -44,23 +44,66 @@ java_library {
],
}
+stubs_defaults {
+ name: "framework-permission-stubs-defaults",
+ srcs: [ ":framework-permission-sources" ],
+ libs: [ "framework-annotations-lib" ],
+ sdk_version: "system_current",
+}
+
droidstubs {
- name: "framework-permission-stubs-sources",
- srcs: [
- ":framework-annotations",
- ":framework-permission-sources",
+ name: "framework-permission-stubs-srcs-publicapi",
+ sdk_version: "system_current",
+ defaults: [
+ "framework-module-stubs-defaults-publicapi",
+ "framework-permission-stubs-defaults",
],
+}
+
+droidstubs {
+ name: "framework-permission-stubs-srcs-systemapi",
sdk_version: "system_current",
defaults: [
"framework-module-stubs-defaults-systemapi",
+ "framework-permission-stubs-defaults",
],
}
-java_library {
- name: "framework-permission-stubs",
- srcs: [
- ":framework-permission-stubs-sources",
+droidstubs {
+ name: "framework-permission-api-module_libs_api",
+ sdk_version: "system_current",
+ defaults: [
+ "framework-module-api-defaults-module_libs_api",
+ "framework-permission-stubs-defaults",
+ ],
+}
+
+droidstubs {
+ name: "framework-permission-stubs-srcs-module_libs_api",
+ sdk_version: "system_current",
+ defaults: [
+ "framework-module-stubs-defaults-module_libs_api",
+ "framework-permission-stubs-defaults",
],
+}
+
+java_library {
+ name: "framework-permission-stubs-publicapi",
+ srcs: [ ":framework-permission-stubs-srcs-publicapi" ],
+ sdk_version: "system_current",
+ installable: false,
+}
+
+java_library {
+ name: "framework-permission-stubs-systemapi",
+ srcs: [ ":framework-permission-stubs-srcs-systemapi" ],
+ sdk_version: "system_current",
+ installable: false,
+}
+
+java_library {
+ name: "framework-permission-stubs-module_libs_api",
+ srcs: [ ":framework-permission-stubs-srcs-module_libs_api" ],
sdk_version: "system_current",
installable: false,
}
diff --git a/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsPersistence.java b/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsPersistence.java
index 5f2d94441965..6c7f82a11908 100644
--- a/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsPersistence.java
+++ b/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsPersistence.java
@@ -19,6 +19,7 @@ package com.android.permission.persistence;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
+import android.annotation.SystemApi.Client;
import android.os.UserHandle;
/**
@@ -27,7 +28,7 @@ import android.os.UserHandle;
* TODO(b/147914847): Remove @hide when it becomes the default.
* @hide
*/
-@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES, process = SystemApi.Process.SYSTEM_SERVER)
+@SystemApi(client = Client.SYSTEM_SERVER)
public interface RuntimePermissionsPersistence {
/**
diff --git a/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsState.java b/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsState.java
index 2a939e51b98e..cd2750a0bee5 100644
--- a/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsState.java
+++ b/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsState.java
@@ -19,6 +19,7 @@ package com.android.permission.persistence;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
+import android.annotation.SystemApi.Client;
import java.util.List;
import java.util.Map;
@@ -29,7 +30,7 @@ import java.util.Map;
* TODO(b/147914847): Remove @hide when it becomes the default.
* @hide
*/
-@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES, process = SystemApi.Process.SYSTEM_SERVER)
+@SystemApi(client = Client.SYSTEM_SERVER)
public final class RuntimePermissionsState {
/**
diff --git a/apex/permission/service/java/com/android/role/persistence/RolesPersistence.java b/apex/permission/service/java/com/android/role/persistence/RolesPersistence.java
index 63c8eedd6285..2908a3872df9 100644
--- a/apex/permission/service/java/com/android/role/persistence/RolesPersistence.java
+++ b/apex/permission/service/java/com/android/role/persistence/RolesPersistence.java
@@ -19,6 +19,7 @@ package com.android.role.persistence;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
+import android.annotation.SystemApi.Client;
import android.os.UserHandle;
/**
@@ -27,7 +28,7 @@ import android.os.UserHandle;
* TODO(b/147914847): Remove @hide when it becomes the default.
* @hide
*/
-@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES, process = SystemApi.Process.SYSTEM_SERVER)
+@SystemApi(client = Client.SYSTEM_SERVER)
public interface RolesPersistence {
/**
diff --git a/apex/permission/service/java/com/android/role/persistence/RolesState.java b/apex/permission/service/java/com/android/role/persistence/RolesState.java
index bff980e2e126..7da9d11f172f 100644
--- a/apex/permission/service/java/com/android/role/persistence/RolesState.java
+++ b/apex/permission/service/java/com/android/role/persistence/RolesState.java
@@ -19,6 +19,7 @@ package com.android.role.persistence;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
+import android.annotation.SystemApi.Client;
import java.util.Map;
import java.util.Set;
@@ -29,7 +30,7 @@ import java.util.Set;
* TODO(b/147914847): Remove @hide when it becomes the default.
* @hide
*/
-@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES, process = SystemApi.Process.SYSTEM_SERVER)
+@SystemApi(client = Client.SYSTEM_SERVER)
public final class RolesState {
/**
diff --git a/apex/sdkextensions/framework/Android.bp b/apex/sdkextensions/framework/Android.bp
index 245a96b99148..86f4ab7c1128 100644
--- a/apex/sdkextensions/framework/Android.bp
+++ b/apex/sdkextensions/framework/Android.bp
@@ -44,34 +44,68 @@ java_library {
],
}
+stubs_defaults {
+ name: "framework-sdkextensions-stubs-defaults",
+ srcs: [ ":framework-sdkextensions-sources" ],
+ libs: [ "framework-annotations-lib" ],
+ sdk_version: "system_current",
+}
+
droidstubs {
- name: "framework-sdkextensions-droidstubs-publicapi",
+ name: "framework-sdkextensions-stubs-srcs-publicapi",
defaults: [
- "framework-sdkextensions-stubs-defaults",
"framework-module-stubs-defaults-publicapi",
+ "framework-sdkextensions-stubs-defaults",
]
}
droidstubs {
- name: "framework-sdkextensions-droidstubs-systemapi",
+ name: "framework-sdkextensions-stubs-srcs-systemapi",
defaults: [
- "framework-sdkextensions-stubs-defaults",
"framework-module-stubs-defaults-systemapi",
+ "framework-sdkextensions-stubs-defaults",
]
}
-stubs_defaults {
- name: "framework-sdkextensions-stubs-defaults",
- srcs: [
- ":framework-sdkextensions-sources",
- ":framework-annotations",
- ],
- sdk_version: "system_current",
+droidstubs {
+ name: "framework-sdkextensions-api-module_libs_api",
+ defaults: [
+ "framework-module-api-defaults-module_libs_api",
+ "framework-sdkextensions-stubs-defaults",
+ ]
+}
+
+droidstubs {
+ name: "framework-sdkextensions-stubs-srcs-module_libs_api",
+ defaults: [
+ "framework-module-stubs-defaults-module_libs_api",
+ "framework-sdkextensions-stubs-defaults",
+ ]
+}
+
+java_library {
+ name: "framework-sdkextensions-stubs-publicapi",
+ srcs: [":framework-sdkextensions-stubs-srcs-publicapi"],
+ sdk_version: "current",
+ visibility: [
+ "//frameworks/base", // Framework
+ "//frameworks/base/apex/sdkextensions", // sdkextensions SDK
+ ]
}
java_library {
name: "framework-sdkextensions-stubs-systemapi",
- srcs: [":framework-sdkextensions-droidstubs-systemapi"],
+ srcs: [":framework-sdkextensions-stubs-srcs-systemapi"],
+ sdk_version: "system_current",
+ visibility: [
+ "//frameworks/base", // Framework
+ "//frameworks/base/apex/sdkextensions", // sdkextensions SDK
+ ]
+}
+
+java_library {
+ name: "framework-sdkextensions-stubs-module_libs_api",
+ srcs: [":framework-sdkextensions-stubs-srcs-module_libs_api"],
sdk_version: "system_current",
visibility: [
"//frameworks/base", // Framework
diff --git a/apex/statsd/framework/Android.bp b/apex/statsd/framework/Android.bp
index 231c91026bb6..d85ae69b799f 100644
--- a/apex/statsd/framework/Android.bp
+++ b/apex/statsd/framework/Android.bp
@@ -30,6 +30,7 @@ java_library {
],
permitted_packages: [
"android.app",
+ "android.os",
"android.util",
],
libs: [
@@ -43,6 +44,7 @@ java_library {
"//frameworks/base/apex/statsd:__subpackages__",
//TODO(b/146167933) remove this when framework is built with framework-statsd-stubs
"//frameworks/base",
+ "//frameworks/opt/net/wifi/service",
],
apex_available: [
"com.android.os.statsd",
@@ -50,31 +52,70 @@ java_library {
],
}
+stubs_defaults {
+ name: "framework-statsd-stubs-srcs-defaults",
+ srcs: [ ":framework-statsd-sources" ],
+ libs: [
+ // TODO(b/148218250): Change to android_system_stubs_current
+ "framework-all",
+ "framework-annotations-lib",
+ ],
+ sdk_version: "core_platform",
+}
+
droidstubs {
- name: "framework-statsd-stubs-docs",
+ name: "framework-statsd-stubs-srcs-publicapi",
defaults: [
- "framework-module-stubs-defaults-systemapi"
+ "framework-module-stubs-defaults-systemapi",
+ "framework-statsd-stubs-srcs-defaults",
],
- srcs: [
- ":framework-annotations",
- ":framework-statsd-sources",
+}
+
+droidstubs {
+ name: "framework-statsd-stubs-srcs-systemapi",
+ defaults: [
+ "framework-module-stubs-defaults-systemapi",
+ "framework-statsd-stubs-srcs-defaults",
],
- libs: [
- // TODO(b/148218250): Change to android_system_stubs_current
- "framework-all",
+}
+
+droidstubs {
+ name: "framework-statsd-api-module_libs_api",
+ defaults: [
+ "framework-module-api-defaults-module_libs_api",
+ "framework-statsd-stubs-srcs-defaults",
+ ],
+}
+
+droidstubs {
+ name: "framework-statsd-stubs-srcs-module_libs_api",
+ defaults: [
+ "framework-module-stubs-defaults-module_libs_api",
+ "framework-statsd-stubs-srcs-defaults",
],
+}
+
+java_library {
+ name: "framework-statsd-stubs-publicapi",
+ srcs: [ ":framework-statsd-stubs-srcs-publicapi" ],
+ // TODO(b/148218250): Change to current
+ libs: [ "framework-all" ],
sdk_version: "core_platform",
}
// TODO(b/146167933): Use these stubs in frameworks/base/Android.bp
java_library {
- name: "framework-statsd-stubs",
- srcs: [
- ":framework-statsd-stubs-docs",
- ],
- libs: [
- // TODO(b/148218250): Change to android_system_stubs_current
- "framework-all",
- ],
+ name: "framework-statsd-stubs-systemapi",
+ srcs: [ ":framework-statsd-stubs-srcs-systemapi" ],
+ // TODO(b/148218250): Change to system_current
+ libs: [ "framework-all" ],
+ sdk_version: "core_platform",
+}
+
+java_library {
+ name: "framework-statsd-stubs-module_libs_api",
+ srcs: [ ":framework-statsd-stubs-srcs-systemapi" ],
+ // TODO(b/148218250): Change to system_current
+ libs: [ "framework-all" ],
sdk_version: "core_platform",
}
diff --git a/core/java/android/os/StatsDimensionsValue.java b/apex/statsd/framework/java/android/os/StatsDimensionsValue.java
index da13ea13d5fa..886130fc5f14 100644
--- a/core/java/android/os/StatsDimensionsValue.java
+++ b/apex/statsd/framework/java/android/os/StatsDimensionsValue.java
@@ -264,7 +264,8 @@ public final class StatsDimensionsValue implements Parcelable {
/**
* Parcelable Creator for StatsDimensionsValue.
*/
- public static final @android.annotation.NonNull Parcelable.Creator<StatsDimensionsValue> CREATOR = new
+ public static final @android.annotation.NonNull
+ Parcelable.Creator<StatsDimensionsValue> CREATOR = new
Parcelable.Creator<StatsDimensionsValue>() {
public StatsDimensionsValue createFromParcel(Parcel in) {
return new StatsDimensionsValue(in);
diff --git a/api/current.txt b/api/current.txt
index 515df6d8b654..a577c62ffe29 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -31293,7 +31293,7 @@ package android.net.wifi {
field public static final String ACTION_PICK_WIFI_NETWORK = "android.net.wifi.PICK_WIFI_NETWORK";
field public static final String ACTION_REQUEST_SCAN_ALWAYS_AVAILABLE = "android.net.wifi.action.REQUEST_SCAN_ALWAYS_AVAILABLE";
field public static final String ACTION_WIFI_NETWORK_SUGGESTION_POST_CONNECTION = "android.net.wifi.action.WIFI_NETWORK_SUGGESTION_POST_CONNECTION";
- field public static final String ACTION_WIFI_SCAN_AVAILABLE = "android.net.wifi.action.WIFI_SCAN_AVAILABLE";
+ field public static final String ACTION_WIFI_SCAN_AVAILABILITY_CHANGED = "android.net.wifi.action.WIFI_SCAN_AVAILABILITY_CHANGED";
field @Deprecated public static final int ERROR_AUTHENTICATING = 1; // 0x1
field @Deprecated public static final String EXTRA_BSSID = "bssid";
field public static final String EXTRA_NETWORK_INFO = "networkInfo";
diff --git a/api/module-app-current.txt b/api/module-app-current.txt
deleted file mode 100644
index d802177e249b..000000000000
--- a/api/module-app-current.txt
+++ /dev/null
@@ -1 +0,0 @@
-// Signature format: 2.0
diff --git a/api/module-app-removed.txt b/api/module-app-removed.txt
deleted file mode 100644
index d802177e249b..000000000000
--- a/api/module-app-removed.txt
+++ /dev/null
@@ -1 +0,0 @@
-// Signature format: 2.0
diff --git a/api/module-lib-current.txt b/api/module-lib-current.txt
index d11801b359c8..b42594740433 100644
--- a/api/module-lib-current.txt
+++ b/api/module-lib-current.txt
@@ -87,8 +87,8 @@ package android.timezone {
method @NonNull public java.util.List<android.timezone.CountryTimeZones.TimeZoneMapping> getEffectiveTimeZoneMappingsAt(long);
method public boolean hasUtcZone(long);
method public boolean isDefaultTimeZoneBoosted();
- method public boolean isForCountryCode(@NonNull String);
method @Nullable public android.timezone.CountryTimeZones.OffsetResult lookupByOffsetWithBias(int, @Nullable Boolean, @Nullable Integer, long, @Nullable android.icu.util.TimeZone);
+ method public boolean matchesCountryCode(@NonNull String);
}
public static final class CountryTimeZones.OffsetResult {
@@ -98,7 +98,7 @@ package android.timezone {
}
public static final class CountryTimeZones.TimeZoneMapping {
- method @Nullable public android.icu.util.TimeZone getTimeZone();
+ method @NonNull public android.icu.util.TimeZone getTimeZone();
method @NonNull public String getTimeZoneId();
}
diff --git a/api/system-current.txt b/api/system-current.txt
index 8630b36f1595..89811ada123a 100755
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -2304,6 +2304,7 @@ package android.content.pm {
field public static final int PROTECTION_FLAG_DOCUMENTER = 262144; // 0x40000
field public static final int PROTECTION_FLAG_INCIDENT_REPORT_APPROVER = 1048576; // 0x100000
field public static final int PROTECTION_FLAG_OEM = 16384; // 0x4000
+ field public static final int PROTECTION_FLAG_RETAIL_DEMO = 16777216; // 0x1000000
field public static final int PROTECTION_FLAG_SYSTEM_TEXT_CLASSIFIER = 65536; // 0x10000
field public static final int PROTECTION_FLAG_TELEPHONY = 4194304; // 0x400000
field public static final int PROTECTION_FLAG_WELLBEING = 131072; // 0x20000
@@ -7775,7 +7776,7 @@ package android.net.wifi {
}
public static interface WifiManager.ScoreChangeCallback {
- method public void onStatusChange(int, boolean);
+ method public void onScoreChange(int, @NonNull android.net.NetworkScore);
method public void onTriggerUpdateOfWifiUsabilityStats(int);
}
diff --git a/api/test-current.txt b/api/test-current.txt
index c8d746b44a15..cee560b00abe 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -933,6 +933,7 @@ package android.content.pm {
field public static final int PROTECTION_FLAG_DOCUMENTER = 262144; // 0x40000
field public static final int PROTECTION_FLAG_INCIDENT_REPORT_APPROVER = 1048576; // 0x100000
field public static final int PROTECTION_FLAG_OEM = 16384; // 0x4000
+ field public static final int PROTECTION_FLAG_RETAIL_DEMO = 16777216; // 0x1000000
field public static final int PROTECTION_FLAG_SYSTEM_TEXT_CLASSIFIER = 65536; // 0x10000
field public static final int PROTECTION_FLAG_TELEPHONY = 4194304; // 0x400000
field public static final int PROTECTION_FLAG_VENDOR_PRIVILEGED = 32768; // 0x8000
diff --git a/cmds/statsd/Android.bp b/cmds/statsd/Android.bp
index 2237bf2b2acb..ebed4ee2b82d 100644
--- a/cmds/statsd/Android.bp
+++ b/cmds/statsd/Android.bp
@@ -110,7 +110,7 @@ cc_defaults {
],
cflags: [
- // "-DNEW_ENCODING_SCHEME",
+ "-DNEW_ENCODING_SCHEME",
],
local_include_dirs: [
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index cc05dbb0639c..fccefdc07363 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -378,7 +378,7 @@ message Atom {
BootTimeEventUtcTime boot_time_event_utc_time_reported = 241;
BootTimeEventErrorCode boot_time_event_error_code_reported = 242 [(module) = "framework"];
UserspaceRebootReported userspace_reboot_reported = 243;
- NotificationReported notification_reported = 244;
+ NotificationReported notification_reported = 244 [(module) = "framework"];
NotificationPanelReported notification_panel_reported = 245;
NotificationChannelModified notification_panel_modified = 246;
IntegrityCheckResultReported integrity_check_result_reported = 247 [(module) = "framework"];
@@ -4247,6 +4247,9 @@ message BootTimeEventDuration {
// Time since last factory reset.
// Logged from bootstat.
FACTORY_RESET_TIME_SINCE_RESET = 18;
+ // Init's total time spent for completing the 1st stage.
+ // Logged from bootstat.
+ ANDROID_INIT_STAGE_1 = 19;
}
// Type of the event.
@@ -4274,19 +4277,19 @@ message BootTimeEventElapsedTime {
// BOOT_COMPLETE for device with no encryption.
BOOT_COMPLETE_NO_ENCRYPTION = 4;
// Adjusted BOOT_COMPLETE for encrypted device extracting decryption time.
- BOOT_COMPLETE_POST_DESCRYPT = 5;
+ BOOT_COMPLETE_POST_DECRYPT = 5;
// BOOT_COMPLETE after factory reset.
FACTORY_RESET_BOOT_COMPLETE = 6;
// BOOT_COMPLETE_NO_ENCRYPTION after factory reset.
FACTORY_RESET_BOOT_COMPLETE_NO_ENCRYPTION = 7;
- // BOOT_COMPLETE_POST_DESCRYPT after factory reset.
- FACTORY_RESET_BOOT_COMPLETE_POST_DESCRYPT = 8;
+ // BOOT_COMPLETE_POST_DECRYPT after factory reset.
+ FACTORY_RESET_BOOT_COMPLETE_POST_DECRYPT = 8;
// BOOT_COMPLETE after OTA.
OTA_BOOT_COMPLETE = 9;
// BOOT_COMPLETE_NO_ENCRYPTION after OTA.
OTA_BOOT_COMPLETE_NO_ENCRYPTION = 10;
- // BOOT_COMPLETE_POST_DESCRYPT after OTA.
- OTA_BOOT_COMPLETE_POST_DESCRYPT = 11;
+ // BOOT_COMPLETE_POST_DECRYPT after OTA.
+ OTA_BOOT_COMPLETE_POST_DECRYPT = 11;
// Time when the system starts sending LOCKED_BOOT_COMPLETED broadcast.
// Logged from f/b/services/.../UserController.java
FRAMEWORK_LOCKED_BOOT_COMPLETED = 12;
@@ -6479,6 +6482,8 @@ message PermissionGrantRequestResultReported {
USER_DENIED_WITH_PREJUDICE_IN_SETTINGS = 14;
// permission was automatically revoked after one-time permission expired
AUTO_ONE_TIME_PERMISSION_REVOKED = 15;
+ // permission was automatically revoked for unused app
+ AUTO_UNUSED_APP_PERMISSION_REVOKED = 16;
}
// The result of the permission grant
optional Result result = 6;
@@ -7556,6 +7561,28 @@ message AppPermissionFragmentActionReported {
// The result of the permission grant
optional bool permission_granted = 6;
+
+ // State of Permission Flags after grant as per android.content.pm.PermissionFlags
+ optional int32 permission_flags = 7;
+
+ enum Button {
+ UNDEFINED = 0;
+ // Allow button
+ ALLOW = 1;
+ // Deny button
+ DENY = 2;
+ // Ask every time button
+ ASK_EVERY_TIME = 3;
+ // Allow all the time button
+ ALLOW_ALWAYS = 4;
+ // Allow only while using the app button
+ ALLOW_FOREGROUND = 5;
+ // Same is Deny button but shown in while in use dialog
+ DENY_FOREGROUND = 6;
+ }
+
+ // Button pressed in the dialog
+ optional Button button_pressed = 8;
}
/**
diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
index 83983e80d479..5c606bc98235 100644
--- a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
@@ -547,14 +547,11 @@ void GaugeMetricProducer::flushIfNeededLocked(const int64_t& eventTimeNs) {
void GaugeMetricProducer::flushCurrentBucketLocked(const int64_t& eventTimeNs,
const int64_t& nextBucketStartTimeNs) {
int64_t fullBucketEndTimeNs = getCurrentBucketEndTimeNs();
+ int64_t bucketEndTime = eventTimeNs < fullBucketEndTimeNs ? eventTimeNs : fullBucketEndTimeNs;
GaugeBucket info;
info.mBucketStartNs = mCurrentBucketStartTimeNs;
- if (eventTimeNs < fullBucketEndTimeNs) {
- info.mBucketEndNs = eventTimeNs;
- } else {
- info.mBucketEndNs = fullBucketEndTimeNs;
- }
+ info.mBucketEndNs = bucketEndTime;
// Add bucket to mPastBuckets if bucket is large enough.
// Otherwise, drop the bucket data and add bucket metadata to mSkippedBuckets.
@@ -569,7 +566,7 @@ void GaugeMetricProducer::flushCurrentBucketLocked(const int64_t& eventTimeNs,
}
} else {
mCurrentSkippedBucket.bucketStartTimeNs = mCurrentBucketStartTimeNs;
- mCurrentSkippedBucket.bucketEndTimeNs = eventTimeNs;
+ mCurrentSkippedBucket.bucketEndTimeNs = bucketEndTime;
if (!maxDropEventsReached()) {
mCurrentSkippedBucket.dropEvents.emplace_back(
buildDropEvent(eventTimeNs, BucketDropReason::BUCKET_TOO_SMALL));
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.cpp b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
index 2a5b5302b619..dc9b41303894 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
@@ -379,9 +379,6 @@ void ValueMetricProducer::invalidateCurrentBucketWithoutResetBase(const int64_t
if (!mCurrentBucketIsInvalid) {
// Only report to StatsdStats once per invalid bucket.
StatsdStats::getInstance().noteInvalidatedBucket(mMetricId);
-
- mCurrentSkippedBucket.bucketStartTimeNs = mCurrentBucketStartTimeNs;
- mCurrentSkippedBucket.bucketEndTimeNs = getCurrentBucketEndTimeNs();
}
if (!maxDropEventsReached()) {
@@ -955,12 +952,6 @@ void ValueMetricProducer::flushCurrentBucketLocked(const int64_t& eventTimeNs,
int64_t conditionTrueDuration = mConditionTimer.newBucketStart(bucketEndTime);
bool isBucketLargeEnough = bucketEndTime - mCurrentBucketStartTimeNs >= mMinBucketSizeNs;
if (!isBucketLargeEnough) {
- // If the bucket is valid, this is the only drop reason and we need to
- // set the skipped bucket start and end times.
- if (!mCurrentBucketIsInvalid) {
- mCurrentSkippedBucket.bucketStartTimeNs = mCurrentBucketStartTimeNs;
- mCurrentSkippedBucket.bucketEndTimeNs = bucketEndTime;
- }
if (!maxDropEventsReached()) {
mCurrentSkippedBucket.dropEvents.emplace_back(
buildDropEvent(eventTimeNs, BucketDropReason::BUCKET_TOO_SMALL));
@@ -978,6 +969,8 @@ void ValueMetricProducer::flushCurrentBucketLocked(const int64_t& eventTimeNs,
}
}
} else {
+ mCurrentSkippedBucket.bucketStartTimeNs = mCurrentBucketStartTimeNs;
+ mCurrentSkippedBucket.bucketEndTimeNs = bucketEndTime;
mSkippedBuckets.emplace_back(mCurrentSkippedBucket);
}
diff --git a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
index 92e8241d9ec2..f6245ac8ea9a 100644
--- a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
@@ -3333,7 +3333,7 @@ TEST(ValueMetricProducerTest_BucketDrop, TestInvalidBucketWhenDumpReportRequeste
EXPECT_EQ(NanoToMillis(bucketStartTimeNs),
report.value_metrics().skipped(0).start_bucket_elapsed_millis());
- EXPECT_EQ(NanoToMillis(bucket2StartTimeNs),
+ EXPECT_EQ(NanoToMillis(bucketStartTimeNs + 40),
report.value_metrics().skipped(0).end_bucket_elapsed_millis());
EXPECT_EQ(1, report.value_metrics().skipped(0).drop_event_size());
@@ -3393,7 +3393,7 @@ TEST(ValueMetricProducerTest_BucketDrop, TestInvalidBucketWhenConditionEventWron
EXPECT_EQ(NanoToMillis(bucket2StartTimeNs),
report.value_metrics().skipped(0).start_bucket_elapsed_millis());
- EXPECT_EQ(NanoToMillis(bucket3StartTimeNs),
+ EXPECT_EQ(NanoToMillis(bucket2StartTimeNs + 100),
report.value_metrics().skipped(0).end_bucket_elapsed_millis());
EXPECT_EQ(1, report.value_metrics().skipped(0).drop_event_size());
@@ -3470,7 +3470,7 @@ TEST(ValueMetricProducerTest_BucketDrop, TestInvalidBucketWhenAccumulateEventWro
EXPECT_EQ(NanoToMillis(bucket2StartTimeNs),
report.value_metrics().skipped(0).start_bucket_elapsed_millis());
- EXPECT_EQ(NanoToMillis(bucket3StartTimeNs),
+ EXPECT_EQ(NanoToMillis(bucket2StartTimeNs + 100),
report.value_metrics().skipped(0).end_bucket_elapsed_millis());
EXPECT_EQ(1, report.value_metrics().skipped(0).drop_event_size());
@@ -3519,7 +3519,8 @@ TEST(ValueMetricProducerTest_BucketDrop, TestInvalidBucketWhenConditionUnknown)
// Check dump report.
ProtoOutputStream output;
std::set<string> strSet;
- valueProducer->onDumpReport(bucketStartTimeNs + 100, true /* include recent buckets */, true,
+ int64_t dumpReportTimeNs = bucketStartTimeNs + 10000;
+ valueProducer->onDumpReport(dumpReportTimeNs, true /* include recent buckets */, true,
NO_TIME_CONSTRAINTS /* dumpLatency */, &strSet, &output);
StatsLogReport report = outputStreamToProto(&output);
@@ -3529,13 +3530,13 @@ TEST(ValueMetricProducerTest_BucketDrop, TestInvalidBucketWhenConditionUnknown)
EXPECT_EQ(NanoToMillis(bucketStartTimeNs),
report.value_metrics().skipped(0).start_bucket_elapsed_millis());
- EXPECT_EQ(NanoToMillis(bucket2StartTimeNs),
+ EXPECT_EQ(NanoToMillis(dumpReportTimeNs),
report.value_metrics().skipped(0).end_bucket_elapsed_millis());
EXPECT_EQ(1, report.value_metrics().skipped(0).drop_event_size());
auto dropEvent = report.value_metrics().skipped(0).drop_event(0);
EXPECT_EQ(BucketDropReason::CONDITION_UNKNOWN, dropEvent.drop_reason());
- EXPECT_EQ(NanoToMillis(bucketStartTimeNs + 100), dropEvent.drop_time_millis());
+ EXPECT_EQ(NanoToMillis(dumpReportTimeNs), dropEvent.drop_time_millis());
}
/*
@@ -3569,7 +3570,8 @@ TEST(ValueMetricProducerTest_BucketDrop, TestInvalidBucketWhenPullFailed) {
// Check dump report.
ProtoOutputStream output;
std::set<string> strSet;
- valueProducer->onDumpReport(bucketStartTimeNs + 100, true /* include recent buckets */, true,
+ int64_t dumpReportTimeNs = bucketStartTimeNs + 10000;
+ valueProducer->onDumpReport(dumpReportTimeNs, true /* include recent buckets */, true,
NO_TIME_CONSTRAINTS /* dumpLatency */, &strSet, &output);
StatsLogReport report = outputStreamToProto(&output);
@@ -3579,13 +3581,13 @@ TEST(ValueMetricProducerTest_BucketDrop, TestInvalidBucketWhenPullFailed) {
EXPECT_EQ(NanoToMillis(bucketStartTimeNs),
report.value_metrics().skipped(0).start_bucket_elapsed_millis());
- EXPECT_EQ(NanoToMillis(bucket2StartTimeNs),
+ EXPECT_EQ(NanoToMillis(dumpReportTimeNs),
report.value_metrics().skipped(0).end_bucket_elapsed_millis());
EXPECT_EQ(1, report.value_metrics().skipped(0).drop_event_size());
auto dropEvent = report.value_metrics().skipped(0).drop_event(0);
EXPECT_EQ(BucketDropReason::PULL_FAILED, dropEvent.drop_reason());
- EXPECT_EQ(NanoToMillis(bucketStartTimeNs + 100), dropEvent.drop_time_millis());
+ EXPECT_EQ(NanoToMillis(dumpReportTimeNs), dropEvent.drop_time_millis());
}
/*
@@ -3691,8 +3693,9 @@ TEST(ValueMetricProducerTest_BucketDrop, TestBucketDropWhenBucketTooSmall) {
// Check dump report.
ProtoOutputStream output;
std::set<string> strSet;
- valueProducer->onDumpReport(bucketStartTimeNs + 9000000, true /* include recent buckets */,
- true, NO_TIME_CONSTRAINTS /* dumpLatency */, &strSet, &output);
+ int64_t dumpReportTimeNs = bucketStartTimeNs + 9000000;
+ valueProducer->onDumpReport(dumpReportTimeNs, true /* include recent buckets */, true,
+ NO_TIME_CONSTRAINTS /* dumpLatency */, &strSet, &output);
StatsLogReport report = outputStreamToProto(&output);
EXPECT_TRUE(report.has_value_metrics());
@@ -3701,13 +3704,13 @@ TEST(ValueMetricProducerTest_BucketDrop, TestBucketDropWhenBucketTooSmall) {
EXPECT_EQ(NanoToMillis(bucketStartTimeNs),
report.value_metrics().skipped(0).start_bucket_elapsed_millis());
- EXPECT_EQ(NanoToMillis(bucketStartTimeNs + 9000000),
+ EXPECT_EQ(NanoToMillis(dumpReportTimeNs),
report.value_metrics().skipped(0).end_bucket_elapsed_millis());
EXPECT_EQ(1, report.value_metrics().skipped(0).drop_event_size());
auto dropEvent = report.value_metrics().skipped(0).drop_event(0);
EXPECT_EQ(BucketDropReason::BUCKET_TOO_SMALL, dropEvent.drop_reason());
- EXPECT_EQ(NanoToMillis(bucketStartTimeNs + 9000000), dropEvent.drop_time_millis());
+ EXPECT_EQ(NanoToMillis(dumpReportTimeNs), dropEvent.drop_time_millis());
}
/*
@@ -3739,7 +3742,8 @@ TEST(ValueMetricProducerTest_BucketDrop, TestMultipleBucketDropEvents) {
// Check dump report.
ProtoOutputStream output;
std::set<string> strSet;
- valueProducer->onDumpReport(bucketStartTimeNs + 1000, true /* include recent buckets */, true,
+ int64_t dumpReportTimeNs = bucketStartTimeNs + 1000;
+ valueProducer->onDumpReport(dumpReportTimeNs, true /* include recent buckets */, true,
FAST /* dumpLatency */, &strSet, &output);
StatsLogReport report = outputStreamToProto(&output);
@@ -3749,7 +3753,7 @@ TEST(ValueMetricProducerTest_BucketDrop, TestMultipleBucketDropEvents) {
EXPECT_EQ(NanoToMillis(bucketStartTimeNs),
report.value_metrics().skipped(0).start_bucket_elapsed_millis());
- EXPECT_EQ(NanoToMillis(bucket2StartTimeNs),
+ EXPECT_EQ(NanoToMillis(dumpReportTimeNs),
report.value_metrics().skipped(0).end_bucket_elapsed_millis());
EXPECT_EQ(2, report.value_metrics().skipped(0).drop_event_size());
@@ -3759,7 +3763,7 @@ TEST(ValueMetricProducerTest_BucketDrop, TestMultipleBucketDropEvents) {
dropEvent = report.value_metrics().skipped(0).drop_event(1);
EXPECT_EQ(BucketDropReason::DUMP_REPORT_REQUESTED, dropEvent.drop_reason());
- EXPECT_EQ(NanoToMillis(bucketStartTimeNs + 1000), dropEvent.drop_time_millis());
+ EXPECT_EQ(NanoToMillis(dumpReportTimeNs), dropEvent.drop_time_millis());
}
/*
@@ -3826,6 +3830,7 @@ TEST(ValueMetricProducerTest_BucketDrop, TestMaxBucketDropEvents) {
// Check dump report.
ProtoOutputStream output;
std::set<string> strSet;
+ int64_t dumpReportTimeNs = bucketStartTimeNs + 1000;
// Because we already have 10 dump events in the current bucket,
// this case should not be added to the list of dump events.
valueProducer->onDumpReport(bucketStartTimeNs + 1000, true /* include recent buckets */, true,
@@ -3838,7 +3843,7 @@ TEST(ValueMetricProducerTest_BucketDrop, TestMaxBucketDropEvents) {
EXPECT_EQ(NanoToMillis(bucketStartTimeNs),
report.value_metrics().skipped(0).start_bucket_elapsed_millis());
- EXPECT_EQ(NanoToMillis(bucket2StartTimeNs),
+ EXPECT_EQ(NanoToMillis(dumpReportTimeNs),
report.value_metrics().skipped(0).end_bucket_elapsed_millis());
EXPECT_EQ(10, report.value_metrics().skipped(0).drop_event_size());
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index 4e47594b6196..c60f7bd29ce8 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -278,7 +278,7 @@ public abstract class ActivityManagerInternal {
String resolvedType, boolean fgRequired, String callingPackage, @UserIdInt int userId,
boolean allowBackgroundActivityStarts) throws TransactionTooLargeException;
- public abstract void disconnectActivityFromServices(Object connectionHolder, Object conns);
+ public abstract void disconnectActivityFromServices(Object connectionHolder);
public abstract void cleanUpServices(@UserIdInt int userId, ComponentName component,
Intent baseIntent);
public abstract ActivityInfo getActivityInfoForUser(ActivityInfo aInfo, @UserIdInt int userId);
diff --git a/core/java/android/app/AppOpsManagerInternal.java b/core/java/android/app/AppOpsManagerInternal.java
index 9958c6a31027..c13c5a5ab9c4 100644
--- a/core/java/android/app/AppOpsManagerInternal.java
+++ b/core/java/android/app/AppOpsManagerInternal.java
@@ -21,6 +21,7 @@ import android.annotation.Nullable;
import android.util.SparseArray;
import android.util.SparseIntArray;
+import com.android.internal.app.IAppOpsCallback;
import com.android.internal.util.function.HexFunction;
import com.android.internal.util.function.QuadFunction;
@@ -91,4 +92,16 @@ public abstract class AppOpsManagerInternal {
*/
public abstract void updateAppWidgetVisibility(SparseArray<String> uidPackageNames,
boolean visible);
+
+ /**
+ * Like {@link AppOpsManager#setUidMode}, but allows ignoring a certain callback.
+ */
+ public abstract void setUidModeIgnoringCallback(int code, int uid, int mode,
+ @Nullable IAppOpsCallback callbackToIgnore);
+
+ /**
+ * Like {@link AppOpsManager#setMode}, but allows ignoring a certain callback.
+ */
+ public abstract void setModeIgnoringCallback(int code, int uid, @NonNull String packageName,
+ int mode, @Nullable IAppOpsCallback callbackToIgnore);
}
diff --git a/core/java/android/app/prediction/AppPredictionContext.java b/core/java/android/app/prediction/AppPredictionContext.java
index d14238bb2672..8fc7e8d256b6 100644
--- a/core/java/android/app/prediction/AppPredictionContext.java
+++ b/core/java/android/app/prediction/AppPredictionContext.java
@@ -100,6 +100,16 @@ public final class AppPredictionContext implements Parcelable {
&& mPackageName.equals(other.mPackageName);
}
+ @NonNull
+ @Override
+ public String toString() {
+ return new StringBuilder(this.getClass().getSimpleName())
+ .append("[mUiSurface=").append(mUiSurface)
+ .append(",mPackageName=").append(mPackageName)
+ .append(",mPredictedTargetCount=").append(mPredictedTargetCount)
+ .append(",mExtras=").append(mExtras.toString()).append("]").toString();
+ }
+
@Override
public int describeContents() {
return 0;
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index b64c001ea6e2..6d5e8fb0240e 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -1506,6 +1506,15 @@ public abstract class PackageManager {
*/
public static final int INSTALL_FAILED_WRONG_INSTALLED_VERSION = -121;
+ /**
+ * Installation return code: this is passed in the {@link PackageInstaller#EXTRA_LEGACY_STATUS}
+ * if the new package failed because it contains a request to use a process that was not
+ * explicitly defined as part of its &lt;processes&gt; tag.
+ *
+ * @hide
+ */
+ public static final int INSTALL_FAILED_PROCESS_NOT_DEFINED = -122;
+
/** @hide */
@IntDef(flag = true, prefix = { "DELETE_" }, value = {
DELETE_KEEP_DATA,
@@ -7237,6 +7246,7 @@ public abstract class PackageManager {
case INSTALL_FAILED_MISSING_SPLIT: return "INSTALL_FAILED_MISSING_SPLIT";
case INSTALL_FAILED_BAD_SIGNATURE: return "INSTALL_FAILED_BAD_SIGNATURE";
case INSTALL_FAILED_WRONG_INSTALLED_VERSION: return "INSTALL_FAILED_WRONG_INSTALLED_VERSION";
+ case INSTALL_FAILED_PROCESS_NOT_DEFINED: return "INSTALL_FAILED_PROCESS_NOT_DEFINED";
default: return Integer.toString(status);
}
}
diff --git a/core/java/android/content/pm/PermissionInfo.java b/core/java/android/content/pm/PermissionInfo.java
index a0f089b2df41..3aa1a6d3f8ff 100644
--- a/core/java/android/content/pm/PermissionInfo.java
+++ b/core/java/android/content/pm/PermissionInfo.java
@@ -259,6 +259,17 @@ public class PermissionInfo extends PackageItemInfo implements Parcelable {
@TestApi
public static final int PROTECTION_FLAG_COMPANION = 0x800000;
+ /**
+ * Additional flag for {@link #protectionLevel}, corresponding
+ * to the <code>retailDemo</code> value of
+ * {@link android.R.attr#protectionLevel}.
+ *
+ * @hide
+ */
+ @SystemApi
+ @TestApi
+ public static final int PROTECTION_FLAG_RETAIL_DEMO = 0x1000000;
+
/** @hide */
@IntDef(flag = true, prefix = { "PROTECTION_FLAG_" }, value = {
PROTECTION_FLAG_PRIVILEGED,
@@ -282,6 +293,7 @@ public class PermissionInfo extends PackageItemInfo implements Parcelable {
PROTECTION_FLAG_APP_PREDICTOR,
PROTECTION_FLAG_TELEPHONY,
PROTECTION_FLAG_COMPANION,
+ PROTECTION_FLAG_RETAIL_DEMO,
})
@Retention(RetentionPolicy.SOURCE)
public @interface ProtectionFlags {}
@@ -528,6 +540,9 @@ public class PermissionInfo extends PackageItemInfo implements Parcelable {
if ((level & PermissionInfo.PROTECTION_FLAG_TELEPHONY) != 0) {
protLevel += "|telephony";
}
+ if ((level & PermissionInfo.PROTECTION_FLAG_RETAIL_DEMO) != 0) {
+ protLevel += "|retailDemo";
+ }
return protLevel;
}
diff --git a/core/java/android/content/pm/parsing/ComponentParseUtils.java b/core/java/android/content/pm/parsing/ComponentParseUtils.java
index 9a0a6d54da50..a0f58120e8a1 100644
--- a/core/java/android/content/pm/parsing/ComponentParseUtils.java
+++ b/core/java/android/content/pm/parsing/ComponentParseUtils.java
@@ -3414,16 +3414,12 @@ public class ComponentParseUtils {
proc.name = sa.getNonConfigurationString(
R.styleable.AndroidManifestProcess_process,0);
proc.name = PackageParser.buildProcessName(parsingPackage.getPackageName(),
- null, proc.name, flags, separateProcesses, outError);
-
- if (proc.name == null || proc.name.length() <= 0) {
- outError[0] = "<process> does not specify android:process";
+ parsingPackage.getPackageName(), proc.name, flags, separateProcesses, outError);
+ if (outError[0] != null) {
return null;
}
- proc.name = PackageParser.buildProcessName(parsingPackage.getPackageName(),
- parsingPackage.getPackageName(), proc.name,
- flags, separateProcesses, outError);
- if (outError[0] != null) {
+ if (proc.name == null || proc.name.length() <= 0) {
+ outError[0] = "<process> does not specify android:process";
return null;
}
} finally {
diff --git a/core/java/android/os/incremental/IncrementalFileStorages.java b/core/java/android/os/incremental/IncrementalFileStorages.java
index 4a668791aeb9..987a53e337a0 100644
--- a/core/java/android/os/incremental/IncrementalFileStorages.java
+++ b/core/java/android/os/incremental/IncrementalFileStorages.java
@@ -17,24 +17,24 @@
package android.os.incremental;
/**
- * Set up files and directories used in an installation session.
- * Currently only used by Incremental Installation.
- * For Incremental installation, the expected outcome of this function is:
- * 0) All the files are in defaultStorage
- * 1) All APK files are in the same directory, bound to mApkStorage, and bound to the
- * InstallerSession's stage dir. The files are linked from mApkStorage to defaultStorage.
- * 2) All lib files are in the sub directories as their names suggest, and in the same parent
- * directory as the APK files. The files are linked from mApkStorage to defaultStorage.
- * 3) OBB files are in another directory that is different from APK files and lib files, bound
- * to mObbStorage. The files are linked from mObbStorage to defaultStorage.
+ * Set up files and directories used in an installation session. Currently only used by Incremental
+ * Installation. For Incremental installation, the expected outcome of this function is: 0) All the
+ * files are in defaultStorage 1) All APK files are in the same directory, bound to mApkStorage, and
+ * bound to the InstallerSession's stage dir. The files are linked from mApkStorage to
+ * defaultStorage. 2) All lib files are in the sub directories as their names suggest, and in the
+ * same parent directory as the APK files. The files are linked from mApkStorage to defaultStorage.
+ * 3) OBB files are in another directory that is different from APK files and lib files, bound to
+ * mObbStorage. The files are linked from mObbStorage to defaultStorage.
*
* @throws IllegalStateException the session is not an Incremental installation session.
*/
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.content.Context;
import android.content.pm.DataLoaderParams;
import android.content.pm.InstallationFile;
+import android.text.TextUtils;
import android.util.Slog;
import java.io.File;
@@ -42,6 +42,8 @@ import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
+import java.util.List;
+import java.util.Objects;
import java.util.Random;
/**
@@ -50,6 +52,10 @@ import java.util.Random;
*/
public final class IncrementalFileStorages {
private static final String TAG = "IncrementalFileStorages";
+
+ private static final String TMP_DIR_ROOT = "/data/incremental/tmp";
+ private static final Random TMP_DIR_RANDOM = new Random();
+
private @Nullable IncrementalStorage mDefaultStorage;
private @Nullable String mDefaultDir;
private @NonNull IncrementalManager mIncrementalManager;
@@ -61,41 +67,77 @@ public final class IncrementalFileStorages {
* TODO(b/133435829): code clean up
*
* @throws IllegalStateException the session is not an Incremental installation session.
+ * @throws IOException if fails to setup files or directories.
*/
- public IncrementalFileStorages(@NonNull String packageName,
+ public static IncrementalFileStorages initialize(Context context,
@NonNull File stageDir,
+ @NonNull DataLoaderParams dataLoaderParams,
+ List<InstallationFile> addedFiles) throws IOException {
+ // TODO(b/136132412): sanity check if session should not be incremental
+ IncrementalManager incrementalManager = (IncrementalManager) context.getSystemService(
+ Context.INCREMENTAL_SERVICE);
+ if (incrementalManager == null) {
+ // TODO(b/146080380): add incremental-specific error code
+ throw new IOException("Failed to obtain incrementalManager.");
+ }
+
+ IncrementalFileStorages result = null;
+ try {
+ result = new IncrementalFileStorages(stageDir, incrementalManager, dataLoaderParams);
+ for (InstallationFile file : addedFiles) {
+ if (file.getFileType() == InstallationFile.FILE_TYPE_APK) {
+ try {
+ result.addApkFile(file);
+ } catch (IOException e) {
+ // TODO(b/146080380): add incremental-specific error code
+ throw new IOException(
+ "Failed to add and configure Incremental File: " + file.getName(),
+ e);
+ }
+ } else {
+ throw new IOException("Unknown file type: " + file.getFileType());
+ }
+ }
+
+ if (!result.mDefaultStorage.startLoading()) {
+ // TODO(b/146080380): add incremental-specific error code
+ throw new IOException("Failed to start loading data for Incremental installation.");
+ }
+
+ return result;
+ } catch (IOException e) {
+ if (result != null) {
+ result.cleanUp();
+ }
+ throw e;
+ }
+ }
+
+ private IncrementalFileStorages(@NonNull File stageDir,
@NonNull IncrementalManager incrementalManager,
- @NonNull DataLoaderParams dataLoaderParams) {
+ @NonNull DataLoaderParams dataLoaderParams) throws IOException {
mStageDir = stageDir;
mIncrementalManager = incrementalManager;
if (dataLoaderParams.getComponentName().getPackageName().equals("local")) {
final String incrementalPath = dataLoaderParams.getArguments();
- mDefaultStorage = mIncrementalManager.openStorage(incrementalPath);
mDefaultDir = incrementalPath;
- return;
- }
- mDefaultDir = getTempDir();
- if (mDefaultDir == null) {
- return;
+ if (TextUtils.isEmpty(mDefaultDir)) {
+ throw new IOException("Failed to create storage: incrementalPath is empty");
+ }
+ mDefaultStorage = mIncrementalManager.openStorage(incrementalPath);
+ } else {
+ mDefaultDir = getTempDir();
+ if (mDefaultDir == null) {
+ throw new IOException("Failed to create storage: tempDir is empty");
+ }
+ mDefaultStorage = mIncrementalManager.createStorage(mDefaultDir,
+ dataLoaderParams,
+ IncrementalManager.CREATE_MODE_CREATE
+ | IncrementalManager.CREATE_MODE_TEMPORARY_BIND, false);
}
- mDefaultStorage = mIncrementalManager.createStorage(mDefaultDir,
- dataLoaderParams,
- IncrementalManager.CREATE_MODE_CREATE
- | IncrementalManager.CREATE_MODE_TEMPORARY_BIND, false);
- }
- /**
- * Adds a file into the installation session. Makes sure it will be placed inside
- * a proper storage instance, based on its file type.
- */
- public void addFile(@NonNull InstallationFile file) throws IOException {
if (mDefaultStorage == null) {
- throw new IOException("Cannot add file because default storage does not exist");
- }
- if (file.getFileType() == InstallationFile.FILE_TYPE_APK) {
- addApkFile(file);
- } else {
- throw new IOException("Unknown file type: " + file.getFileType());
+ throw new IOException("Failed to create storage");
}
}
@@ -108,26 +150,6 @@ public final class IncrementalFileStorages {
mDefaultStorage.makeFile(apkName, apk.getSize(), null,
apk.getMetadata(), 0, null, null, null);
}
- if (targetFile.exists()) {
- Slog.i(TAG, "!!! created: " + targetFile.getAbsolutePath());
- }
- }
-
- /**
- * Starts loading data for default storage.
- * TODO(b/136132412): update the implementation with latest API design.
- */
- public boolean startLoading() {
- if (mDefaultStorage == null) {
- return false;
- }
- return mDefaultStorage.startLoading();
- }
-
- /**
- * Sets up obb storage directory and create bindings.
- */
- public void finishSetUp() {
}
/**
@@ -135,22 +157,21 @@ public final class IncrementalFileStorages {
* TODO(b/136132412): make sure unnecessary binds are removed but useful storages are kept
*/
public void cleanUp() {
- if (mDefaultStorage != null && mDefaultDir != null) {
- try {
- mDefaultStorage.unBind(mDefaultDir);
- mDefaultStorage.unBind(mStageDir.getAbsolutePath());
- } catch (IOException ignored) {
- }
- mDefaultDir = null;
- mDefaultStorage = null;
+ Objects.requireNonNull(mDefaultStorage);
+
+ try {
+ mDefaultStorage.unBind(mDefaultDir);
+ mDefaultStorage.unBind(mStageDir.getAbsolutePath());
+ } catch (IOException ignored) {
}
+
+ mDefaultDir = null;
+ mDefaultStorage = null;
}
- private String getTempDir() {
- final String tmpDirRoot = "/data/incremental/tmp";
- final Random random = new Random();
- final Path tmpDir =
- Paths.get(tmpDirRoot, String.valueOf(random.nextInt(Integer.MAX_VALUE - 1)));
+ private static String getTempDir() {
+ final Path tmpDir = Paths.get(TMP_DIR_ROOT,
+ String.valueOf(TMP_DIR_RANDOM.nextInt(Integer.MAX_VALUE - 1)));
try {
Files.createDirectories(tmpDir);
} catch (Exception ex) {
diff --git a/core/java/android/timezone/CountryTimeZones.java b/core/java/android/timezone/CountryTimeZones.java
index 5875761bb1c9..970acd0a5b3f 100644
--- a/core/java/android/timezone/CountryTimeZones.java
+++ b/core/java/android/timezone/CountryTimeZones.java
@@ -51,8 +51,10 @@ public final class CountryTimeZones {
}
/**
- * Returns the ID for this mapping. See also {@link #getTimeZone()} which handles when the
- * ID is unrecognized.
+ * Returns the ID for this mapping. The ID is a tzdb time zone identifier like
+ * "America/Los_Angeles" that can be used with methods such as {@link
+ * TimeZone#getFrozenTimeZone(String)}. See {@link #getTimeZone()} which returns a frozen
+ * {@link TimeZone} object.
*/
@NonNull
public String getTimeZoneId() {
@@ -60,10 +62,9 @@ public final class CountryTimeZones {
}
/**
- * Returns a {@link TimeZone} object for this mapping, or {@code null} if the ID is
- * unrecognized.
+ * Returns a frozen {@link TimeZone} object for this mapping.
*/
- @Nullable
+ @NonNull
public TimeZone getTimeZone() {
return mDelegate.getTimeZone();
}
@@ -158,9 +159,10 @@ public final class CountryTimeZones {
}
/**
- * Returns true if the ISO code for the country is a match for the one specified.
+ * Returns true if the ISO code for the country is a case-insensitive match for the one
+ * supplied.
*/
- public boolean isForCountryCode(@NonNull String countryIso) {
+ public boolean matchesCountryCode(@NonNull String countryIso) {
return mDelegate.isForCountryCode(countryIso);
}
@@ -183,15 +185,25 @@ public final class CountryTimeZones {
}
/**
- * Qualifier for a country's default time zone. {@code true} indicates whether the default
- * would be a good choice <em>generally</em> when there's no other information available.
+ * Qualifier for a country's default time zone. {@code true} indicates that the country's
+ * default time zone would be a good choice <em>generally</em> when there's no UTC offset
+ * information available. This will only be {@code true} in countries with multiple zones where
+ * a large majority of the population is covered by only one of them.
*/
public boolean isDefaultTimeZoneBoosted() {
return mDelegate.isDefaultTimeZoneBoosted();
}
/**
- * Returns true if the country has at least one zone that is the same as UTC at the given time.
+ * Returns {@code true} if the country has at least one time zone that uses UTC at the given
+ * time. This is an efficient check when trying to validate received UTC offset information.
+ * For example, there are situations when a detected zero UTC offset cannot be distinguished
+ * from "no information available" or a corrupted signal. This method is useful because checking
+ * offset information for large countries is relatively expensive but it is generally only the
+ * countries close to the prime meridian that use UTC at <em>any</em> time of the year.
+ *
+ * @param whenMillis the time the offset information is for in milliseconds since the beginning
+ * of the Unix epoch
*/
public boolean hasUtcZone(long whenMillis) {
return mDelegate.hasUtcZone(whenMillis);
diff --git a/core/java/android/util/RotationUtils.java b/core/java/android/util/RotationUtils.java
new file mode 100644
index 000000000000..a44ed59c14d4
--- /dev/null
+++ b/core/java/android/util/RotationUtils.java
@@ -0,0 +1,72 @@
+/*
+ * 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.util;
+
+import static android.view.Surface.ROTATION_0;
+import static android.view.Surface.ROTATION_180;
+import static android.view.Surface.ROTATION_270;
+import static android.view.Surface.ROTATION_90;
+
+import android.graphics.Insets;
+import android.view.Surface.Rotation;
+
+/**
+ * A class containing utility methods related to rotation.
+ *
+ * @hide
+ */
+public class RotationUtils {
+
+ /**
+ * Rotates an Insets according to the given rotation.
+ */
+ public static Insets rotateInsets(Insets insets, @Rotation int rotation) {
+ if (insets == null || insets == Insets.NONE) {
+ return insets;
+ }
+ Insets rotated;
+ switch (rotation) {
+ case ROTATION_0:
+ rotated = insets;
+ break;
+ case ROTATION_90:
+ rotated = Insets.of(
+ insets.top,
+ insets.right,
+ insets.bottom,
+ insets.left);
+ break;
+ case ROTATION_180:
+ rotated = Insets.of(
+ insets.right,
+ insets.bottom,
+ insets.left,
+ insets.top);
+ break;
+ case ROTATION_270:
+ rotated = Insets.of(
+ insets.bottom,
+ insets.left,
+ insets.top,
+ insets.right);
+ break;
+ default:
+ throw new IllegalArgumentException("unknown rotation: " + rotation);
+ }
+ return rotated;
+ }
+}
diff --git a/core/java/android/view/ImeFocusController.java b/core/java/android/view/ImeFocusController.java
index 8d58ee83cd67..67e88a5a1831 100644
--- a/core/java/android/view/ImeFocusController.java
+++ b/core/java/android/view/ImeFocusController.java
@@ -253,4 +253,12 @@ public final class ImeFocusController {
public void setNextServedView(View view) {
mNextServedView = view;
}
+
+ /**
+ * Indicates whether the view's window has IME focused.
+ */
+ @UiThread
+ boolean hasImeFocus() {
+ return mHasImeFocus;
+ }
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 70475860cb4d..a407bd8f001e 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -14470,7 +14470,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @hide
*/
public boolean hasImeFocus() {
- return mAttachInfo != null && mAttachInfo.mHasImeFocus;
+ return getViewRootImpl() != null && getViewRootImpl().getImeFocusController().hasImeFocus();
}
/**
@@ -28725,11 +28725,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
boolean mHasWindowFocus;
/**
- * Indicates whether the view's window has IME focused.
- */
- boolean mHasImeFocus;
-
- /**
* The current visibility of the window.
*/
int mWindowVisibility;
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 435c9113a7e8..4e3050c6b022 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -3145,8 +3145,7 @@ public final class ViewRootImpl implements ViewParent,
}
mAttachInfo.mHasWindowFocus = hasWindowFocus;
- mAttachInfo.mHasImeFocus = mImeFocusController.updateImeFocusable(
- mWindowAttributes, true /* force */);
+ mImeFocusController.updateImeFocusable(mWindowAttributes, true /* force */);
mImeFocusController.onPreWindowFocus(hasWindowFocus, mWindowAttributes);
if (mView != null) {
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 307abd2f5f65..f0c16aadf12f 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -671,6 +671,11 @@ public final class InputMethodManager {
mWindowFocusGainFuture = null;
}
synchronized (mH) {
+ if (mCurRootView != null) {
+ // Reset the last served view and restart window focus state of the root view.
+ mCurRootView.getImeFocusController().setServedView(null);
+ mRestartOnNextWindowFocus = true;
+ }
mCurRootView = rootView;
}
}
diff --git a/core/java/android/widget/Magnifier.java b/core/java/android/widget/Magnifier.java
index 57b63a7a9f0d..50da6ce19f44 100644
--- a/core/java/android/widget/Magnifier.java
+++ b/core/java/android/widget/Magnifier.java
@@ -854,6 +854,8 @@ public final class Magnifier {
// The z of the magnifier surface, defining its z order in the list of
// siblings having the same parent surface (usually the main app surface).
private static final int SURFACE_Z = 5;
+ // The width of the ramp region in pixels on the left & right sides of the fish-eye effect.
+ private static final int FISHEYE_RAMP_WIDTH = 30;
// Display associated to the view the magnifier is attached to.
private final Display mDisplay;
@@ -906,7 +908,8 @@ public final class Magnifier {
// Whether is in the new magnifier style.
private boolean mIsFishEyeStyle;
// The mesh matrix for the fish-eye effect.
- private float[] mMesh;
+ private float[] mMeshLeft;
+ private float[] mMeshRight;
private int mMeshWidth;
private int mMeshHeight;
@@ -986,29 +989,29 @@ public final class Magnifier {
}
private void createMeshMatrixForFishEyeEffect() {
- mMeshWidth = mZoom < 1.5f ? 5 : 4;
+ mMeshWidth = 1;
mMeshHeight = 6;
final float w = mContentWidth;
final float h = mContentHeight;
- final float dx = (w - mZoom * w * (mMeshWidth - 2) / mMeshWidth) / 2;
- mMesh = new float[2 * (mMeshWidth + 1) * (mMeshHeight + 1)];
+ final float h0 = h / mZoom;
+ final float dh = h - h0;
+ final float ramp = FISHEYE_RAMP_WIDTH;
+ mMeshLeft = new float[2 * (mMeshWidth + 1) * (mMeshHeight + 1)];
+ mMeshRight = new float[2 * (mMeshWidth + 1) * (mMeshHeight + 1)];
for (int i = 0; i < 2 * (mMeshWidth + 1) * (mMeshHeight + 1); i += 2) {
// Calculates X value.
final int colIndex = i % (2 * (mMeshWidth + 1)) / 2;
- if (colIndex == 0) {
- mMesh[i] = 0;
- } else if (colIndex == mMeshWidth) {
- mMesh[i] = w;
- } else {
- mMesh[i] = (colIndex - 1) * (w - 2 * dx) / (mMeshWidth - 2) + dx;
- }
+ mMeshLeft[i] = (float) colIndex * ramp / mMeshWidth;
+ mMeshRight[i] = w - ramp + colIndex * ramp / mMeshWidth;
+
// Calculates Y value.
final int rowIndex = i / 2 / (mMeshWidth + 1);
- final float y0 = colIndex == 0 || colIndex == mMeshWidth
- ? (h - h / mZoom) / 2 : 0;
- final float dy = colIndex == 0 || colIndex == mMeshWidth
- ? h / mZoom / mMeshHeight : h / mMeshHeight;
- mMesh[i + 1] = y0 + rowIndex * dy;
+ final float hl = h0 + dh * colIndex / mMeshWidth;
+ final float yl = (h - hl) / 2;
+ mMeshLeft[i + 1] = yl + hl * rowIndex / mMeshHeight;
+ final float hr = h - dh * colIndex / mMeshWidth;
+ final float yr = (h - hr) / 2;
+ mMeshRight[i + 1] = yr + hr * rowIndex / mMeshHeight;
}
}
@@ -1166,14 +1169,31 @@ public final class Magnifier {
final RecordingCanvas canvas =
mBitmapRenderNode.beginRecording(mContentWidth, mContentHeight);
try {
+ final int w = mBitmap.getWidth();
+ final int h = mBitmap.getHeight();
+ final Paint paint = new Paint();
+ paint.setFilterBitmap(true);
if (mIsFishEyeStyle) {
+ final int ramp = FISHEYE_RAMP_WIDTH;
+ final int margin =
+ (int)((mContentWidth - (mContentWidth - 2 * ramp) / mZoom) / 2);
+
+ // Draws the middle part.
+ final Rect srcRect = new Rect(margin, 0, w - margin, h);
+ final Rect dstRect = new Rect(
+ ramp, 0, mContentWidth - ramp, mContentHeight);
+ canvas.drawBitmap(mBitmap, srcRect, dstRect, paint);
+
+ // Draws the left/right parts with mesh matrixes.
+ canvas.drawBitmapMesh(
+ Bitmap.createBitmap(mBitmap, 0, 0, margin, h),
+ mMeshWidth, mMeshHeight, mMeshLeft, 0, null, 0, paint);
canvas.drawBitmapMesh(
- mBitmap, mMeshWidth, mMeshHeight, mMesh, 0, null, 0, null);
+ Bitmap.createBitmap(mBitmap, w - margin, 0, margin, h),
+ mMeshWidth, mMeshHeight, mMeshRight, 0, null, 0, paint);
} else {
- final Rect srcRect = new Rect(0, 0, mBitmap.getWidth(), mBitmap.getHeight());
+ final Rect srcRect = new Rect(0, 0, w, h);
final Rect dstRect = new Rect(0, 0, mContentWidth, mContentHeight);
- final Paint paint = new Paint();
- paint.setFilterBitmap(true);
canvas.drawBitmap(mBitmap, srcRect, dstRect, paint);
}
} finally {
diff --git a/core/java/com/android/ims/internal/uce/common/CapInfo.java b/core/java/com/android/ims/internal/uce/common/CapInfo.java
index 2bb3f1fed927..a7a90f6912c2 100644
--- a/core/java/com/android/ims/internal/uce/common/CapInfo.java
+++ b/core/java/com/android/ims/internal/uce/common/CapInfo.java
@@ -78,6 +78,10 @@ public class CapInfo implements Parcelable {
private boolean mChatbotSupported = false;
/** Chatbot role support. */
private boolean mChatbotRoleSupported = false;
+ /** Standalone Chatbot communication support. */
+ private boolean mSmChatbotSupported = false;
+ /** MMtel based call composer support. */
+ private boolean mMmtelCallComposerSupported = false;
/** List of supported extensions. */
private String[] mExts = new String[10];
/** Time used to compute when to query again. */
@@ -498,6 +502,34 @@ public class CapInfo implements Parcelable {
this.mChatbotRoleSupported = chatbotRoleSupported;
}
+ /**
+ * Checks whether standalone chatbot communication is supported.
+ */
+ public boolean isSmChatbotSupported() {
+ return mSmChatbotSupported;
+ }
+
+ /**
+ * Sets standalone chatbot communication as supported or not supported.
+ */
+ public void setSmChatbotSupported(boolean smChatbotSupported) {
+ this.mSmChatbotSupported = smChatbotSupported;
+ }
+
+ /**
+ * Checks whether Mmtel based call composer is supported.
+ */
+ public boolean isMmtelCallComposerSupported() {
+ return mMmtelCallComposerSupported;
+ }
+
+ /**
+ * Sets Mmtel based call composer as supported or not supported.
+ */
+ public void setMmtelCallComposerSupported(boolean mmtelCallComposerSupported) {
+ this.mMmtelCallComposerSupported = mmtelCallComposerSupported;
+ }
+
/** Gets the list of supported extensions. */
public String[] getExts() {
return mExts;
@@ -553,6 +585,8 @@ public class CapInfo implements Parcelable {
dest.writeInt(mSharedSketchSupported ? 1 : 0);
dest.writeInt(mChatbotSupported ? 1 : 0);
dest.writeInt(mChatbotRoleSupported ? 1 : 0);
+ dest.writeInt(mSmChatbotSupported ? 1 : 0);
+ dest.writeInt(mMmtelCallComposerSupported ? 1 : 0);
dest.writeInt(mRcsIpVoiceCallSupported ? 1 : 0);
dest.writeInt(mRcsIpVideoCallSupported ? 1 : 0);
@@ -602,6 +636,8 @@ public class CapInfo implements Parcelable {
mSharedSketchSupported = (source.readInt() == 0) ? false : true;
mChatbotSupported = (source.readInt() == 0) ? false : true;
mChatbotRoleSupported = (source.readInt() == 0) ? false : true;
+ mSmChatbotSupported = (source.readInt() == 0) ? false : true;
+ mMmtelCallComposerSupported = (source.readInt() == 0) ? false : true;
mRcsIpVoiceCallSupported = (source.readInt() == 0) ? false : true;
mRcsIpVideoCallSupported = (source.readInt() == 0) ? false : true;
diff --git a/core/java/com/android/internal/app/AccessibilityButtonChooserActivity.java b/core/java/com/android/internal/app/AccessibilityButtonChooserActivity.java
index 384275f64e3d..6a6a60d6617c 100644
--- a/core/java/com/android/internal/app/AccessibilityButtonChooserActivity.java
+++ b/core/java/com/android/internal/app/AccessibilityButtonChooserActivity.java
@@ -39,6 +39,8 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
import android.content.res.TypedArray;
+import android.graphics.ColorMatrix;
+import android.graphics.ColorMatrixColorFilter;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Bundle;
@@ -74,6 +76,8 @@ import java.util.StringJoiner;
*/
public class AccessibilityButtonChooserActivity extends Activity {
private static final char SERVICES_SEPARATOR = ':';
+ private static final float DISABLED_ALPHA = 0.5f;
+ private static final float ENABLED_ALPHA = 1.0f;
private static final TextUtils.SimpleStringSplitter sStringColonSplitter =
new TextUtils.SimpleStringSplitter(SERVICES_SEPARATOR);
@ShortcutType
@@ -452,9 +456,16 @@ public class AccessibilityButtonChooserActivity extends Activity {
final boolean isLaunchMenuMode = (mShortcutMenuMode == ShortcutMenuMode.LAUNCH);
final boolean isHardwareButtonTriggered =
(mShortcutButtonType == ACCESSIBILITY_SHORTCUT_KEY);
-
- holder.mLabelView.setEnabled(isLaunchMenuMode || isHardwareButtonTriggered);
- holder.mViewItem.setEnabled(isLaunchMenuMode || isHardwareButtonTriggered);
+ final boolean enabledState = (isLaunchMenuMode || isHardwareButtonTriggered);
+ final ColorMatrix grayScaleMatrix = new ColorMatrix();
+ grayScaleMatrix.setSaturation(/* grayScale */0);
+
+ holder.mIconView.setColorFilter(enabledState
+ ? null : new ColorMatrixColorFilter(grayScaleMatrix));
+ holder.mIconView.setAlpha(enabledState
+ ? ENABLED_ALPHA : DISABLED_ALPHA);
+ holder.mLabelView.setEnabled(enabledState);
+ holder.mViewItem.setEnabled(enabledState);
holder.mViewItem.setImageDrawable(context.getDrawable(R.drawable.ic_delete_item));
holder.mViewItem.setVisibility(View.VISIBLE);
holder.mSwitchItem.setVisibility(View.GONE);
@@ -463,12 +474,15 @@ public class AccessibilityButtonChooserActivity extends Activity {
private void updateInvisibleActionItemVisibility(@NonNull Context context,
@NonNull ViewHolder holder) {
- final boolean isEditMenuMode = (mShortcutMenuMode == ShortcutMenuMode.EDIT);
-
+ holder.mIconView.setColorFilter(null);
+ holder.mIconView.setAlpha(ENABLED_ALPHA);
+ holder.mLabelView.setEnabled(true);
+ holder.mViewItem.setEnabled(true);
holder.mViewItem.setImageDrawable(context.getDrawable(R.drawable.ic_delete_item));
holder.mViewItem.setVisibility(View.VISIBLE);
holder.mSwitchItem.setVisibility(View.GONE);
- holder.mItemContainer.setVisibility(isEditMenuMode ? View.VISIBLE : View.GONE);
+ holder.mItemContainer.setVisibility((mShortcutMenuMode == ShortcutMenuMode.EDIT)
+ ? View.VISIBLE : View.GONE);
}
private void updateIntuitiveActionItemVisibility(@NonNull Context context,
@@ -478,6 +492,10 @@ public class AccessibilityButtonChooserActivity extends Activity {
? isWhiteListingServiceEnabled(context, target)
: isAccessibilityServiceEnabled(context, target);
+ holder.mIconView.setColorFilter(null);
+ holder.mIconView.setAlpha(ENABLED_ALPHA);
+ holder.mLabelView.setEnabled(true);
+ holder.mViewItem.setEnabled(true);
holder.mViewItem.setImageDrawable(context.getDrawable(R.drawable.ic_delete_item));
holder.mViewItem.setVisibility(isEditMenuMode ? View.VISIBLE : View.GONE);
holder.mSwitchItem.setVisibility(isEditMenuMode ? View.GONE : View.VISIBLE);
@@ -487,12 +505,13 @@ public class AccessibilityButtonChooserActivity extends Activity {
private void updateBounceActionItemVisibility(@NonNull Context context,
@NonNull ViewHolder holder) {
- final boolean isEditMenuMode = (mShortcutMenuMode == ShortcutMenuMode.EDIT);
-
- holder.mViewItem.setImageDrawable(
- isEditMenuMode ? context.getDrawable(R.drawable.ic_delete_item)
- : context.getDrawable(R.drawable.ic_open_in_new));
- holder.mViewItem.setVisibility(isEditMenuMode ? View.VISIBLE : View.GONE);
+ holder.mIconView.setColorFilter(null);
+ holder.mIconView.setAlpha(ENABLED_ALPHA);
+ holder.mLabelView.setEnabled(true);
+ holder.mViewItem.setEnabled(true);
+ holder.mViewItem.setImageDrawable(context.getDrawable(R.drawable.ic_delete_item));
+ holder.mViewItem.setVisibility((mShortcutMenuMode == ShortcutMenuMode.EDIT)
+ ? View.VISIBLE : View.GONE);
holder.mSwitchItem.setVisibility(View.GONE);
holder.mItemContainer.setVisibility(View.VISIBLE);
}
diff --git a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
index b232efc8f46c..3322834c9ed1 100644
--- a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
+++ b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
@@ -253,6 +253,13 @@ public final class SystemUiDeviceConfigFlags {
public static final String NOTIFICATIONS_USE_PEOPLE_FILTERING =
"notifications_use_people_filtering";
+ /**
+ * (boolean) Whether or not to enable user dismissing of foreground service notifications
+ * into a new section at the bottom of the notification shade.
+ */
+ public static final String NOTIFICATIONS_ALLOW_FGS_DISMISSAL =
+ "notifications_allow_fgs_dismissal";
+
// Flags related to brightline falsing
/**
diff --git a/core/java/com/android/internal/util/ObjectUtils.java b/core/java/com/android/internal/util/ObjectUtils.java
index 5568d91011dc..0e7b93d406f5 100644
--- a/core/java/com/android/internal/util/ObjectUtils.java
+++ b/core/java/com/android/internal/util/ObjectUtils.java
@@ -46,4 +46,12 @@ public class ObjectUtils {
return (b != null) ? -1 : 0;
}
}
+
+ /**
+ * Returns its first argument if non-null, and the second otherwise.
+ */
+ @Nullable
+ public static <T> T getOrElse(@Nullable final T object, @Nullable final T otherwise) {
+ return null != object ? object : otherwise;
+ }
}
diff --git a/core/proto/android/server/connectivity/data_stall_event.proto b/core/proto/android/server/connectivity/data_stall_event.proto
index a82326f67d74..23fcf6ebc2cc 100644
--- a/core/proto/android/server/connectivity/data_stall_event.proto
+++ b/core/proto/android/server/connectivity/data_stall_event.proto
@@ -34,7 +34,7 @@ enum ApBand {
AP_BAND_5GHZ = 2;
}
-// Refer to definition in ServiceState.java.
+// Refer to definition in TelephonyManager.java.
enum RadioTech {
RADIO_TECHNOLOGY_UNKNOWN = 0;
RADIO_TECHNOLOGY_GPRS = 1;
@@ -49,8 +49,8 @@ enum RadioTech {
RADIO_TECHNOLOGY_HSUPA = 10;
RADIO_TECHNOLOGY_HSPA = 11;
RADIO_TECHNOLOGY_EVDO_B = 12;
- RADIO_TECHNOLOGY_EHRPD = 13;
- RADIO_TECHNOLOGY_LTE = 14;
+ RADIO_TECHNOLOGY_LTE = 13;
+ RADIO_TECHNOLOGY_EHRPD = 14;
RADIO_TECHNOLOGY_HSPAP = 15;
RADIO_TECHNOLOGY_GSM = 16;
RADIO_TECHNOLOGY_TD_SCDMA = 17;
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 6df0161c3ca6..8b8b09f68c1b 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -377,7 +377,7 @@
<protected-broadcast android:name="android.net.wifi.action.PASSPOINT_SUBSCRIPTION_REMEDIATION" />
<protected-broadcast android:name="android.net.wifi.action.PASSPOINT_LAUNCH_OSU_VIEW" />
<protected-broadcast android:name="android.net.wifi.action.WIFI_NETWORK_SUGGESTION_POST_CONNECTION" />
- <protected-broadcast android:name="android.net.wifi.action.WIFI_SCAN_AVAILABLE" />
+ <protected-broadcast android:name="android.net.wifi.action.WIFI_SCAN_AVAILABILITY_CHANGED" />
<protected-broadcast android:name="android.net.wifi.supplicant.CONNECTION_CHANGE" />
<protected-broadcast android:name="android.net.wifi.supplicant.STATE_CHANGE" />
<protected-broadcast android:name="android.net.wifi.p2p.STATE_CHANGED" />
@@ -2088,7 +2088,6 @@
Allows reading of detailed information about phone state for special-use applications
such as dialers, carrier applications, or ims applications. -->
<permission android:name="android.permission.READ_PRECISE_PHONE_STATE"
- android:permissionGroup="android.permission-group.UNDEFINED"
android:protectionLevel="signature|privileged" />
<!-- @SystemApi Allows read access to privileged phone state.
@@ -4018,9 +4017,9 @@
statistics
<p>Declaring the permission implies intention to use the API and the user of the
device can grant permission through the Settings application.
- <p>Protection level: signature|privileged|development|appop -->
+ <p>Protection level: signature|privileged|development|appop|retailDemo -->
<permission android:name="android.permission.PACKAGE_USAGE_STATS"
- android:protectionLevel="signature|privileged|development|appop" />
+ android:protectionLevel="signature|privileged|development|appop|retailDemo" />
<uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" />
<!-- @hide @SystemApi Allows an application to observe usage time of apps. The app can register
diff --git a/core/res/res/drawable/ic_open_in_new.xml b/core/res/res/drawable/ic_open_in_new.xml
deleted file mode 100644
index 67378c8d4b8a..000000000000
--- a/core/res/res/drawable/ic_open_in_new.xml
+++ /dev/null
@@ -1,26 +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.
- -->
-
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
- android:viewportWidth="24"
- android:viewportHeight="24"
- android:tint="?attr/colorControlNormal">
- <path
- android:pathData="M19,19H5V5h7V3H5c-1.11,0 -2,0.9 -2,2v14c0,1.1 0.89,2 2,2h14c1.1,0 2,-0.9 2,-2v-7h-2v7zM14,3v2h3.59l-9.83,9.83 1.41,1.41L19,6.41V10h2V3h-7z"
- android:fillColor="#FFFFFF"/>
-</vector>
diff --git a/core/res/res/values-mcc334/config.xml b/core/res/res/values-mcc334/config.xml
new file mode 100644
index 000000000000..e99c9a028178
--- /dev/null
+++ b/core/res/res/values-mcc334/config.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** 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.
+*/
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- Show area update info settings in CellBroadcastReceiver and information in SIM status in Settings app -->
+ <bool name="config_showAreaUpdateInfoSettings">true</bool>
+</resources>
diff --git a/core/res/res/values-mcc732/config.xml b/core/res/res/values-mcc732/config.xml
new file mode 100644
index 000000000000..e99c9a028178
--- /dev/null
+++ b/core/res/res/values-mcc732/config.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** 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.
+*/
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- Show area update info settings in CellBroadcastReceiver and information in SIM status in Settings app -->
+ <bool name="config_showAreaUpdateInfoSettings">true</bool>
+</resources>
diff --git a/core/res/res/values-mcc740/config.xml b/core/res/res/values-mcc740/config.xml
new file mode 100644
index 000000000000..e99c9a028178
--- /dev/null
+++ b/core/res/res/values-mcc740/config.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** 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.
+*/
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- Show area update info settings in CellBroadcastReceiver and information in SIM status in Settings app -->
+ <bool name="config_showAreaUpdateInfoSettings">true</bool>
+</resources>
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 059bc443a609..b22e1867f257 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -301,6 +301,9 @@
<!-- Additional flag from base permission type: this permission can be automatically
granted to the system companion device manager service -->
<flag name="companion" value="0x800000" />
+ <!-- Additional flag from base permission type: this permission will be granted to the
+ retail demo app, as defined by the OEM. -->
+ <flag name="retailDemo" value="0x1000000" />
</attr>
<!-- Flags indicating more context for a permission group. -->
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 1c9cccb6a1dd..3d7b1e18be7b 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -3594,7 +3594,6 @@
-->
<string name="config_defaultWellbeingPackage" translatable="false"></string>
-
<!-- The package name for the system telephony apps.
This package must be trusted, as it will be granted with permissions with special telephony
protection level. Note, framework by default support multiple telephony apps, each package
@@ -3662,6 +3661,19 @@
-->
<string name="config_defaultContentSuggestionsService" translatable="false"></string>
+ <!-- The package name for the default retail demo app.
+ This package must be trusted, as it has the permissions to query the usage stats on the
+ device.
+ Example: "com.google.android.retaildemo"
+ -->
+ <string name="config_retailDemoPackage" translatable="false"></string>
+
+ <!-- The package signature hash for the default retail demo app.
+ This package must be trusted, as it has the permissions to query the usage stats on the
+ device.
+ -->
+ <string name="config_retailDemoPackageSignature" translatable="false"></string>
+
<!-- Whether the device uses the default focus highlight when focus state isn't specified. -->
<bool name="config_useDefaultFocusHighlight">true</bool>
@@ -4335,4 +4347,9 @@
<!-- Boolean indicating whether frameworks needs to reset cell broadcast geo-fencing
check after reboot or airplane mode toggling -->
<bool translatable="false" name="reset_geo_fencing_check_after_boot_or_apm">false</bool>
+
+ <!-- Screen Wake Keys
+ Determines whether the specified key groups can be used to wake up the device. -->
+ <bool name="config_wakeOnDpadKeyPress">true</bool>
+ <bool name="config_wakeOnAssistKeyPress">true</bool>
</resources>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 0b5082cdaf94..22abedcac2a7 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -33,9 +33,11 @@
<dimen name="toast_y_offset">24dp</dimen>
<!-- Height of the status bar -->
<dimen name="status_bar_height">@dimen/status_bar_height_portrait</dimen>
- <!-- Height of the status bar in portrait -->
+ <!-- Height of the status bar in portrait. The height should be
+ Max((status bar content height + waterfall top size), top cutout size) -->
<dimen name="status_bar_height_portrait">24dp</dimen>
- <!-- Height of the status bar in landscape -->
+ <!-- Height of the status bar in landscape. The height should be
+ Max((status bar content height + waterfall top size), top cutout size) -->
<dimen name="status_bar_height_landscape">@dimen/status_bar_height_portrait</dimen>
<!-- Height of area above QQS where battery/time go -->
<dimen name="quick_qs_offset_height">48dp</dimen>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 8f56164de688..36296a850dcb 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3028,6 +3028,10 @@
<java-symbol type="id" name="notification_action_list_margin_target" />
<java-symbol type="dimen" name="notification_action_disabled_alpha" />
+ <!-- Override Wake Key Behavior When Screen is Off -->
+ <java-symbol type="bool" name="config_wakeOnDpadKeyPress" />
+ <java-symbol type="bool" name="config_wakeOnAssistKeyPress" />
+
<!-- Pinner Service -->
<java-symbol type="array" name="config_defaultPinnerServiceFiles" />
<java-symbol type="bool" name="config_pinnerCameraApp" />
@@ -3227,7 +3231,6 @@
<java-symbol type="drawable" name="ic_accessibility_magnification" />
<java-symbol type="drawable" name="ic_delete_item" />
- <java-symbol type="drawable" name="ic_open_in_new" />
<!-- com.android.internal.widget.RecyclerView -->
<java-symbol type="id" name="item_touch_helper_previous_elevation"/>
@@ -3397,6 +3400,8 @@
<java-symbol type="string" name="config_defaultAttentionService" />
<java-symbol type="string" name="config_defaultSystemCaptionsService" />
<java-symbol type="string" name="config_defaultSystemCaptionsManagerService" />
+ <java-symbol type="string" name="config_retailDemoPackage" />
+ <java-symbol type="string" name="config_retailDemoPackageSignature" />
<java-symbol type="string" name="notification_channel_foreground_service" />
<java-symbol type="string" name="foreground_service_app_in_background" />
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 692af584cd61..b5eba090691f 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -132,6 +132,7 @@ applications that come with the platform
<permission name="android.permission.APPROVE_INCIDENT_REPORTS"/>
<permission name="android.permission.READ_PRIVILEGED_PHONE_STATE" />
<permission name="android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME" />
+ <permission name="android.permission.PACKAGE_USAGE_STATS" />
</privapp-permissions>
<privapp-permissions package="com.android.phone">
@@ -400,5 +401,6 @@ applications that come with the platform
</privapp-permissions>
<privapp-permissions package="com.android.settings">
<permission name="android.permission.INSTALL_DYNAMIC_SYSTEM"/>
+ <permission name="android.permission.BIND_CELL_BROADCAST_SERVICE"/>
</privapp-permissions>
</permissions>
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.cpp b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
index b940cff04713..6f4af3d26b3a 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
@@ -24,6 +24,7 @@
#include <SkOverdrawColorFilter.h>
#include <SkPicture.h>
#include <SkPictureRecorder.h>
+#include <SkTypeface.h>
#include <SkSerialProcs.h>
#include "LightingInfo.h"
#include "VectorDrawable.h"
@@ -264,6 +265,9 @@ bool SkiaPipeline::setupMultiFrameCapture() {
SkSerialProcs procs;
procs.fImageProc = SkSharingSerialContext::serializeImage;
procs.fImageCtx = mSerialContext.get();
+ procs.fTypefaceProc = [](SkTypeface* tf, void* ctx){
+ return tf->serialize(SkTypeface::SerializeBehavior::kDoIncludeData);
+ };
// SkDocuments don't take owership of the streams they write.
// we need to keep it until after mMultiPic.close()
// procs is passed as a pointer, but just as a method of having an optional default.
@@ -405,6 +409,10 @@ void SkiaPipeline::endCapture(SkSurface* surface) {
std::invoke(mPictureCapturedCallback, std::move(picture));
} else {
// single frame skp to file
+ SkSerialProcs procs;
+ procs.fTypefaceProc = [](SkTypeface* tf, void* ctx){
+ return tf->serialize(SkTypeface::SerializeBehavior::kDoIncludeData);
+ };
auto data = picture->serialize();
savePictureAsync(data, mCapturedFile);
mCaptureSequence = 0;
diff --git a/media/java/android/media/session/MediaSessionManager.java b/media/java/android/media/session/MediaSessionManager.java
index 5ef466dfd0e9..69be8b307950 100644
--- a/media/java/android/media/session/MediaSessionManager.java
+++ b/media/java/android/media/session/MediaSessionManager.java
@@ -61,6 +61,7 @@ import java.util.concurrent.Executor;
* @see MediaSession
* @see MediaController
*/
+// TODO: (jinpark) Add API for getting and setting session policies from MediaSessionService.
@SystemService(Context.MEDIA_SESSION_SERVICE)
public final class MediaSessionManager {
private static final String TAG = "SessionManager";
diff --git a/media/tests/MediaRouteProvider/Android.bp b/media/tests/MediaRouteProvider/Android.bp
deleted file mode 100644
index da4282495ac2..000000000000
--- a/media/tests/MediaRouteProvider/Android.bp
+++ /dev/null
@@ -1,18 +0,0 @@
-android_test {
- name: "mediarouteprovider",
-
- srcs: ["**/*.java"],
-
- libs: [
- "android.test.runner",
- "android.test.base",
- ],
-
- static_libs: [
- "android-support-test",
- "mockito-target-minus-junit4",
- ],
-
- platform_apis: true,
- certificate: "platform",
-} \ No newline at end of file
diff --git a/media/tests/MediaRouteProvider/AndroidManifest.xml b/media/tests/MediaRouteProvider/AndroidManifest.xml
deleted file mode 100644
index 489a6214ecbd..000000000000
--- a/media/tests/MediaRouteProvider/AndroidManifest.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright 2019 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.mediarouteprovider.example">
-
- <application android:label="@string/app_name">
- <uses-library android:name="android.test.runner" />
- <service android:name=".SampleMediaRoute2ProviderService"
- android:label="@string/app_name"
- android:exported="true">
- <intent-filter>
- <action android:name="android.media.MediaRoute2ProviderService" />
- </intent-filter>
- </service>
- </application>
-</manifest>
diff --git a/media/tests/MediaRouteProvider/res/values/strings.xml b/media/tests/MediaRouteProvider/res/values/strings.xml
deleted file mode 100644
index bb970641ffda..000000000000
--- a/media/tests/MediaRouteProvider/res/values/strings.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<resources>
- <!-- name of the app [CHAR LIMIT=25]-->
- <string name="app_name">SampleMediaRouteProvider</string>
-</resources> \ No newline at end of file
diff --git a/media/tests/MediaRouter/AndroidManifest.xml b/media/tests/MediaRouter/AndroidManifest.xml
index a34a264e1247..95465007d5ea 100644
--- a/media/tests/MediaRouter/AndroidManifest.xml
+++ b/media/tests/MediaRouter/AndroidManifest.xml
@@ -17,10 +17,14 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.mediaroutertest">
- <uses-permission android:name="android.permission.CONTROL_MEDIA_ROUTE" />
-
<application android:label="@string/app_name">
<uses-library android:name="android.test.runner" />
+ <service android:name=".SampleMediaRoute2ProviderService"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.media.MediaRoute2ProviderService" />
+ </intent-filter>
+ </service>
</application>
<instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
diff --git a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java
index 16259ab45792..4316e42bb0e1 100644
--- a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java
+++ b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java
@@ -16,9 +16,23 @@
package com.android.mediaroutertest;
+import static android.media.MediaRoute2Info.FEATURE_LIVE_AUDIO;
import static android.media.MediaRoute2Info.PLAYBACK_VOLUME_FIXED;
import static android.media.MediaRoute2Info.PLAYBACK_VOLUME_VARIABLE;
+import static com.android.mediaroutertest.SampleMediaRoute2ProviderService.ACTION_REMOVE_ROUTE;
+import static com.android.mediaroutertest.SampleMediaRoute2ProviderService.FEATURE_SAMPLE;
+import static com.android.mediaroutertest.SampleMediaRoute2ProviderService.FEATURE_SPECIAL;
+import static com.android.mediaroutertest.SampleMediaRoute2ProviderService.ROUTE_ID1;
+import static com.android.mediaroutertest.SampleMediaRoute2ProviderService.ROUTE_ID2;
+import static com.android.mediaroutertest.SampleMediaRoute2ProviderService.ROUTE_ID5_TO_TRANSFER_TO;
+import static com.android.mediaroutertest.SampleMediaRoute2ProviderService.ROUTE_ID_FIXED_VOLUME;
+import static com.android.mediaroutertest.SampleMediaRoute2ProviderService.ROUTE_ID_SPECIAL_FEATURE;
+import static com.android.mediaroutertest.SampleMediaRoute2ProviderService.ROUTE_ID_VARIABLE_VOLUME;
+import static com.android.mediaroutertest.SampleMediaRoute2ProviderService.ROUTE_NAME1;
+import static com.android.mediaroutertest.SampleMediaRoute2ProviderService.ROUTE_NAME2;
+import static com.android.mediaroutertest.SampleMediaRoute2ProviderService.VOLUME_MAX;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
@@ -56,50 +70,6 @@ import java.util.function.Predicate;
@SmallTest
public class MediaRouterManagerTest {
private static final String TAG = "MediaRouterManagerTest";
-
- public static final String SAMPLE_PROVIDER_ROUTES_ID_PREFIX =
- "com.android.mediarouteprovider.example/.SampleMediaRoute2ProviderService:";
-
- // Must be the same as SampleMediaRoute2ProviderService except the prefix of IDs.
- public static final String ROUTE_ID1 = SAMPLE_PROVIDER_ROUTES_ID_PREFIX + "route_id1";
- public static final String ROUTE_NAME1 = "Sample Route 1";
- public static final String ROUTE_ID2 = SAMPLE_PROVIDER_ROUTES_ID_PREFIX + "route_id2";
- public static final String ROUTE_NAME2 = "Sample Route 2";
- public static final String ROUTE_ID3_SESSION_CREATION_FAILED =
- SAMPLE_PROVIDER_ROUTES_ID_PREFIX + "route_id3_session_creation_failed";
- public static final String ROUTE_NAME3 = "Sample Route 3 - Session creation failed";
- public static final String ROUTE_ID4_TO_SELECT_AND_DESELECT =
- SAMPLE_PROVIDER_ROUTES_ID_PREFIX + "route_id4_to_select_and_deselect";
- public static final String ROUTE_NAME4 = "Sample Route 4 - Route to select and deselect";
- public static final String ROUTE_ID5_TO_TRANSFER_TO =
- SAMPLE_PROVIDER_ROUTES_ID_PREFIX + "route_id5_to_transfer_to";
- public static final String ROUTE_NAME5 = "Sample Route 5 - Route to transfer to";
-
- public static final String ROUTE_ID_SPECIAL_FEATURE =
- SAMPLE_PROVIDER_ROUTES_ID_PREFIX + "route_special_feature";
- public static final String ROUTE_NAME_SPECIAL_FEATURE = "Special Feature Route";
-
- public static final String SYSTEM_PROVIDER_ID =
- "com.android.server.media/.SystemMediaRoute2Provider";
-
- public static final int VOLUME_MAX = 100;
- public static final String ROUTE_ID_FIXED_VOLUME =
- SAMPLE_PROVIDER_ROUTES_ID_PREFIX + "route_fixed_volume";
- public static final String ROUTE_NAME_FIXED_VOLUME = "Fixed Volume Route";
- public static final String ROUTE_ID_VARIABLE_VOLUME =
- SAMPLE_PROVIDER_ROUTES_ID_PREFIX + "route_variable_volume";
- public static final String ROUTE_NAME_VARIABLE_VOLUME = "Variable Volume Route";
-
- public static final String ACTION_REMOVE_ROUTE =
- "com.android.mediarouteprovider.action_remove_route";
-
- public static final String FEATURE_SAMPLE =
- "com.android.mediarouteprovider.FEATURE_SAMPLE";
- public static final String FEATURE_SPECIAL =
- "com.android.mediarouteprovider.FEATURE_SPECIAL";
-
- private static final String FEATURE_LIVE_AUDIO = "android.media.intent.route.LIVE_AUDIO";
-
private static final int TIMEOUT_MS = 5000;
private Context mContext;
@@ -155,7 +125,8 @@ public class MediaRouterManagerTest {
public void onRoutesAdded(List<MediaRoute2Info> routes) {
assertTrue(routes.size() > 0);
for (MediaRoute2Info route : routes) {
- if (route.getId().equals(ROUTE_ID1) && route.getName().equals(ROUTE_NAME1)) {
+ if (route.getOriginalId().equals(ROUTE_ID1)
+ && route.getName().equals(ROUTE_NAME1)) {
latch.countDown();
}
}
@@ -176,7 +147,8 @@ public class MediaRouterManagerTest {
public void onRoutesRemoved(List<MediaRoute2Info> routes) {
assertTrue(routes.size() > 0);
for (MediaRoute2Info route : routes) {
- if (route.getId().equals(ROUTE_ID2) && route.getName().equals(ROUTE_NAME2)) {
+ if (route.getOriginalId().equals(ROUTE_ID2)
+ && route.getName().equals(ROUTE_NAME2)) {
latch.countDown();
}
}
@@ -352,8 +324,7 @@ public class MediaRouterManagerTest {
@Override
public void onRoutesAdded(List<MediaRoute2Info> routes) {
for (int i = 0; i < routes.size(); i++) {
- //TODO: use isSystem() or similar method when it's ready
- if (!TextUtils.equals(routes.get(i).getProviderId(), SYSTEM_PROVIDER_ID)) {
+ if (!routes.get(i).isSystemRoute()) {
latch.countDown();
break;
}
@@ -406,7 +377,7 @@ public class MediaRouterManagerTest {
static Map<String, MediaRoute2Info> createRouteMap(List<MediaRoute2Info> routes) {
Map<String, MediaRoute2Info> routeMap = new HashMap<>();
for (MediaRoute2Info route : routes) {
- routeMap.put(route.getId(), route);
+ routeMap.put(route.getOriginalId(), route);
}
return routeMap;
}
diff --git a/media/tests/MediaRouteProvider/src/com/android/mediarouteprovider/example/SampleMediaRoute2ProviderService.java b/media/tests/MediaRouter/src/com/android/mediaroutertest/SampleMediaRoute2ProviderService.java
index 6595cae3c028..e29b3239fcaa 100644
--- a/media/tests/MediaRouteProvider/src/com/android/mediarouteprovider/example/SampleMediaRoute2ProviderService.java
+++ b/media/tests/MediaRouter/src/com/android/mediaroutertest/SampleMediaRoute2ProviderService.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.mediarouteprovider.example;
+package com.android.mediaroutertest;
import static android.media.MediaRoute2Info.DEVICE_TYPE_REMOTE_SPEAKER;
import static android.media.MediaRoute2Info.DEVICE_TYPE_REMOTE_TV;
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
index a784e04ee6a0..ddb7341b7366 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
@@ -16,6 +16,7 @@
package com.android.settingslib.bluetooth;
+import static android.bluetooth.BluetoothAdapter.ACTIVE_DEVICE_AUDIO;
import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_ALLOWED;
import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
@@ -45,6 +46,7 @@ public class A2dpProfile implements LocalBluetoothProfile {
private boolean mIsProfileReady;
private final CachedBluetoothDeviceManager mDeviceManager;
+ private final BluetoothAdapter mBluetoothAdapter;
static final ParcelUuid[] SINK_UUIDS = {
BluetoothUuid.A2DP_SINK,
@@ -99,7 +101,8 @@ public class A2dpProfile implements LocalBluetoothProfile {
mContext = context;
mDeviceManager = deviceManager;
mProfileManager = profileManager;
- BluetoothAdapter.getDefaultAdapter().getProfileProxy(context, new A2dpServiceListener(),
+ mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
+ mBluetoothAdapter.getProfileProxy(context, new A2dpServiceListener(),
BluetoothProfile.A2DP);
}
@@ -173,8 +176,10 @@ public class A2dpProfile implements LocalBluetoothProfile {
}
public boolean setActiveDevice(BluetoothDevice device) {
- if (mService == null) return false;
- return mService.setActiveDevice(device);
+ if (mBluetoothAdapter == null) {
+ return false;
+ }
+ return mBluetoothAdapter.setActiveDevice(device, ACTIVE_DEVICE_AUDIO);
}
public BluetoothDevice getActiveDevice() {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java
index d65b5da22056..218d0b2dc2c0 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java
@@ -16,6 +16,7 @@
package com.android.settingslib.bluetooth;
+import static android.bluetooth.BluetoothAdapter.ACTIVE_DEVICE_PHONE_CALL;
import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_ALLOWED;
import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
@@ -45,6 +46,7 @@ public class HeadsetProfile implements LocalBluetoothProfile {
private final CachedBluetoothDeviceManager mDeviceManager;
private final LocalBluetoothProfileManager mProfileManager;
+ private final BluetoothAdapter mBluetoothAdapter;
static final ParcelUuid[] UUIDS = {
BluetoothUuid.HSP,
@@ -99,7 +101,8 @@ public class HeadsetProfile implements LocalBluetoothProfile {
LocalBluetoothProfileManager profileManager) {
mDeviceManager = deviceManager;
mProfileManager = profileManager;
- BluetoothAdapter.getDefaultAdapter().getProfileProxy(context, new HeadsetServiceListener(),
+ mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
+ mBluetoothAdapter.getProfileProxy(context, new HeadsetServiceListener(),
BluetoothProfile.HEADSET);
}
@@ -134,10 +137,10 @@ public class HeadsetProfile implements LocalBluetoothProfile {
}
public boolean setActiveDevice(BluetoothDevice device) {
- if (mService == null) {
+ if (mBluetoothAdapter == null) {
return false;
}
- return mService.setActiveDevice(device);
+ return mBluetoothAdapter.setActiveDevice(device, ACTIVE_DEVICE_PHONE_CALL);
}
public BluetoothDevice getActiveDevice() {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java
index 9f1af669c708..b82fb37a770f 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java
@@ -16,6 +16,7 @@
package com.android.settingslib.bluetooth;
+import static android.bluetooth.BluetoothAdapter.ACTIVE_DEVICE_ALL;
import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_ALLOWED;
import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
@@ -45,6 +46,7 @@ public class HearingAidProfile implements LocalBluetoothProfile {
static final String NAME = "HearingAid";
private final LocalBluetoothProfileManager mProfileManager;
+ private final BluetoothAdapter mBluetoothAdapter;
// Order of this profile in device profiles list
private static final int ORDINAL = 1;
@@ -97,7 +99,8 @@ public class HearingAidProfile implements LocalBluetoothProfile {
mContext = context;
mDeviceManager = deviceManager;
mProfileManager = profileManager;
- BluetoothAdapter.getDefaultAdapter().getProfileProxy(context,
+ mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
+ mBluetoothAdapter.getProfileProxy(context,
new HearingAidServiceListener(), BluetoothProfile.HEARING_AID);
}
@@ -171,8 +174,10 @@ public class HearingAidProfile implements LocalBluetoothProfile {
}
public boolean setActiveDevice(BluetoothDevice device) {
- if (mService == null) return false;
- return mService.setActiveDevice(device);
+ if (mBluetoothAdapter == null) {
+ return false;
+ }
+ return mBluetoothAdapter.setActiveDevice(device, ACTIVE_DEVICE_ALL);
}
public List<BluetoothDevice> getActiveDevices() {
diff --git a/packages/SettingsLib/src/com/android/settingslib/license/LicenseHtmlGeneratorFromXml.java b/packages/SettingsLib/src/com/android/settingslib/license/LicenseHtmlGeneratorFromXml.java
index 9db4a35c1d78..b4c95e6ee2df 100644
--- a/packages/SettingsLib/src/com/android/settingslib/license/LicenseHtmlGeneratorFromXml.java
+++ b/packages/SettingsLib/src/com/android/settingslib/license/LicenseHtmlGeneratorFromXml.java
@@ -35,8 +35,10 @@ 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.Set;
import java.util.zip.GZIPInputStream;
/**
@@ -84,7 +86,7 @@ class LicenseHtmlGeneratorFromXml {
* "9645f39e9db895a4aa6e02cb57294595". Here "9645f39e9db895a4aa6e02cb57294595" is a MD5 sum
* of the content of packages/services/Telephony/MODULE_LICENSE_APACHE2.
*/
- private final Map<String, String> mFileNameToContentIdMap = new HashMap();
+ private final Map<String, Set<String>> mFileNameToContentIdMap = new HashMap();
/*
* A map from a content id (MD5 sum of file content) to a license file content.
@@ -186,10 +188,10 @@ class LicenseHtmlGeneratorFromXml {
* </licenses>
*/
@VisibleForTesting
- static void parse(InputStreamReader in, Map<String, String> outFileNameToContentIdMap,
+ static void parse(InputStreamReader in, Map<String, Set<String>> outFileNameToContentIdMap,
Map<String, String> outContentIdToFileContentMap)
throws XmlPullParserException, IOException {
- Map<String, String> fileNameToContentIdMap = new HashMap<String, String>();
+ Map<String, Set<String>> fileNameToContentIdMap = new HashMap<String, Set<String>>();
Map<String, String> contentIdToFileContentMap = new HashMap<String, String>();
XmlPullParser parser = Xml.newPullParser();
@@ -206,7 +208,10 @@ class LicenseHtmlGeneratorFromXml {
if (!TextUtils.isEmpty(contentId)) {
String fileName = readText(parser).trim();
if (!TextUtils.isEmpty(fileName)) {
- fileNameToContentIdMap.put(fileName, contentId);
+ Set<String> contentIds =
+ fileNameToContentIdMap.computeIfAbsent(
+ fileName, k -> new HashSet<>());
+ contentIds.add(contentId);
}
}
} else if (TAG_FILE_CONTENT.equals(parser.getName())) {
@@ -224,7 +229,13 @@ class LicenseHtmlGeneratorFromXml {
state = parser.next();
}
- outFileNameToContentIdMap.putAll(fileNameToContentIdMap);
+ for (Map.Entry<String, Set<String>> entry : fileNameToContentIdMap.entrySet()) {
+ outFileNameToContentIdMap.merge(
+ entry.getKey(), entry.getValue(), (s1, s2) -> {
+ s1.addAll(s2);
+ return s1;
+ });
+ }
outContentIdToFileContentMap.putAll(contentIdToFileContentMap);
}
@@ -240,7 +251,7 @@ class LicenseHtmlGeneratorFromXml {
}
@VisibleForTesting
- static void generateHtml(Map<String, String> fileNameToContentIdMap,
+ static void generateHtml(Map<String, Set<String>> fileNameToContentIdMap,
Map<String, String> contentIdToFileContentMap, PrintWriter writer,
String noticeHeader) {
List<String> fileNameList = new ArrayList();
@@ -259,19 +270,20 @@ class LicenseHtmlGeneratorFromXml {
// Prints all the file list with a link to its license file content.
for (String fileName : fileNameList) {
- String contentId = fileNameToContentIdMap.get(fileName);
- // Assigns an id to a newly referred license file content.
- if (!contentIdToOrderMap.containsKey(contentId)) {
- contentIdToOrderMap.put(contentId, count);
-
- // An index in contentIdAndFileNamesList is the order of each element.
- contentIdAndFileNamesList.add(new ContentIdAndFileNames(contentId));
- count++;
- }
+ for (String contentId : fileNameToContentIdMap.get(fileName)) {
+ // Assigns an id to a newly referred license file content.
+ if (!contentIdToOrderMap.containsKey(contentId)) {
+ contentIdToOrderMap.put(contentId, count);
+
+ // An index in contentIdAndFileNamesList is the order of each element.
+ contentIdAndFileNamesList.add(new ContentIdAndFileNames(contentId));
+ count++;
+ }
- int id = contentIdToOrderMap.get(contentId);
- contentIdAndFileNamesList.get(id).mFileNameList.add(fileName);
- writer.format("<li><a href=\"#id%d\">%s</a></li>\n", id, fileName);
+ int id = contentIdToOrderMap.get(contentId);
+ contentIdAndFileNamesList.get(id).mFileNameList.add(fileName);
+ writer.format("<li><a href=\"#id%d\">%s</a></li>\n", id, fileName);
+ }
}
writer.println(HTML_MIDDLE_STRING);
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/license/LicenseHtmlGeneratorFromXmlTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/license/LicenseHtmlGeneratorFromXmlTest.java
index 4b5e9097b3fe..e87461f85762 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/license/LicenseHtmlGeneratorFromXmlTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/license/LicenseHtmlGeneratorFromXmlTest.java
@@ -28,8 +28,11 @@ import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.StringWriter;
+import java.util.Arrays;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.Map;
+import java.util.Set;
@RunWith(RobolectricTestRunner.class)
public class LicenseHtmlGeneratorFromXmlTest {
@@ -68,6 +71,7 @@ public class LicenseHtmlGeneratorFromXmlTest {
private static final String HTML_BODY_STRING =
"<li><a href=\"#id0\">/file0</a></li>\n"
+ + "<li><a href=\"#id1\">/file0</a></li>\n"
+ "<li><a href=\"#id0\">/file1</a></li>\n"
+ "</ul>\n"
+ "</div><!-- table of contents -->\n"
@@ -82,6 +86,15 @@ public class LicenseHtmlGeneratorFromXmlTest {
+ "license content #0\n"
+ "</pre><!-- license-text -->\n"
+ "</td></tr><!-- same-license -->\n"
+ + "<tr id=\"id1\"><td class=\"same-license\">\n"
+ + "<div class=\"label\">Notices for file(s):</div>\n"
+ + "<div class=\"file-list\">\n"
+ + "/file0 <br/>\n"
+ + "</div><!-- file-list -->\n"
+ + "<pre class=\"license-text\">\n"
+ + "license content #1\n"
+ + "</pre><!-- license-text -->\n"
+ + "</td></tr><!-- same-license -->\n"
+ "</table></body></html>\n";
private static final String EXPECTED_HTML_STRING = HTML_HEAD_STRING + HTML_BODY_STRING;
@@ -91,22 +104,22 @@ public class LicenseHtmlGeneratorFromXmlTest {
@Test
public void testParseValidXmlStream() throws XmlPullParserException, IOException {
- Map<String, String> fileNameToContentIdMap = new HashMap<>();
+ Map<String, Set<String>> fileNameToContentIdMap = new HashMap<>();
Map<String, String> contentIdToFileContentMap = new HashMap<>();
LicenseHtmlGeneratorFromXml.parse(
new InputStreamReader(new ByteArrayInputStream(VALILD_XML_STRING.getBytes())),
fileNameToContentIdMap, contentIdToFileContentMap);
assertThat(fileNameToContentIdMap.size()).isEqualTo(2);
- assertThat(fileNameToContentIdMap.get("/file0")).isEqualTo("0");
- assertThat(fileNameToContentIdMap.get("/file1")).isEqualTo("0");
+ assertThat(fileNameToContentIdMap.get("/file0")).containsExactly("0");
+ assertThat(fileNameToContentIdMap.get("/file1")).containsExactly("0");
assertThat(contentIdToFileContentMap.size()).isEqualTo(1);
assertThat(contentIdToFileContentMap.get("0")).isEqualTo("license content #0");
}
@Test(expected = XmlPullParserException.class)
public void testParseInvalidXmlStream() throws XmlPullParserException, IOException {
- Map<String, String> fileNameToContentIdMap = new HashMap<>();
+ Map<String, Set<String>> fileNameToContentIdMap = new HashMap<>();
Map<String, String> contentIdToFileContentMap = new HashMap<>();
LicenseHtmlGeneratorFromXml.parse(
@@ -116,12 +129,13 @@ public class LicenseHtmlGeneratorFromXmlTest {
@Test
public void testGenerateHtml() {
- Map<String, String> fileNameToContentIdMap = new HashMap<>();
+ Map<String, Set<String>> fileNameToContentIdMap = new HashMap<>();
Map<String, String> contentIdToFileContentMap = new HashMap<>();
- fileNameToContentIdMap.put("/file0", "0");
- fileNameToContentIdMap.put("/file1", "0");
+ fileNameToContentIdMap.put("/file0", new HashSet<String>(Arrays.asList("0", "1")));
+ fileNameToContentIdMap.put("/file1", new HashSet<String>(Arrays.asList("0")));
contentIdToFileContentMap.put("0", "license content #0");
+ contentIdToFileContentMap.put("1", "license content #1");
StringWriter output = new StringWriter();
LicenseHtmlGeneratorFromXml.generateHtml(
@@ -131,12 +145,13 @@ public class LicenseHtmlGeneratorFromXmlTest {
@Test
public void testGenerateHtmlWithCustomHeading() {
- Map<String, String> fileNameToContentIdMap = new HashMap<>();
+ Map<String, Set<String>> fileNameToContentIdMap = new HashMap<>();
Map<String, String> contentIdToFileContentMap = new HashMap<>();
- fileNameToContentIdMap.put("/file0", "0");
- fileNameToContentIdMap.put("/file1", "0");
+ fileNameToContentIdMap.put("/file0", new HashSet<String>(Arrays.asList("0", "1")));
+ fileNameToContentIdMap.put("/file1", new HashSet<String>(Arrays.asList("0")));
contentIdToFileContentMap.put("0", "license content #0");
+ contentIdToFileContentMap.put("1", "license content #1");
StringWriter output = new StringWriter();
LicenseHtmlGeneratorFromXml.generateHtml(
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 149eaf47b97d..139a8c3f7411 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -644,7 +644,7 @@
<activity android:name=".controls.management.ControlsProviderSelectorActivity"
android:label="Controls Providers"
- android:theme="@style/Theme.SystemUI"
+ android:theme="@style/Theme.ControlsManagement"
android:exported="true"
android:showForAllUsers="true"
android:excludeFromRecents="true"
@@ -654,7 +654,7 @@
<activity android:name=".controls.management.ControlsFavoritingActivity"
android:parentActivityName=".controls.management.ControlsProviderSelectorActivity"
- android:theme="@style/Theme.SystemUI"
+ android:theme="@style/Theme.ControlsManagement"
android:excludeFromRecents="true"
android:showForAllUsers="true"
android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation|keyboard|keyboardHidden"
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java
index 6518924ca0c2..01811e9cdced 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java
@@ -14,9 +14,6 @@
package com.android.systemui.plugins.qs;
-import static java.lang.annotation.RetentionPolicy.SOURCE;
-
-import android.annotation.IntDef;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.metrics.LogMaker;
@@ -28,7 +25,6 @@ import com.android.systemui.plugins.qs.QSTile.Callback;
import com.android.systemui.plugins.qs.QSTile.Icon;
import com.android.systemui.plugins.qs.QSTile.State;
-import java.lang.annotation.Retention;
import java.util.Objects;
import java.util.function.Supplier;
@@ -84,17 +80,6 @@ public interface QSTile {
return logMaker;
}
- @Retention(SOURCE)
- @IntDef({COLOR_TILE_ACCENT, COLOR_TILE_RED, COLOR_TILE_BLUE, COLOR_TILE_YELLOW,
- COLOR_TILE_GREEN})
- @interface ColorTile {}
- int COLOR_TILE_ACCENT = 0;
- int COLOR_TILE_RED = 1;
- int COLOR_TILE_BLUE = 2;
- int COLOR_TILE_YELLOW = 3;
- int COLOR_TILE_GREEN = 4;
- default void setColor(@ColorTile int color) {}
-
@ProvidesInterface(version = Callback.VERSION)
public interface Callback {
public static final int VERSION = 1;
@@ -141,7 +126,6 @@ public interface QSTile {
public SlashState slash;
public boolean handlesLongClick = true;
public boolean showRippleEffect = true;
- public int colorActive = -1;
public boolean copyTo(State other) {
if (other == null) throw new IllegalArgumentException();
@@ -161,8 +145,7 @@ public interface QSTile {
|| !Objects.equals(other.dualTarget, dualTarget)
|| !Objects.equals(other.slash, slash)
|| !Objects.equals(other.handlesLongClick, handlesLongClick)
- || !Objects.equals(other.showRippleEffect, showRippleEffect)
- || !Objects.equals(other.colorActive, colorActive);
+ || !Objects.equals(other.showRippleEffect, showRippleEffect);
other.icon = icon;
other.iconSupplier = iconSupplier;
other.label = label;
@@ -177,7 +160,6 @@ public interface QSTile {
other.slash = slash != null ? slash.copy() : null;
other.handlesLongClick = handlesLongClick;
other.showRippleEffect = showRippleEffect;
- other.colorActive = colorActive;
return changed;
}
diff --git a/packages/SystemUI/proguard.flags b/packages/SystemUI/proguard.flags
index 3e74970ee725..2a2ba1b0ccaa 100644
--- a/packages/SystemUI/proguard.flags
+++ b/packages/SystemUI/proguard.flags
@@ -16,6 +16,7 @@
-keep class com.android.systemui.statusbar.tv.TvStatusBar
-keep class com.android.systemui.car.CarSystemUIFactory
-keep class com.android.systemui.SystemUIFactory
+-keep class com.android.systemui.tv.TvSystemUIFactory
-keep class * extends com.android.systemui.SystemUI
-keep class * implements com.android.systemui.SystemUI$Injector
diff --git a/packages/SystemUI/res-keyguard/layout/controls_management.xml b/packages/SystemUI/res-keyguard/layout/controls_management.xml
new file mode 100644
index 000000000000..8330258e2456
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/layout/controls_management.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:gravity="center_horizontal"
+ android:paddingTop="@dimen/controls_management_top_padding"
+ android:paddingStart="@dimen/controls_management_side_padding"
+ android:paddingEnd="@dimen/controls_management_side_padding" >
+
+ <TextView
+ android:id="@+id/title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textAppearance="?android:attr/textAppearanceLarge"
+ android:textSize="@dimen/controls_title_size"
+ android:textAlignment="center" />
+
+ <TextView
+ android:id="@+id/subtitle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/controls_management_titles_margin"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textAlignment="center" />
+
+ <androidx.recyclerview.widget.RecyclerView
+ android:id="@+id/list"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/controls_management_list_margin" />
+
+</LinearLayout> \ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/auth_dialog_enterprise.xml b/packages/SystemUI/res/drawable/auth_dialog_enterprise.xml
new file mode 100644
index 000000000000..c547c52a4077
--- /dev/null
+++ b/packages/SystemUI/res/drawable/auth_dialog_enterprise.xml
@@ -0,0 +1,25 @@
+<?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.
+ -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:pathData="M20,6h-4L16,4c0,-1.11 -0.89,-2 -2,-2h-4c-1.11,0 -2,0.89 -2,2v2L4,6c-1.11,0 -1.99,0.89 -1.99,2L2,19c0,1.11 0.89,2 2,2h16c1.11,0 2,-0.89 2,-2L22,8c0,-1.11 -0.89,-2 -2,-2zM12,15c-1.1,0 -2,-0.9 -2,-2s0.9,-2 2,-2 2,0.9 2,2 -0.9,2 -2,2zM14,6h-4L10,4h4v2z"
+ android:fillColor="?android:attr/colorAccent"/>
+</vector> \ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/notif_dungeon_bg_gradient.xml b/packages/SystemUI/res/drawable/notif_dungeon_bg_gradient.xml
new file mode 100644
index 000000000000..e456e2965d21
--- /dev/null
+++ b/packages/SystemUI/res/drawable/notif_dungeon_bg_gradient.xml
@@ -0,0 +1,25 @@
+<?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.
+ -->
+<shape
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <gradient
+ android:angle="90"
+ android:startColor="#ff000000"
+ android:endColor="#00000000"
+ android:type="linear" />
+</shape>
diff --git a/packages/SystemUI/res/layout-land/auth_credential_pattern_view.xml b/packages/SystemUI/res/layout-land/auth_credential_pattern_view.xml
index c3fa39e5a87f..c40e47df9a55 100644
--- a/packages/SystemUI/res/layout-land/auth_credential_pattern_view.xml
+++ b/packages/SystemUI/res/layout-land/auth_credential_pattern_view.xml
@@ -34,20 +34,15 @@
android:layout_weight="1"/>
<ImageView
- android:layout_width="32dp"
- android:layout_height="32dp"
- android:background="@drawable/auth_dialog_lock"/>
+ android:id="@+id/icon"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"/>
<TextView
android:id="@+id/title"
- android:fontFamily="@*android:string/config_headlineFontFamilyMedium"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginHorizontal="24dp"
- android:layout_marginTop="12dp"
- android:textSize="20sp"
- android:gravity="center"
- android:textColor="?android:attr/textColorPrimary"/>
+ style="@style/TextAppearance.AuthCredential.Title"/>
<TextView
android:id="@+id/subtitle"
@@ -63,17 +58,41 @@
android:id="@+id/description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginHorizontal="24dp"
- android:layout_marginTop="8dp"
- android:gravity="center"
- android:textSize="16sp"
- android:textColor="?android:attr/textColorPrimary"/>
+ style="@style/TextAppearance.AuthCredential.Description"/>
<Space
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_weight="1"/>
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:gravity="center"
+ android:paddingLeft="0dp"
+ android:paddingRight="0dp"
+ android:paddingTop="0dp"
+ android:paddingBottom="16dp"
+ android:clipToPadding="false">
+
+ <FrameLayout
+ android:layout_width="wrap_content"
+ android:layout_height="0dp"
+ android:layout_weight="1"
+ style="@style/LockPatternContainerStyle">
+
+ <com.android.internal.widget.LockPatternView
+ android:id="@+id/lockPattern"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_gravity="center"
+ style="@style/LockPatternStyleBiometricPrompt"/>
+
+ </FrameLayout>
+
<TextView
android:id="@+id/error"
android:layout_width="match_parent"
@@ -90,24 +109,4 @@
</LinearLayout>
- <LinearLayout
- android:layout_width="0dp"
- android:layout_height="match_parent"
- android:layout_weight="1"
- android:orientation="vertical"
- android:gravity="center">
-
- <com.android.internal.widget.LockPatternView
- android:id="@+id/lockPattern"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginLeft="40dp"
- android:layout_marginRight="40dp"
- android:layout_gravity="center"
- android:clipChildren="false"
- android:clipToPadding="false"
- style="@style/LockPatternStyleBiometricPrompt"/>
-
- </LinearLayout>
-
</com.android.systemui.biometrics.AuthCredentialPatternView> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/app_item.xml b/packages/SystemUI/res/layout/app_item.xml
deleted file mode 100644
index 83e788731442..000000000000
--- a/packages/SystemUI/res/layout/app_item.xml
+++ /dev/null
@@ -1,70 +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:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:background="?android:attr/selectableItemBackground"
- android:gravity="center_vertical"
- android:minHeight="?android:attr/listPreferredItemHeightSmall"
- android:paddingStart="?android:attr/listPreferredItemPaddingStart"
- android:paddingEnd="?android:attr/listPreferredItemPaddingEnd">
-
- <LinearLayout
- android:id="@+id/icon_frame"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:gravity="start|center_vertical"
- android:minWidth="56dp"
- android:orientation="horizontal"
- android:paddingEnd="8dp"
- android:paddingTop="4dp"
- android:paddingBottom="4dp">
- <ImageView
- android:id="@android:id/icon"
- android:layout_width="@dimen/app_icon_size"
- android:layout_height="@dimen/app_icon_size"/>
- </LinearLayout>
-
- <LinearLayout
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:orientation="vertical"
- android:paddingTop="16dp"
- android:paddingBottom="16dp">
-
- <TextView
- android:id="@android:id/title"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:ellipsize="marquee"
- android:fadingEdge="horizontal"
- android:singleLine="true"
- android:textAppearance="?android:attr/textAppearanceListItem"/>
-
- </LinearLayout>
-
- <LinearLayout
- android:id="@android:id/widget_frame"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:gravity="center_vertical|end"
- android:minWidth="64dp"
- android:orientation="vertical"/>
-
-</LinearLayout> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/auth_credential_password_view.xml b/packages/SystemUI/res/layout/auth_credential_password_view.xml
index 4aed0333e9ca..a1c593fa455c 100644
--- a/packages/SystemUI/res/layout/auth_credential_password_view.xml
+++ b/packages/SystemUI/res/layout/auth_credential_password_view.xml
@@ -28,20 +28,15 @@
android:layout_weight="1"/>
<ImageView
- android:layout_width="32dp"
- android:layout_height="32dp"
- android:background="@drawable/auth_dialog_lock"/>
+ android:id="@+id/icon"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"/>
<TextView
android:id="@+id/title"
- android:fontFamily="@*android:string/config_headlineFontFamilyMedium"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginHorizontal="24dp"
- android:layout_marginTop="12dp"
- android:textSize="20sp"
- android:gravity="center"
- android:textColor="?android:attr/textColorPrimary"/>
+ style="@style/TextAppearance.AuthCredential.Title"/>
<TextView
android:id="@+id/subtitle"
@@ -57,11 +52,7 @@
android:id="@+id/description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginHorizontal="24dp"
- android:layout_marginTop="8dp"
- android:gravity="center"
- android:textSize="16sp"
- android:textColor="?android:attr/textColorPrimary"/>
+ style="@style/TextAppearance.AuthCredential.Description"/>
<Space
android:layout_width="0dp"
@@ -79,19 +70,14 @@
<EditText
android:id="@+id/lockPassword"
- android:layout_marginBottom="20dp"
- android:layout_marginLeft="100dp"
- android:layout_marginRight="100dp"
android:layout_width="208dp"
android:layout_height="wrap_content"
- android:layout_gravity="center"
+ android:layout_gravity="center_horizontal"
android:gravity="center"
android:inputType="textPassword"
android:maxLength="500"
- android:textSize="16sp"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:imeOptions="flagForceAscii"
- style="@style/LockPatternStyleBiometricPrompt"/>
+ android:imeOptions="actionNext|flagNoFullscreen|flagForceAscii"
+ style="@style/TextAppearance.AuthCredential.PasswordEntry"/>
<Space
android:layout_width="0dp"
diff --git a/packages/SystemUI/res/layout/auth_credential_pattern_view.xml b/packages/SystemUI/res/layout/auth_credential_pattern_view.xml
index c9edcd606277..eda5ecbf7f8c 100644
--- a/packages/SystemUI/res/layout/auth_credential_pattern_view.xml
+++ b/packages/SystemUI/res/layout/auth_credential_pattern_view.xml
@@ -28,20 +28,15 @@
android:layout_weight="1"/>
<ImageView
- android:layout_width="32dp"
- android:layout_height="32dp"
- android:background="@drawable/auth_dialog_lock"/>
+ android:id="@+id/icon"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"/>
<TextView
android:id="@+id/title"
- android:fontFamily="@*android:string/config_headlineFontFamilyMedium"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginHorizontal="24dp"
- android:layout_marginTop="12dp"
- android:textSize="20sp"
- android:gravity="center"
- android:textColor="?android:attr/textColorPrimary"/>
+ style="@style/TextAppearance.AuthCredential.Title"/>
<TextView
android:id="@+id/subtitle"
@@ -57,37 +52,49 @@
android:id="@+id/description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginHorizontal="24dp"
- android:layout_marginTop="8dp"
- android:gravity="center"
- android:textSize="16sp"
- android:textColor="?android:attr/textColorPrimary"/>
+ style="@style/TextAppearance.AuthCredential.Description"/>
<Space
android:layout_width="0dp"
android:layout_height="0dp"
- android:layout_weight="3"/>
+ android:layout_weight="1"/>
- <TextView
- android:id="@+id/error"
+ <LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginHorizontal="24dp"
- android:textSize="16sp"
+ android:orientation="vertical"
android:gravity="center"
- android:textColor="?android:attr/colorError"/>
+ android:paddingLeft="0dp"
+ android:paddingRight="0dp"
+ android:paddingTop="0dp"
+ android:paddingBottom="16dp"
+ android:clipToPadding="false">
- <com.android.internal.widget.LockPatternView
- android:id="@+id/lockPattern"
- android:layout_marginBottom="20dp"
- android:layout_marginLeft="40dp"
- android:layout_marginRight="40dp"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:clipChildren="false"
- android:clipToPadding="false"
- style="@style/LockPatternStyleBiometricPrompt"/>
+ <FrameLayout
+ android:layout_width="wrap_content"
+ android:layout_height="0dp"
+ android:layout_weight="1"
+ style="@style/LockPatternContainerStyle">
+
+ <com.android.internal.widget.LockPatternView
+ android:id="@+id/lockPattern"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_gravity="center"
+ style="@style/LockPatternStyleBiometricPrompt"/>
+
+ </FrameLayout>
+
+ <TextView
+ android:id="@+id/error"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginHorizontal="24dp"
+ android:textSize="16sp"
+ android:gravity="center"
+ android:textColor="?android:attr/colorError"/>
+
+ </LinearLayout>
<Space
android:layout_width="0dp"
diff --git a/packages/SystemUI/res/layout/control_item.xml b/packages/SystemUI/res/layout/control_item.xml
deleted file mode 100644
index 85701aaca41d..000000000000
--- a/packages/SystemUI/res/layout/control_item.xml
+++ /dev/null
@@ -1,72 +0,0 @@
-<?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.
--->
-<androidx.constraintlayout.widget.ConstraintLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto"
- android:layout_width="match_parent"
- android:layout_height="100dp"
- android:padding="15dp"
- android:clickable="true"
- android:focusable="true">
-
- <ImageView
- android:id="@+id/icon"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toTopOf="parent" />
-
- <TextView
- android:id="@+id/status"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textSize="12sp"
- android:textColor="?android:attr/textColorPrimary"
- android:fontFamily="@*android:string/config_bodyFontFamily"
- android:paddingLeft="3dp"
- app:layout_constraintBottom_toBottomOf="@+id/icon"
- app:layout_constraintStart_toEndOf="@+id/icon" />
-
- <TextView
- android:id="@+id/title"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textSize="18sp"
- android:textColor="?android:attr/textColorPrimary"
- android:fontFamily="@*android:string/config_headlineFontFamily"
- app:layout_constraintBottom_toTopOf="@+id/subtitle"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toBottomOf="@+id/icon" />
-
- <TextView
- android:id="@+id/subtitle"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textSize="16sp"
- android:textColor="?android:attr/textColorSecondary"
- android:fontFamily="@*android:string/config_headlineFontFamily"
- app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintStart_toStartOf="parent" />
-
- <CheckBox
- android:id="@+id/favorite"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintTop_toTopOf="parent"
- app:layout_constraintBottom_toBottomOf="parent"/>
-</androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/packages/SystemUI/res/layout/controls_app_item.xml b/packages/SystemUI/res/layout/controls_app_item.xml
new file mode 100644
index 000000000000..d54cd6db867a
--- /dev/null
+++ b/packages/SystemUI/res/layout/controls_app_item.xml
@@ -0,0 +1,87 @@
+<?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.
+-->
+<FrameLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:background="?android:attr/selectableItemBackground">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="start|top"
+ android:gravity="center_vertical"
+ android:minHeight="?android:attr/listPreferredItemHeightSmall"
+ android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+ android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
+ android:layout_marginBottom="@dimen/controls_app_bottom_margin">
+
+ <FrameLayout
+ android:id="@+id/icon_frame"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:gravity="start|center_vertical"
+ android:minWidth="56dp"
+ android:orientation="horizontal"
+ android:paddingTop="@dimen/controls_app_icon_frame_top_padding"
+ android:paddingBottom="@dimen/controls_app_icon_frame_top_padding"
+ android:paddingEnd="@dimen/controls_app_icon_frame_side_padding"
+ android:paddingStart="@dimen/controls_app_icon_frame_side_padding" >
+
+ <ImageView
+ android:id="@android:id/icon"
+ android:layout_width="@dimen/controls_app_icon_size"
+ android:layout_height="@dimen/controls_app_icon_size" />
+ </FrameLayout>
+
+ <LinearLayout
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:orientation="vertical"
+ android:paddingTop="@dimen/controls_app_text_padding"
+ android:paddingBottom="@dimen/controls_app_text_padding">
+
+ <TextView
+ android:id="@android:id/title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:ellipsize="end"
+ android:fadingEdge="horizontal"
+ android:singleLine="true"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textColor="?android:attr/textColorPrimary"/>
+
+ <TextView
+ android:id="@+id/favorites"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:ellipsize="end"
+ android:fadingEdge="horizontal"
+ android:singleLine="true"
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+
+ </LinearLayout>
+
+ </LinearLayout>
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/controls_app_divider_height"
+ android:layout_gravity="center_horizontal|bottom"
+ android:layout_marginStart="@dimen/controls_app_divider_side_margin"
+ android:layout_marginEnd="@dimen/controls_app_divider_side_margin"
+ android:background="?android:attr/listDivider" />
+</FrameLayout> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/controls_base_item.xml b/packages/SystemUI/res/layout/controls_base_item.xml
index cd7ec5eb5c81..68c824698b2d 100644
--- a/packages/SystemUI/res/layout/controls_base_item.xml
+++ b/packages/SystemUI/res/layout/controls_base_item.xml
@@ -23,8 +23,8 @@
android:padding="@dimen/control_padding"
android:clickable="true"
android:focusable="true"
- android:layout_marginLeft="2dp"
- android:layout_marginRight="2dp"
+ android:layout_marginLeft="@dimen/control_base_item_margin"
+ android:layout_marginRight="@dimen/control_base_item_margin"
android:background="@drawable/control_background">
<ImageView
@@ -38,10 +38,8 @@
android:id="@+id/status"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:textSize="@dimen/control_status_normal"
- android:textColor="?android:attr/textColorPrimary"
- android:fontFamily="@*android:string/config_bodyFontFamily"
- android:paddingLeft="3dp"
+ android:textAppearance="@style/TextAppearance.Control.Status"
+ android:paddingStart="@dimen/control_status_padding"
app:layout_constraintBottom_toBottomOf="@+id/icon"
app:layout_constraintStart_toEndOf="@+id/icon" />
@@ -49,10 +47,8 @@
android:id="@+id/status_extra"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:textSize="@dimen/control_status_normal"
- android:textColor="?android:attr/textColorPrimary"
- android:fontFamily="@*android:string/config_bodyFontFamily"
- android:paddingLeft="3dp"
+ android:textAppearance="@style/TextAppearance.Control.Status"
+ android:paddingStart="@dimen/control_status_padding"
app:layout_constraintBottom_toBottomOf="@+id/icon"
app:layout_constraintStart_toEndOf="@+id/status" />
@@ -60,9 +56,7 @@
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:textSize="14sp"
- android:textColor="?android:attr/textColorPrimary"
- android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textAppearance="@style/TextAppearance.Control.Title"
app:layout_constraintBottom_toTopOf="@+id/subtitle"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/icon" />
@@ -71,9 +65,15 @@
android:id="@+id/subtitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:textSize="12sp"
- android:textColor="?android:attr/textColorSecondary"
- android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textAppearance="@style/TextAppearance.Control.Subtitle"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent" />
+
+ <CheckBox
+ android:id="@+id/favorite"
+ android:visibility="gone"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/packages/SystemUI/res/layout/controls_row.xml b/packages/SystemUI/res/layout/controls_row.xml
index 13a6b36accd3..4cc461a28187 100644
--- a/packages/SystemUI/res/layout/controls_row.xml
+++ b/packages/SystemUI/res/layout/controls_row.xml
@@ -16,7 +16,7 @@
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
- orientation="horizontal"
+ android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/control_spacing" />
diff --git a/packages/SystemUI/res/layout/controls_with_favorites.xml b/packages/SystemUI/res/layout/controls_with_favorites.xml
index 6a3e95d34358..40b2476941c2 100644
--- a/packages/SystemUI/res/layout/controls_with_favorites.xml
+++ b/packages/SystemUI/res/layout/controls_with_favorites.xml
@@ -13,7 +13,7 @@
android:layout_height="wrap_content"
android:singleLine="true"
android:gravity="center"
- android:textSize="25dp"
+ android:textSize="25sp"
android:textColor="@*android:color/foreground_material_dark"
android:fontFamily="@*android:string/config_headlineFontFamily"
app:layout_constraintBottom_toBottomOf="parent"
diff --git a/packages/SystemUI/res/layout/foreground_service_dungeon.xml b/packages/SystemUI/res/layout/foreground_service_dungeon.xml
new file mode 100644
index 000000000000..d4e98e217213
--- /dev/null
+++ b/packages/SystemUI/res/layout/foreground_service_dungeon.xml
@@ -0,0 +1,61 @@
+<!--
+ ~ 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.
+ -->
+
+<com.android.systemui.statusbar.notification.row.ForegroundServiceDungeonView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/foreground_service_dungeon"
+ android:layout_width="@dimen/qs_panel_width"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal|bottom"
+ android:visibility="visible"
+>
+ <LinearLayout
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:orientation="vertical"
+ android:gravity="bottom"
+ android:visibility="visible"
+ android:background="@drawable/notif_dungeon_bg_gradient"
+ >
+
+ <!-- divider view -->
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1dp"
+ android:background="@color/GM2_grey_200"
+ android:visibility="visible"
+ />
+
+ <TextView
+ android:id="@+id/dungeon_title"
+ android:layout_height="48dp"
+ android:layout_width="match_parent"
+ android:padding="8dp"
+ android:text="Apps active in background"
+ android:textColor="@color/GM2_grey_200"
+ />
+
+ <!-- List containing the actual foreground service notifications -->
+ <LinearLayout
+ android:id="@+id/entry_list"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="bottom"
+ android:orientation="vertical" >
+ </LinearLayout>
+
+ </LinearLayout>
+</com.android.systemui.statusbar.notification.row.ForegroundServiceDungeonView>
diff --git a/packages/SystemUI/res/layout/foreground_service_dungeon_row.xml b/packages/SystemUI/res/layout/foreground_service_dungeon_row.xml
new file mode 100644
index 000000000000..a6f1638a1d89
--- /dev/null
+++ b/packages/SystemUI/res/layout/foreground_service_dungeon_row.xml
@@ -0,0 +1,43 @@
+<!--
+ ~ 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.
+ -->
+
+<com.android.systemui.statusbar.notification.row.DungeonRow
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/foreground_service_dungeon_row"
+ android:layout_width="match_parent"
+ android:layout_height="48dp"
+ android:padding="8dp"
+ android:clickable="true"
+ android:orientation="horizontal" >
+
+ <com.android.systemui.statusbar.StatusBarIconView
+ android:id="@+id/icon"
+ android:layout_width="24dp"
+ android:layout_height="24dp"
+ android:padding="4dp" />
+
+ <TextView
+ android:id="@+id/app_name"
+ android:layout_width="0dp"
+ android:layout_weight="1"
+ android:layout_height="wrap_content"
+ android:paddingStart="4dp"
+ android:gravity="center_vertical"
+ android:layout_gravity="center_vertical"
+ android:textColor="@color/GM2_grey_200"
+ />
+
+</com.android.systemui.statusbar.notification.row.DungeonRow>
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index 823685e15807..478a93de1427 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -964,4 +964,5 @@
<string name="magnification_overlay_title" msgid="6584179429612427958">"Vergrotingoorleggervenster"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Vergrotingvenster"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Vergrotingvensterkontroles"</string>
+ <string name="quick_controls_title" msgid="525285759614231333">"Vinnige kontroles"</string>
</resources>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index c3248249ebb6..08a655a67faa 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -964,4 +964,5 @@
<string name="magnification_overlay_title" msgid="6584179429612427958">"የማጉያ ንብርብር መስኮት"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"የማጉያ መስኮት"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"የማጉያ መስኮት መቆጣጠሪያዎች"</string>
+ <string name="quick_controls_title" msgid="525285759614231333">"ፈጣን መቆጣጠሪያዎች"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 113d705d7f31..6ceb6cdca3bc 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -984,4 +984,6 @@
<string name="magnification_overlay_title" msgid="6584179429612427958">"نافذة تراكب التكبير"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"نافذة التكبير"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"عناصر التحكم في نافذة التكبير"</string>
+ <!-- no translation found for quick_controls_title (525285759614231333) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml
index 975d639c2ea4..ffefb48438c5 100644
--- a/packages/SystemUI/res/values-as/strings.xml
+++ b/packages/SystemUI/res/values-as/strings.xml
@@ -964,4 +964,6 @@
<string name="magnification_overlay_title" msgid="6584179429612427958">"বিবৰ্ধন অ’ভাৰলে’ৰ ৱিণ্ড’"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"বিবৰ্ধন ৱিণ্ড’"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"বিবৰ্ধন ৱিণ্ড’ৰ নিয়ন্ত্ৰণসমূহ"</string>
+ <!-- no translation found for quick_controls_title (525285759614231333) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index d98d939da47a..2caffffc7ca1 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -964,4 +964,6 @@
<string name="magnification_overlay_title" msgid="6584179429612427958">"Böyütmə Üst-üstə Düşən Pəncərəsi"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Böyütmə Pəncərəsi"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Böyütmə Pəncərəsi Kontrolları"</string>
+ <!-- no translation found for quick_controls_title (525285759614231333) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index ff03bb9726ae..aaa35ffd7058 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -969,4 +969,5 @@
<string name="magnification_overlay_title" msgid="6584179429612427958">"Preklopni prozor za uvećanje"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Prozor za uvećanje"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Kontrole prozora za uvećanje"</string>
+ <string name="quick_controls_title" msgid="525285759614231333">"Brze kontrole"</string>
</resources>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index 1ebbb5ea100c..619fd1c79a26 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -976,4 +976,6 @@
<string name="magnification_overlay_title" msgid="6584179429612427958">"Акно-накладка з павелічэннем"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Акно павелічэння"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Налады акна павелічэння"</string>
+ <!-- no translation found for quick_controls_title (525285759614231333) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index 5cfea60f901f..99c1fecef526 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -964,4 +964,5 @@
<string name="magnification_overlay_title" msgid="6584179429612427958">"Прозорец с наслагване за ниво на мащаба"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Прозорец за ниво на мащаба"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Контроли за прозореца за ниво на мащаба"</string>
+ <string name="quick_controls_title" msgid="525285759614231333">"Бързи контроли"</string>
</resources>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index f1e49ce57ce8..1327cf40fa55 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -964,4 +964,6 @@
<string name="magnification_overlay_title" msgid="6584179429612427958">"ওভারলে উইন্ডো বড় করে দেখা"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"উইন্ডো বড় করে দেখা"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"উইন্ডো কন্ট্রোল বড় করে দেখা"</string>
+ <!-- no translation found for quick_controls_title (525285759614231333) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index cabe87f4a0b0..7bce70a92485 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -971,4 +971,5 @@
<string name="magnification_overlay_title" msgid="6584179429612427958">"Preklopni prozor za uvećavanje"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Prozor za uvećavanje"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Kontrole prozora za uvećavanje"</string>
+ <string name="quick_controls_title" msgid="525285759614231333">"Brze kontrole"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 3e257952050a..5597f51066e2 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -964,4 +964,5 @@
<string name="magnification_overlay_title" msgid="6584179429612427958">"Finestra superposada d\'ampliació"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Finestra d\'ampliació"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Finestra de controls d\'ampliació"</string>
+ <string name="quick_controls_title" msgid="525285759614231333">"Controls ràpids"</string>
</resources>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 3c85880eaaf8..a608c5b77735 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -974,4 +974,5 @@
<string name="magnification_overlay_title" msgid="6584179429612427958">"Překryvné zvětšovací okno"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Zvětšovací okno"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Ovládací prvky zvětšovacího okna"</string>
+ <string name="quick_controls_title" msgid="525285759614231333">"Rychlé ovládací prvky"</string>
</resources>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index f2ffdaac0e37..9fb778354bda 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -964,4 +964,5 @@
<string name="magnification_overlay_title" msgid="6584179429612427958">"Vindue med overlejret forstørrelse"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Vindue med forstørrelse"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Vindue med forstørrelsesstyring"</string>
+ <string name="quick_controls_title" msgid="525285759614231333">"Hurtig betjening"</string>
</resources>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 58caef2b46bb..9d83e9cf55e7 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -968,4 +968,6 @@
<string name="magnification_overlay_title" msgid="6584179429612427958">"Overlay-Vergrößerungsfenster"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Vergrößerungsfenster"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Einstellungen für Vergrößerungsfenster"</string>
+ <!-- no translation found for quick_controls_title (525285759614231333) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index d3686c834882..b94d10c2a741 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -964,4 +964,5 @@
<string name="magnification_overlay_title" msgid="6584179429612427958">"Παράθυρο επικάλυψης μεγέθυνσης"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Παράθυρο μεγέθυνσης"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Στοιχεία ελέγχου παραθύρου μεγέθυνσης"</string>
+ <string name="quick_controls_title" msgid="525285759614231333">"Στοιχεία γρήγορου ελέγχου"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index 4f61daa2bf18..df2496951be7 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -964,4 +964,5 @@
<string name="magnification_overlay_title" msgid="6584179429612427958">"Magnification overlay window"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Magnification window"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Magnification window controls"</string>
+ <string name="quick_controls_title" msgid="525285759614231333">"Quick controls"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml
index 34a2f1975d75..2d087c92b2d6 100644
--- a/packages/SystemUI/res/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings.xml
@@ -964,4 +964,5 @@
<string name="magnification_overlay_title" msgid="6584179429612427958">"Magnification overlay window"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Magnification window"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Magnification window controls"</string>
+ <string name="quick_controls_title" msgid="525285759614231333">"Quick controls"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 4f61daa2bf18..df2496951be7 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -964,4 +964,5 @@
<string name="magnification_overlay_title" msgid="6584179429612427958">"Magnification overlay window"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Magnification window"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Magnification window controls"</string>
+ <string name="quick_controls_title" msgid="525285759614231333">"Quick controls"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index 4f61daa2bf18..df2496951be7 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -964,4 +964,5 @@
<string name="magnification_overlay_title" msgid="6584179429612427958">"Magnification overlay window"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Magnification window"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Magnification window controls"</string>
+ <string name="quick_controls_title" msgid="525285759614231333">"Quick controls"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml
index 2bb51311aa0a..9d4e1622ede4 100644
--- a/packages/SystemUI/res/values-en-rXC/strings.xml
+++ b/packages/SystemUI/res/values-en-rXC/strings.xml
@@ -964,4 +964,5 @@
<string name="magnification_overlay_title" msgid="6584179429612427958">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‏‏‎‏‎‏‏‏‏‏‏‎‏‏‎‏‎‎‎‏‎‎‏‏‏‎‏‎‎‎‎‏‏‏‎‏‏‏‏‎‏‏‏‎‎‏‏‎‏‎‏‎‏‏‎‏‏‎‎Magnification Overlay Window‎‏‎‎‏‎"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‏‏‏‎‎‎‎‎‎‎‎‎‎‏‏‎‎‎‎‏‎‏‎‏‏‏‎‏‎‏‎‎‎‎‎‎‏‏‏‎‎‎‏‏‎‏‎‎‏‎‏‏‎‏‏‏‎‏‎Magnification Window‎‏‎‎‏‎"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‎‎‏‏‎‏‏‏‎‏‏‏‎‎‎‏‏‏‏‏‎‏‎‏‏‏‏‎‎‎‎‏‎‎‏‎‎‏‎‏‎‎‎‎‎‏‏‏‏‏‎‏‏‏‏‏‏‏‎Magnification Window Controls‎‏‎‎‏‎"</string>
+ <string name="quick_controls_title" msgid="525285759614231333">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‏‏‏‏‎‏‎‎‏‎‏‎‎‎‏‏‎‎‎‎‏‎‎‏‏‏‎‏‏‎‎‎‎‎‏‏‎‏‏‎‎‎‎‎‏‎‏‎‎‎‏‏‎‎‏‎‎‏‎‏‎Quick Controls‎‏‎‎‏‎"</string>
</resources>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index e2bf6efa538e..33689a1ac7d2 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -964,4 +964,5 @@
<string name="magnification_overlay_title" msgid="6584179429612427958">"Ventana superpuesta de ampliación"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Ventana de ampliación"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Controles de ampliación de la ventana"</string>
+ <string name="quick_controls_title" msgid="525285759614231333">"Controles rápidos"</string>
</resources>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index 40d7fe3bdf25..458df31e2231 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -964,4 +964,5 @@
<string name="magnification_overlay_title" msgid="6584179429612427958">"Ventana de superposición de ampliación"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Ventana de ampliación"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Ventana de controles de ampliación"</string>
+ <string name="quick_controls_title" msgid="525285759614231333">"Controles rápidos"</string>
</resources>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index d8f546ce48d4..4729a0d6787a 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -964,4 +964,6 @@
<string name="magnification_overlay_title" msgid="6584179429612427958">"Suurendamisakna ülekate"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Suurendamisaken"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Suurendamisakna juhtelemendid"</string>
+ <!-- no translation found for quick_controls_title (525285759614231333) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index 9dceb5fe3f05..470a410aa88d 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -964,4 +964,5 @@
<string name="magnification_overlay_title" msgid="6584179429612427958">"Lupa-leiho gainjarria"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Lupa-leihoa"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Lupa-leihoaren aukerak"</string>
+ <string name="quick_controls_title" msgid="525285759614231333">"Kontrol bizkorrak"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index d27b420c0e9c..ae85a260eaf3 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -964,4 +964,6 @@
<string name="magnification_overlay_title" msgid="6584179429612427958">"پنجره همپوشانی بزرگ‌نمایی"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"پنجره بزرگ‌نمایی"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"کنترل‌های پنجره بزرگ‌نمایی"</string>
+ <!-- no translation found for quick_controls_title (525285759614231333) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index cf01efd933d0..da22e1c502e5 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -964,4 +964,5 @@
<string name="magnification_overlay_title" msgid="6584179429612427958">"Suurennuksen peittoikkuna"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Suurennusikkuna"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Suurennusikkunan ohjaimet"</string>
+ <string name="quick_controls_title" msgid="525285759614231333">"Pikasäätimet"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 5f7a358239c7..d5d3f56286cb 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -964,4 +964,6 @@
<string name="magnification_overlay_title" msgid="6584179429612427958">"Fenêtre d\'agrandissement superposée"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Fenêtre d\'agrandissement"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Commandes pour la fenêtre d\'agrandissement"</string>
+ <!-- no translation found for quick_controls_title (525285759614231333) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 3c12f668d2b9..5c5d353e4103 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -964,4 +964,6 @@
<string name="magnification_overlay_title" msgid="6584179429612427958">"Fenêtre de superposition de l\'agrandissement"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Fenêtre d\'agrandissement"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Fenêtre des commandes d\'agrandissement"</string>
+ <!-- no translation found for quick_controls_title (525285759614231333) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index 0c444e48aee3..2c0eef659a60 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -964,4 +964,6 @@
<string name="magnification_overlay_title" msgid="6584179429612427958">"Ampliación da ventá de superposición"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Ventá de superposición"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Controis de ampliación da ventá"</string>
+ <!-- no translation found for quick_controls_title (525285759614231333) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index 9dde523d9a89..df4254ca4e0f 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -964,4 +964,6 @@
<string name="magnification_overlay_title" msgid="6584179429612427958">"વિસ્તૃતીકરણ ઓવરલે વિંડો"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"વિસ્તૃતીકરણ વિંડો"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"વિસ્તૃતીકરણ વિંડોના નિયંત્રણો"</string>
+ <!-- no translation found for quick_controls_title (525285759614231333) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 5522605cd0f4..b62a45eb7747 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -390,8 +390,8 @@
<string name="quick_settings_dark_mode_secondary_label_battery_saver" msgid="4990712734503013251">"बैटरी सेवर"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at_sunset" msgid="6017379738102015710">"शाम को चालू होगा"</string>
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"सुबह तक चालू रहेगी"</string>
- <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"<xliff:g id="TIME">%s</xliff:g> बजे चालू हाेगी"</string>
- <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"<xliff:g id="TIME">%s</xliff:g> बजे तक चालू रहेगी"</string>
+ <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"<xliff:g id="TIME">%s</xliff:g> पर चालू हाेगी"</string>
+ <string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"<xliff:g id="TIME">%s</xliff:g> तक चालू रहेगी"</string>
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"एनएफ़सी"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC बंद है"</string>
<string name="quick_settings_nfc_on" msgid="1004976611203202230">"NFC चालू है"</string>
@@ -964,4 +964,6 @@
<string name="magnification_overlay_title" msgid="6584179429612427958">"Magnification Overlay Window"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"स्क्रीन को बड़ा करके दिखाने वाली विंडो"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"स्क्रीन को बड़ा करके दिखाने वाली विंडो के नियंत्रण"</string>
+ <!-- no translation found for quick_controls_title (525285759614231333) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index 55a0e788581a..5eefc79a35f2 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -969,4 +969,5 @@
<string name="magnification_overlay_title" msgid="6584179429612427958">"Prozor preklapanja povećavanja"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Prozor za povećavanje"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Kontrole prozora za povećavanje"</string>
+ <string name="quick_controls_title" msgid="525285759614231333">"Brze kontrole"</string>
</resources>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index a9b2d036ebcc..5ce235dccce0 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -964,4 +964,5 @@
<string name="magnification_overlay_title" msgid="6584179429612427958">"Nagyítási fedvény ablaka"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Nagyítás ablaka"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Nagyítási vezérlők ablaka"</string>
+ <string name="quick_controls_title" msgid="525285759614231333">"Gyorsvezérlők"</string>
</resources>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index 78acb2ed164e..4fa7096217be 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -964,4 +964,5 @@
<string name="magnification_overlay_title" msgid="6584179429612427958">"Խոշորացման պատուհանի վրադրում"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Խոշորացման պատուհան"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Խոշորացման պատուհանի կառավարման տարրեր"</string>
+ <string name="quick_controls_title" msgid="525285759614231333">"Արագ կառավարման տարրեր"</string>
</resources>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 95c16c87dc1a..b3db0f3fd30b 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -964,4 +964,5 @@
<string name="magnification_overlay_title" msgid="6584179429612427958">"Jendela Overlay Pembesaran"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Jendela Pembesaran"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Kontrol Jendela Pembesaran"</string>
+ <string name="quick_controls_title" msgid="525285759614231333">"Kontrol Cepat"</string>
</resources>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index 985f62d3e936..56e67ef3e0ff 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -964,4 +964,5 @@
<string name="magnification_overlay_title" msgid="6584179429612427958">"Stækkun yfirglugga"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Stækkunargluggi"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Stækkunarstillingar glugga"</string>
+ <string name="quick_controls_title" msgid="525285759614231333">"Flýtistýringar"</string>
</resources>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 870e6b7a75e7..423067713aa8 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -964,4 +964,5 @@
<string name="magnification_overlay_title" msgid="6584179429612427958">"Finestra overlay ingrandimento"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Finestra ingrandimento"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Finestra controlli di ingrandimento"</string>
+ <string name="quick_controls_title" msgid="525285759614231333">"Controlli rapidi"</string>
</resources>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 775be02e20e9..b20b10f227ba 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -974,4 +974,6 @@
<string name="magnification_overlay_title" msgid="6584179429612427958">"חלון ליצירת שכבת-על להגדלה"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"חלון הגדלה"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"בקרות של חלון ההגדלה"</string>
+ <!-- no translation found for quick_controls_title (525285759614231333) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 7af3f8631f03..b5189732a11b 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -964,4 +964,5 @@
<string name="magnification_overlay_title" msgid="6584179429612427958">"拡大オーバーレイ ウィンドウ"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"拡大ウィンドウ"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"拡大ウィンドウ コントロール"</string>
+ <string name="quick_controls_title" msgid="525285759614231333">"クイック コントロール"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index 2433f9e32e8f..ab0dba829107 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -964,4 +964,6 @@
<string name="magnification_overlay_title" msgid="6584179429612427958">"გადიდების გადაფარვის ფანჯარა"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"გადიდების ფანჯარა"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"გადიდების კონტროლის ფანჯარა"</string>
+ <!-- no translation found for quick_controls_title (525285759614231333) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index be93c18006b9..3c44cabb2f2f 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -964,4 +964,6 @@
<string name="magnification_overlay_title" msgid="6584179429612427958">"Ұлғайту терезесін қабаттастыру"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Ұлғайту терезесі"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Ұлғайту терезесінің басқару элементтері"</string>
+ <!-- no translation found for quick_controls_title (525285759614231333) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index 413125cefb92..480b69490252 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -964,4 +964,5 @@
<string name="magnification_overlay_title" msgid="6584179429612427958">"វិនដូ​ត្រួតគ្នា​លើ​ការពង្រីក"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"វិនដូ​ការពង្រីក"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"វិនដូគ្រប់គ្រង​​ការពង្រីក"</string>
+ <string name="quick_controls_title" msgid="525285759614231333">"ការគ្រប់គ្រង​រហ័ស"</string>
</resources>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index 0b98e0655a7e..c65e653f0f51 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -964,4 +964,6 @@
<string name="magnification_overlay_title" msgid="6584179429612427958">"ವರ್ಧನೆಯ ಓವರ್‌ಲೇ ವಿಂಡೋ"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"ವರ್ಧನೆಯ ವಿಂಡೋ"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"ವರ್ಧನೆಯ ವಿಂಡೋ ನಿಯಂತ್ರಣಗಳು"</string>
+ <!-- no translation found for quick_controls_title (525285759614231333) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 54b055dd674b..fb5818c710dc 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -964,4 +964,6 @@
<string name="magnification_overlay_title" msgid="6584179429612427958">"확대 오버레이 창"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"확대 창"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"확대 창 컨트롤"</string>
+ <!-- no translation found for quick_controls_title (525285759614231333) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index ed6b9186cdba..53d780ea488f 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -964,4 +964,6 @@
<string name="magnification_overlay_title" msgid="6584179429612427958">"Чоңойтуу терезесин үстүнө коюу"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Чоңойтуу терезеси"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Чоңойтуу терезесин башкаруу каражаттары"</string>
+ <!-- no translation found for quick_controls_title (525285759614231333) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index 11c4f7c45433..48166f394289 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -964,4 +964,5 @@
<string name="magnification_overlay_title" msgid="6584179429612427958">"ໜ້າຈໍວາງທັບການຂະຫຍາຍ"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"ໜ້າຈໍການຂະຫຍາຍ"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"ການຄວບຄຸມໜ້າຈໍການຂະຫຍາຍ"</string>
+ <string name="quick_controls_title" msgid="525285759614231333">"ການຄວບຄຸມດ່ວນ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 7da1174c0878..70bcf372d895 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -974,4 +974,5 @@
<string name="magnification_overlay_title" msgid="6584179429612427958">"Didinimo perdangos langas"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Didinimo langas"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Didinimo lango valdikliai"</string>
+ <string name="quick_controls_title" msgid="525285759614231333">"Spartieji valdikliai"</string>
</resources>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index fed86b324c78..6c28b103748f 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -969,4 +969,6 @@
<string name="magnification_overlay_title" msgid="6584179429612427958">"Palielināšanas pārklājuma logs"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Palielināšanas logs"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Palielināšanas loga vadīklas"</string>
+ <!-- no translation found for quick_controls_title (525285759614231333) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index a02f38ed267b..f81c5ff6fc64 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -964,4 +964,5 @@
<string name="magnification_overlay_title" msgid="6584179429612427958">"Прозорец за преклопување на зголемувањето"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Прозорец за зголемување"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Контроли на прозорец за зголемување"</string>
+ <string name="quick_controls_title" msgid="525285759614231333">"Брзи контроли"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index 2d3f73fc5978..3ffcbc278bac 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -964,4 +964,6 @@
<string name="magnification_overlay_title" msgid="6584179429612427958">"മാഗ്നിഫിക്കേഷൻ ഓവർലേ വിൻഡോ"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"മാഗ്നിഫിക്കേഷൻ വിൻഡോ"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"മാഗ്നിഫിക്കേഷൻ വിൻഡോ നിയന്ത്രണങ്ങൾ"</string>
+ <!-- no translation found for quick_controls_title (525285759614231333) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index 85d7eadce349..87d5fbffb1bc 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -964,4 +964,5 @@
<string name="magnification_overlay_title" msgid="6584179429612427958">"Томруулалтыг давхарласан цонх"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Томруулалтын цонх"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Томруулалтын цонхны хяналт"</string>
+ <string name="quick_controls_title" msgid="525285759614231333">"Шуурхай хяналтууд"</string>
</resources>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index 3406edf3f1bd..d67c0ef05c6d 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -964,4 +964,6 @@
<string name="magnification_overlay_title" msgid="6584179429612427958">"मॅग्निफिकेशन ओव्हरले विंडो"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"मॅग्निफिकेशन विंडो"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"मॅग्निफिकेशन विंडो नियंत्रणे"</string>
+ <!-- no translation found for quick_controls_title (525285759614231333) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index eeaaceae0669..e3e9746d728a 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -964,4 +964,6 @@
<string name="magnification_overlay_title" msgid="6584179429612427958">"Tetingkap Tindanan Pembesaran"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Tetingkap Pembesaran"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Kawalan Tetingkap Pembesaran"</string>
+ <!-- no translation found for quick_controls_title (525285759614231333) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index 5ae82eafbcf9..99075709a62a 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -964,4 +964,6 @@
<string name="magnification_overlay_title" msgid="6584179429612427958">"ဝင်းဒိုး ထပ်ပိုးလွှာ ချဲ့ခြင်း"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"ဝင်းဒိုး ချဲ့ခြင်း"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"ဝင်းဒိုး ထိန်းချုပ်မှုများ ချဲ့ခြင်း"</string>
+ <!-- no translation found for quick_controls_title (525285759614231333) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 463b95c0107e..c273cc9c4bf2 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -964,4 +964,5 @@
<string name="magnification_overlay_title" msgid="6584179429612427958">"Overleggsvindu for forstørring"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Forstørringsvindu"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Kontroller for forstørringsvindu"</string>
+ <string name="quick_controls_title" msgid="525285759614231333">"Hurtigkontroller"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index 21a76a3a86d0..dea3311e558e 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -964,4 +964,6 @@
<string name="magnification_overlay_title" msgid="6584179429612427958">"म्याग्निफिकेसन ओभरले विन्डो"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"म्याग्निफिकेसन विन्डो"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"म्याग्निफिकेसन विन्डोका नियन्त्रणहरू"</string>
+ <!-- no translation found for quick_controls_title (525285759614231333) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 3c040154437c..8b015ab3c048 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -964,4 +964,5 @@
<string name="magnification_overlay_title" msgid="6584179429612427958">"Overlay voor vergrotingsvenster"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Vergrotingsvenster"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Bediening van vergrotingsvenster"</string>
+ <string name="quick_controls_title" msgid="525285759614231333">"Snelle bedieningselementen"</string>
</resources>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index 42302756debd..e274f2720d58 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -964,4 +964,6 @@
<string name="magnification_overlay_title" msgid="6584179429612427958">"ମ୍ୟାଗ୍ନିଫିକେସନ୍ ଓଭର୍‌ଲେ ୱିଣ୍ଡୋ"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"ମ୍ୟାଗ୍ନିଫିକେସନ୍ ୱିଣ୍ଡୋ"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"ମ୍ୟାଗ୍ନିଫିକେସନ୍ ୱିଣ୍ଡୋ ନିୟନ୍ତ୍ରଣଗୁଡ଼ିକ"</string>
+ <!-- no translation found for quick_controls_title (525285759614231333) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index f345d6a8f7aa..28da4edbe50d 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -964,4 +964,6 @@
<string name="magnification_overlay_title" msgid="6584179429612427958">"ਵੱਡਦਰਸ਼ੀਕਰਨ ਓਵਰਲੇ Window"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"ਵੱਡਦਰਸ਼ੀਕਰਨ Window"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"ਵੱਡਦਰਸ਼ੀਕਰਨ Window ਦੇ ਕੰਟਰੋਲ"</string>
+ <!-- no translation found for quick_controls_title (525285759614231333) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 68cb14eb32b3..fd48b9721e52 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -909,7 +909,7 @@
<string name="notification_channel_battery" msgid="9219995638046695106">"Bateria"</string>
<string name="notification_channel_screenshot" msgid="7665814998932211997">"Zrzuty ekranu"</string>
<string name="notification_channel_general" msgid="4384774889645929705">"Wiadomości"</string>
- <string name="notification_channel_storage" msgid="2720725707628094977">"Pamięć"</string>
+ <string name="notification_channel_storage" msgid="2720725707628094977">"Pamięć wewnętrzna"</string>
<string name="notification_channel_hints" msgid="7703783206000346876">"Wskazówki"</string>
<string name="instant_apps" msgid="8337185853050247304">"Aplikacje błyskawiczne"</string>
<string name="instant_apps_title" msgid="8942706782103036910">"Aplikacja <xliff:g id="APP">%1$s</xliff:g> działa"</string>
@@ -974,4 +974,5 @@
<string name="magnification_overlay_title" msgid="6584179429612427958">"Okno nakładki powiększenia"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Okno powiększenia"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Elementy sterujące okna powiększenia"</string>
+ <string name="quick_controls_title" msgid="525285759614231333">"Szybkie sterowanie"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index a9101d74706f..6f616626a633 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -964,4 +964,5 @@
<string name="magnification_overlay_title" msgid="6584179429612427958">"Janela de sobreposição de ampliação"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Janela de ampliação"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Controles da janela de ampliação"</string>
+ <string name="quick_controls_title" msgid="525285759614231333">"Controles rápidos"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 1a6e6739e7ff..be534ae205c4 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -964,4 +964,5 @@
<string name="magnification_overlay_title" msgid="6584179429612427958">"Janela de sobreposição da ampliação"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Janela de ampliação"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Controlos da janela de ampliação"</string>
+ <string name="quick_controls_title" msgid="525285759614231333">"Controlos rápidos"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index a9101d74706f..6f616626a633 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -964,4 +964,5 @@
<string name="magnification_overlay_title" msgid="6584179429612427958">"Janela de sobreposição de ampliação"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Janela de ampliação"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Controles da janela de ampliação"</string>
+ <string name="quick_controls_title" msgid="525285759614231333">"Controles rápidos"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index e34fa2de54d2..44940bf84a77 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -969,4 +969,5 @@
<string name="magnification_overlay_title" msgid="6584179429612427958">"Fereastra de suprapunere pentru mărire"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Fereastra de mărire"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Comenzi pentru fereastra de mărire"</string>
+ <string name="quick_controls_title" msgid="525285759614231333">"Comenzi rapide"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 0ee159d0c648..6fe20944448c 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -974,4 +974,6 @@
<string name="magnification_overlay_title" msgid="6584179429612427958">"Наложение окна увеличения"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Окно увеличения"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Настройки окна увеличения"</string>
+ <!-- no translation found for quick_controls_title (525285759614231333) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index 2c5e1d8ba117..38933ad6c46a 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -964,4 +964,5 @@
<string name="magnification_overlay_title" msgid="6584179429612427958">"විශාලන උඩැතිරි කවුළුව"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"විශාලන කවුළුව"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"විශාලනය කිරීමේ කවුළු පාලන"</string>
+ <string name="quick_controls_title" msgid="525285759614231333">"ඉක්මන් පාලන"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 93f93a2860a9..5bd709c7142a 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -974,4 +974,5 @@
<string name="magnification_overlay_title" msgid="6584179429612427958">"Okno prekrytia priblíženia"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Okno priblíženia"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Ovládacie prvky okna priblíženia"</string>
+ <string name="quick_controls_title" msgid="525285759614231333">"Rýchle ovládacie prvky"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 452827fa362f..7c06fa7da3cb 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -974,4 +974,5 @@
<string name="magnification_overlay_title" msgid="6584179429612427958">"Prekrivno povečevalno okno"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Povečevalno okno"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Kontrolniki povečevalnega okna"</string>
+ <string name="quick_controls_title" msgid="525285759614231333">"Hitro upravljanje"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index 2dc3cc8b1cd2..7549611ec071 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -964,4 +964,6 @@
<string name="magnification_overlay_title" msgid="6584179429612427958">"Dritarja e mbivendosjes së zmadhimit"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Dritarja e zmadhimit"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Kontrollet e dritares së zmadhimit"</string>
+ <!-- no translation found for quick_controls_title (525285759614231333) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 4127806f9cd3..6b2d971df6ed 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -969,4 +969,5 @@
<string name="magnification_overlay_title" msgid="6584179429612427958">"Преклопни прозор за увећање"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Прозор за увећање"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Контроле прозора за увећање"</string>
+ <string name="quick_controls_title" msgid="525285759614231333">"Брзе контроле"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 3e29fa6e6749..33c20789dc2b 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -964,4 +964,5 @@
<string name="magnification_overlay_title" msgid="6584179429612427958">"Överlagrat förstoringsfönster"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Förstoringsfönster"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Inställningar för förstoringsfönster"</string>
+ <string name="quick_controls_title" msgid="525285759614231333">"Snabbinställningar"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 9fd4284710d1..bf2640f41042 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -958,10 +958,11 @@
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Sogeza chini kushoto"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Sogeza chini kulia"</string>
<string name="bubble_dismiss_text" msgid="7071770411580452911">"Ondoa"</string>
- <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Umesasisha usogezaji kwenye mfumo. Ili ufanye mabadiliko, nenda kwenye Mipangilio."</string>
+ <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Umesasisha usogezaji kwenye mfumo. Ili ubadilishe, nenda kwenye Mipangilio."</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Nenda kwenye mipangilio ili usasishe usogezaji kwenye mfumo"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"Hali tuli"</string>
<string name="magnification_overlay_title" msgid="6584179429612427958">"Dirisha la Kuwekelea Linalokuza"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Dirisha la Ukuzaji"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Vidhibiti vya Dirisha la Ukuzaji"</string>
+ <string name="quick_controls_title" msgid="525285759614231333">"Vidhibiti vya Haraka"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index 55bd472a7889..c5289ec55c50 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -964,4 +964,6 @@
<string name="magnification_overlay_title" msgid="6584179429612427958">"Magnification Overlay Window"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"பெரிதாக்கல் சாளரம்"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"பெரிதாக்கல் சாளரக் கட்டுப்பாடுகள்"</string>
+ <!-- no translation found for quick_controls_title (525285759614231333) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index 8b9c07ce0264..ed562f3d7377 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -71,7 +71,7 @@
<string name="compat_mode_on" msgid="4963711187149440884">"స్క్రీన్‌కు నింపేలా జూమ్ చేయండి"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"స్క్రీన్‌కు నింపేలా విస్తరించండి"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"స్క్రీన్‌షాట్"</string>
- <string name="remote_input_image_insertion_text" msgid="4613177882724332877">"చిత్రం చొప్పించబడింది"</string>
+ <string name="remote_input_image_insertion_text" msgid="4613177882724332877">"ఇమేజ్ చొప్పించబడింది"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"స్క్రీన్‌షాట్‌ను సేవ్ చేస్తోంది…"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"స్క్రీన్‌షాట్‌ను సేవ్ చేస్తోంది…"</string>
<string name="screenshot_saved_title" msgid="8893267638659083153">"స్క్రీన్‌షాట్ సేవ్ చేయబడింది"</string>
@@ -390,7 +390,7 @@
<string name="quick_settings_dark_mode_secondary_label_battery_saver" msgid="4990712734503013251">"బ్యాటరీ సేవర్"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at_sunset" msgid="6017379738102015710">"సూర్యాస్తమయానికి"</string>
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"సూర్యోదయం వరకు"</string>
- <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"<xliff:g id="TIME">%s</xliff:g> వద్ద"</string>
+ <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"<xliff:g id="TIME">%s</xliff:g> కు ఆన్ అవుతుంది"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"<xliff:g id="TIME">%s</xliff:g> వరకు"</string>
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC నిలిపివేయబడింది"</string>
@@ -964,4 +964,6 @@
<string name="magnification_overlay_title" msgid="6584179429612427958">"మాగ్నిఫికేషన్ ఓవర్‌లే విండో"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"మాగ్నిఫికేషన్ విండో"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"మాగ్నిఫికేషన్ నియంత్రణల విండో"</string>
+ <!-- no translation found for quick_controls_title (525285759614231333) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-television/config.xml b/packages/SystemUI/res/values-television/config.xml
index dd4c3210922a..bb4999453d4f 100644
--- a/packages/SystemUI/res/values-television/config.xml
+++ b/packages/SystemUI/res/values-television/config.xml
@@ -20,6 +20,9 @@
<!-- These resources are around just to allow their values to be customized
for different hardware and product builds. -->
<resources>
+ <!-- SystemUIFactory component -->
+ <string name="config_systemUIFactoryComponent" translatable="false">com.android.systemui.tv.TvSystemUIFactory</string>
+
<!-- SystemUI Services: The classes of the stuff to start. -->
<string-array name="config_systemUIServiceComponents" translatable="false">
<item>com.android.systemui.util.NotificationChannels</item>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index c5e01236912d..9e5b2dbaf18b 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -964,4 +964,5 @@
<string name="magnification_overlay_title" msgid="6584179429612427958">"หน้าต่างการขยายที่วางซ้อน"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"หน้าต่างการขยาย"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"การควบคุมหน้าต่างการขยาย"</string>
+ <string name="quick_controls_title" msgid="525285759614231333">"การควบคุมอย่างรวดเร็ว"</string>
</resources>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 3d343c5b4c0b..9485a2bf3cc2 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -964,4 +964,5 @@
<string name="magnification_overlay_title" msgid="6584179429612427958">"Window ng Overlay sa Pag-magnify"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Window ng Pag-magnify"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Mga Kontrol sa Pag-magnify ng Window"</string>
+ <string name="quick_controls_title" msgid="525285759614231333">"Mga Mabilisang Kontrol"</string>
</resources>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 46e583fb5124..950b66b11dbf 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -964,4 +964,5 @@
<string name="magnification_overlay_title" msgid="6584179429612427958">"Yer Paylaşımlı Büyütme Penceresi"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Büyütme Penceresi"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Büyütme Penceresi Kontrolleri"</string>
+ <string name="quick_controls_title" msgid="525285759614231333">"Hızlı Kontroller"</string>
</resources>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 7baad0df2e55..3e1e4a96fb5c 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -974,4 +974,5 @@
<string name="magnification_overlay_title" msgid="6584179429612427958">"Вікно збільшення з накладанням"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Вікно збільшення"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Елементи керування вікна збільшення"</string>
+ <string name="quick_controls_title" msgid="525285759614231333">"Елементи швидкого керування"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index 97d0a5d1d2a3..6f3e7ab02ff3 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -964,4 +964,5 @@
<string name="magnification_overlay_title" msgid="6584179429612427958">"میگنیفیکیشن اوورلے ونڈو"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"میگنیفکیشن ونڈو"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"میگنیفکیشن ونڈو کنٹرولز"</string>
+ <string name="quick_controls_title" msgid="525285759614231333">"فوری کنٹرولز"</string>
</resources>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index b514f1e9754c..618463e91040 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -390,7 +390,7 @@
<string name="quick_settings_dark_mode_secondary_label_battery_saver" msgid="4990712734503013251">"Quvvat tejash"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at_sunset" msgid="6017379738102015710">"Kunbotarda yoqish"</string>
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Quyosh chiqqunicha"</string>
- <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"<xliff:g id="TIME">%s</xliff:g> da yoqish"</string>
+ <string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"<xliff:g id="TIME">%s</xliff:g> da yoqiladi"</string>
<string name="quick_settings_dark_mode_secondary_label_until" msgid="2289774641256492437">"<xliff:g id="TIME">%s</xliff:g> gacha"</string>
<string name="quick_settings_nfc_label" msgid="1054317416221168085">"NFC"</string>
<string name="quick_settings_nfc_off" msgid="3465000058515424663">"NFC o‘chiq"</string>
@@ -477,9 +477,9 @@
<string name="media_projection_remember_text" msgid="6896767327140422951">"Boshqa ko‘rsatilmasin"</string>
<string name="clear_all_notifications_text" msgid="348312370303046130">"Hammasini tozalash"</string>
<string name="manage_notifications_text" msgid="6885645344647733116">"Boshqarish"</string>
- <string name="notification_section_header_gentle" msgid="3044910806569985386">"Tovushsiz bildirishnomalar"</string>
+ <string name="notification_section_header_gentle" msgid="3044910806569985386">"Sokin bildirishnomalar"</string>
<string name="notification_section_header_conversations" msgid="821834744538345661">"Suhbatlar"</string>
- <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Barcha tovushsiz bildirishnomalarni tozalash"</string>
+ <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Barcha sokin bildirishnomalarni tozalash"</string>
<string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Bezovta qilinmasin rejimida bildirishnomalar pauza qilingan"</string>
<string name="media_projection_action_text" msgid="3634906766918186440">"Boshlash"</string>
<string name="empty_shade_text" msgid="8935967157319717412">"Bildirishnomalar yo‘q"</string>
@@ -964,4 +964,5 @@
<string name="magnification_overlay_title" msgid="6584179429612427958">"Kattalashtirish oynasining ustidan ochilishi"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Kattalashtirish oynasi"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Kattalashtirish oynasi sozlamalari"</string>
+ <string name="quick_controls_title" msgid="525285759614231333">"Tezkor tugmalar"</string>
</resources>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index c4d76187c817..6be05aab1583 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -964,4 +964,6 @@
<string name="magnification_overlay_title" msgid="6584179429612427958">"Cửa sổ lớp phủ phóng to"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Cửa sổ phóng to"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Các tùy chọn điều khiển cửa sổ phóng to"</string>
+ <!-- no translation found for quick_controls_title (525285759614231333) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 56edb64fd798..e10abbb342a0 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -964,4 +964,6 @@
<string name="magnification_overlay_title" msgid="6584179429612427958">"放大叠加窗口"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"放大窗口"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"放大窗口控件"</string>
+ <!-- no translation found for quick_controls_title (525285759614231333) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index 251e23d1526b..a83ce53ca1e4 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -964,4 +964,5 @@
<string name="magnification_overlay_title" msgid="6584179429612427958">"放大重疊視窗"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"放大視窗"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"放大視窗控制項"</string>
+ <string name="quick_controls_title" msgid="525285759614231333">"快速控制介面"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index a7ec5985a745..903259593765 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -964,4 +964,5 @@
<string name="magnification_overlay_title" msgid="6584179429612427958">"放大重疊視窗"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"放大視窗"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"放大視窗控制項"</string>
+ <string name="quick_controls_title" msgid="525285759614231333">"快速控制項"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 1203b579c52f..019128b0ab5b 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -964,4 +964,5 @@
<string name="magnification_overlay_title" msgid="6584179429612427958">"Iwindi Lembondela Lesikhulisi"</string>
<string name="magnification_window_title" msgid="4863914360847258333">"Iwindi Lesikhulisi"</string>
<string name="magnification_controls_title" msgid="8421106606708891519">"Izilawuli Zewindi Lesikhulisi"</string>
+ <string name="quick_controls_title" msgid="525285759614231333">"Izilawuli Ezisheshayo"</string>
</resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 33cabc1fea52..9c997e88c0c2 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -1187,7 +1187,27 @@
<dimen name="control_corner_radius">15dp</dimen>
<dimen name="control_height">100dp</dimen>
<dimen name="control_padding">15dp</dimen>
- <dimen name="control_status_normal">12dp</dimen>
- <dimen name="control_status_expanded">18dp</dimen>
- <dimen name="app_icon_size">32dp</dimen>
+ <dimen name="control_status_normal">12sp</dimen>
+ <dimen name="control_status_expanded">18sp</dimen>
+ <dimen name="control_base_item_margin">2dp</dimen>
+ <dimen name="control_status_padding">3dp</dimen>
+
+ <!-- Home Controls management screens -->
+ <dimen name="controls_management_top_padding">48dp</dimen>
+ <dimen name="controls_management_side_padding">8dp</dimen>
+ <dimen name="controls_management_titles_margin">8dp</dimen>
+ <dimen name="controls_management_list_margin">16dp</dimen>
+ <dimen name="controls_title_size">26sp</dimen>
+
+ <dimen name="controls_app_icon_size">32dp</dimen>
+ <dimen name="controls_app_icon_frame_side_padding">8dp</dimen>
+ <dimen name="controls_app_icon_frame_top_padding">4dp</dimen>
+ <dimen name="controls_app_bottom_margin">8dp</dimen>
+ <dimen name="controls_app_text_padding">8dp</dimen>
+ <dimen name="controls_app_divider_height">2dp</dimen>
+ <dimen name="controls_app_divider_side_margin">32dp</dimen>
+
+ <dimen name="controls_card_margin">2dp</dimen>
+
+
</resources>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index fb8df5bfc7ce..82cd5f71e8a0 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -2547,6 +2547,24 @@
<!-- Title for Magnification Controls Window [CHAR LIMIT=NONE] -->
<string name="magnification_controls_title">Magnification Window Controls</string>
- <!-- Quick Controls strings [CHAR LIMIT=30] -->
+ <!-- Quick Controls strings -->
+ <!-- Quick Controls view header [CHAR LIMIT=30] -->
<string name="quick_controls_title">Quick Controls</string>
+
+ <!-- Controls management providers screen title [CHAR LIMIT=30]-->
+ <string name="controls_providers_title">Add Controls</string>
+ <!-- Controls management providers screen subtitle [CHAR LIMIT=NONE] -->
+ <string name="controls_providers_subtitle">Choose an app from which to add controls</string>
+ <!-- Number of favorites for controls management screen [CHAR LIMIT=NONE]-->
+ <plurals name="controls_number_of_favorites">
+ <item quantity="one"><xliff:g id="number" example="1">%s</xliff:g> current favorite.</item>
+ <item quantity="other"><xliff:g id="number" example="3">%s</xliff:g> current favorites.</item>
+ </plurals>
+
+ <!-- Controls management controls screen default title [CHAR LIMIT=30] -->
+ <string name="controls_favorite_default_title">Controls</string>
+ <!-- Controls management controls screen subtitle [CHAR LIMIT=NONE] -->
+ <string name="controls_favorite_subtitle">Choose controls for quick access</string>
+
+
</resources>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 10f59a423805..bcffa8d0feea 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -234,6 +234,37 @@
<style name="TextAppearance.DeviceManagementDialog.Title" parent="@android:style/TextAppearance.DeviceDefault.DialogWindowTitle"/>
+ <style name="TextAppearance.AuthCredential">
+ <item name="android:gravity">center_horizontal</item>
+ <item name="android:fontFamily">google-sans</item>
+ <item name="android:textAlignment">gravity</item>
+ <item name="android:layout_gravity">top</item>
+ <item name="android:textColor">?android:attr/textColorPrimary</item>
+ </style>
+
+ <style name="TextAppearance.AuthCredential.Title">
+ <item name="android:layout_marginBottom">2dp</item>
+ <item name="android:layout_marginLeft">24dp</item>
+ <item name="android:layout_marginRight">24dp</item>
+ <item name="android:layout_marginTop">16dp</item>
+ <item name="android:textSize">24sp</item>
+ </style>
+
+ <style name="TextAppearance.AuthCredential.Description">
+ <item name="android:layout_marginBottom">12dp</item>
+ <item name="android:layout_marginStart">40dp</item>
+ <item name="android:layout_marginEnd">40dp</item>
+ <item name="android:layout_marginTop">3dp</item>
+ <item name="android:textSize">16sp</item>
+ </style>
+
+ <style name="TextAppearance.AuthCredential.PasswordEntry" parent="@android:style/TextAppearance.DeviceDefault">
+ <item name="android:gravity">center</item>
+ <item name="android:singleLine">true</item>
+ <item name="android:textColor">?android:attr/colorForeground</item>
+ <item name="android:textSize">24sp</item>
+ </style>
+
<style name="DeviceManagementDialogTitle">
<item name="android:gravity">center</item>
<item name="android:textAppearance">@style/TextAppearance.DeviceManagementDialog.Title</item>
@@ -297,6 +328,16 @@
<item name="android:textColor">?attr/wallpaperTextColor</item>
</style>
+ <style name="LockPatternContainerStyle">
+ <item name="android:maxHeight">400dp</item>
+ <item name="android:maxWidth">420dp</item>
+ <item name="android:minHeight">0dp</item>
+ <item name="android:minWidth">0dp</item>
+ <item name="android:paddingBottom">0dp</item>
+ <item name="android:paddingHorizontal">44dp</item>
+ <item name="android:paddingTop">0dp</item>
+ </style>
+
<style name="LockPatternStyle">
<item name="*android:regularColor">?attr/wallpaperTextColor</item>
<item name="*android:successColor">?attr/wallpaperTextColor</item>
@@ -583,4 +624,28 @@
<item name="android:background">?android:attr/selectableItemBackground</item>
<item name="android:textColor">?android:attr/textColorPrimary</item>
</style>
+
+ <!-- Controls styles -->
+ <style name="Theme.ControlsManagement" parent="@android:style/Theme.DeviceDefault.NoActionBar">
+ <item name="android:windowIsTranslucent">false</item>
+ </style>
+
+ <style name="TextAppearance.Control">
+ <item name="android:fontFamily">@*android:string/config_bodyFontFamily</item>
+ </style>
+
+ <style name="TextAppearance.Control.Status">
+ <item name="android:textSize">12sp</item>
+ <item name="android:textColor">?android:attr/textColorPrimary</item>
+ </style>
+
+ <style name="TextAppearance.Control.Title">
+ <item name="android:textSize">14sp</item>
+ <item name="android:textColor">?android:attr/textColorPrimary</item>
+ </style>
+ <style name="TextAppearance.Control.Subtitle">
+ <item name="android:textSize">12sp</item>
+ <item name="android:textColor">?android:attr/textColorSecondary</item>
+ </style>
+
</resources>
diff --git a/packages/SystemUI/src/com/android/systemui/ForegroundServiceNotificationListener.java b/packages/SystemUI/src/com/android/systemui/ForegroundServiceNotificationListener.java
index eab970626bf1..924d16dd27d7 100644
--- a/packages/SystemUI/src/com/android/systemui/ForegroundServiceNotificationListener.java
+++ b/packages/SystemUI/src/com/android/systemui/ForegroundServiceNotificationListener.java
@@ -89,7 +89,7 @@ public class ForegroundServiceNotificationListener {
}
@Override
- public void onEntryRemoved(NotificationEntry entry, int reason, boolean removedByUser) {
+ public void onEntryRemoved(NotificationEntry entry, int reason) {
removeNotification(entry.getSbn());
}
});
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java
index 044c5a027dac..7dea7f83f0c6 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java
@@ -664,6 +664,7 @@ public abstract class AuthBiometricView extends LinearLayout {
setTextOrHide(mSubtitleView,
mBiometricPromptBundle.getString(BiometricPrompt.KEY_SUBTITLE));
+
setTextOrHide(mDescriptionView,
mBiometricPromptBundle.getString(BiometricPrompt.KEY_DESCRIPTION));
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialView.java
index 8f2cf70a8184..68b05e358786 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialView.java
@@ -17,6 +17,7 @@
package com.android.systemui.biometrics;
import android.content.Context;
+import android.graphics.drawable.Drawable;
import android.hardware.biometrics.BiometricPrompt;
import android.os.AsyncTask;
import android.os.Bundle;
@@ -28,6 +29,7 @@ import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.View;
import android.view.accessibility.AccessibilityManager;
+import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
@@ -56,6 +58,7 @@ public abstract class AuthCredentialView extends LinearLayout {
private TextView mTitleView;
private TextView mSubtitleView;
private TextView mDescriptionView;
+ private ImageView mIconView;
protected TextView mErrorView;
protected @Utils.CredentialType int mCredentialType;
@@ -176,6 +179,16 @@ public abstract class AuthCredentialView extends LinearLayout {
setTextOrHide(mDescriptionView,
mBiometricPromptBundle.getString(BiometricPrompt.KEY_DESCRIPTION));
+ final boolean isManagedProfile = Utils.isManagedProfile(mContext, mEffectiveUserId);
+ final Drawable image;
+ if (isManagedProfile) {
+ image = getResources().getDrawable(R.drawable.auth_dialog_enterprise,
+ mContext.getTheme());
+ } else {
+ image = getResources().getDrawable(R.drawable.auth_dialog_lock, mContext.getTheme());
+ }
+ mIconView.setImageDrawable(image);
+
// Only animate this if we're transitioning from a biometric view.
if (mShouldAnimateContents) {
setTranslationY(getResources()
@@ -207,6 +220,7 @@ public abstract class AuthCredentialView extends LinearLayout {
mTitleView = findViewById(R.id.title);
mSubtitleView = findViewById(R.id.subtitle);
mDescriptionView = findViewById(R.id.description);
+ mIconView = findViewById(R.id.icon);
mErrorView = findViewById(R.id.error);
}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
index a26cce0bfc0c..7c07c9d81000 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
@@ -429,12 +429,11 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
}
});
- mNotificationEntryManager.setNotificationRemoveInterceptor(
+ mNotificationEntryManager.addNotificationRemoveInterceptor(
new NotificationRemoveInterceptor() {
@Override
- public boolean onNotificationRemoveRequested(String key, int reason) {
- NotificationEntry entry =
- mNotificationEntryManager.getActiveNotificationUnfiltered(key);
+ public boolean onNotificationRemoveRequested(
+ String key, NotificationEntry entry, int reason) {
return shouldInterceptDismissal(entry, reason);
}
});
diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsController.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsController.kt
index b02de4500043..b3ba2b22f6df 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsController.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsController.kt
@@ -29,6 +29,7 @@ interface ControlsController : UserAwareController {
fun loadForComponent(componentName: ComponentName, callback: (List<ControlStatus>) -> Unit)
fun subscribeToFavorites()
fun changeFavoriteStatus(controlInfo: ControlInfo, state: Boolean)
+ fun countFavoritesForComponent(componentName: ComponentName): Int = 0
fun unsubscribe()
fun action(controlInfo: ControlInfo, action: ControlAction)
fun refreshStatus(componentName: ComponentName, control: Control)
diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt
index 6ff1cf8474d3..a6f1d84877c5 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt
@@ -328,6 +328,12 @@ class ControlsControllerImpl @Inject constructor (
}
}
+ override fun countFavoritesForComponent(componentName: ComponentName): Int {
+ return synchronized(currentFavorites) {
+ currentFavorites.get(componentName)?.size ?: 0
+ }
+ }
+
override fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<out String>) {
pw.println("ControlsController state:")
pw.println(" Available: $available")
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/AppAdapter.kt b/packages/SystemUI/src/com/android/systemui/controls/management/AppAdapter.kt
index 22c69086cf8c..b12243964fc1 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/AppAdapter.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/AppAdapter.kt
@@ -17,6 +17,7 @@
package com.android.systemui.controls.management
import android.content.ComponentName
+import android.content.res.Resources
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
@@ -25,6 +26,7 @@ import android.widget.TextView
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleOwner
import androidx.recyclerview.widget.RecyclerView
+import com.android.settingslib.applications.DefaultAppInfo
import com.android.settingslib.widget.CandidateInfo
import com.android.systemui.R
import java.util.concurrent.Executor
@@ -46,7 +48,8 @@ class AppAdapter(
lifecycle: Lifecycle,
controlsListingController: ControlsListingController,
private val layoutInflater: LayoutInflater,
- private val onAppSelected: (ComponentName?) -> Unit = {}
+ private val onAppSelected: (ComponentName?) -> Unit = {},
+ private val favoritesRenderer: FavoritesRenderer
) : RecyclerView.Adapter<AppAdapter.Holder>() {
private var listOfServices = emptyList<CandidateInfo>()
@@ -54,7 +57,9 @@ class AppAdapter(
private val callback = object : ControlsListingController.ControlsListingCallback {
override fun onServicesUpdated(list: List<CandidateInfo>) {
uiExecutor.execute {
- listOfServices = list
+ listOfServices = list.sortedBy {
+ it.loadLabel().toString()
+ }
notifyDataSetChanged()
}
}
@@ -65,7 +70,8 @@ class AppAdapter(
}
override fun onCreateViewHolder(parent: ViewGroup, i: Int): Holder {
- return Holder(layoutInflater.inflate(R.layout.app_item, parent, false))
+ return Holder(layoutInflater.inflate(R.layout.controls_app_item, parent, false),
+ favoritesRenderer)
}
override fun getItemCount() = listOfServices.size
@@ -80,9 +86,10 @@ class AppAdapter(
/**
* Holder for binding views in the [RecyclerView]-
*/
- class Holder(view: View) : RecyclerView.ViewHolder(view) {
+ class Holder(view: View, val favRenderer: FavoritesRenderer) : RecyclerView.ViewHolder(view) {
private val icon: ImageView = itemView.requireViewById(com.android.internal.R.id.icon)
private val title: TextView = itemView.requireViewById(com.android.internal.R.id.title)
+ private val favorites: TextView = itemView.requireViewById(R.id.favorites)
/**
* Bind data to the view
@@ -91,6 +98,19 @@ class AppAdapter(
fun bindData(data: CandidateInfo) {
icon.setImageDrawable(data.loadIcon())
title.text = data.loadLabel()
+ favorites.text = favRenderer.renderFavoritesForComponent(
+ (data as DefaultAppInfo).componentName)
}
}
+}
+
+class FavoritesRenderer(
+ private val resources: Resources,
+ private val favoriteFunction: (ComponentName) -> Int
+) {
+
+ fun renderFavoritesForComponent(component: ComponentName): String {
+ val qty = favoriteFunction(component)
+ return resources.getQuantityString(R.plurals.controls_number_of_favorites, qty, qty)
+ }
} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt
index e6d3c26ea7b8..65dcc2b193d5 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt
@@ -16,15 +16,20 @@
package com.android.systemui.controls.management
+import android.graphics.Rect
+import android.graphics.drawable.Icon
+import android.service.controls.DeviceTypes
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.CheckBox
+import android.widget.ImageView
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.android.systemui.R
import com.android.systemui.controls.ControlStatus
import com.android.systemui.controls.controller.ControlInfo
+import com.android.systemui.controls.ui.RenderInfo
/**
* Adapter for binding [Control] information to views.
@@ -43,7 +48,12 @@ class ControlAdapter(
var listOfControls = emptyList<ControlStatus>()
override fun onCreateViewHolder(parent: ViewGroup, i: Int): Holder {
- return Holder(layoutInflater.inflate(R.layout.control_item, parent, false))
+ return Holder(layoutInflater.inflate(R.layout.controls_base_item, parent, false).apply {
+ layoutParams.apply {
+ width = ViewGroup.LayoutParams.MATCH_PARENT
+ }
+ elevation = 15f
+ })
}
override fun getItemCount() = listOfControls.size
@@ -56,9 +66,13 @@ class ControlAdapter(
* Holder for binding views in the [RecyclerView]-
*/
class Holder(view: View) : RecyclerView.ViewHolder(view) {
+ private val icon: ImageView = itemView.requireViewById(R.id.icon)
private val title: TextView = itemView.requireViewById(R.id.title)
private val subtitle: TextView = itemView.requireViewById(R.id.subtitle)
- private val favorite: CheckBox = itemView.requireViewById(R.id.favorite)
+ private val removed: TextView = itemView.requireViewById(R.id.status)
+ private val favorite: CheckBox = itemView.requireViewById<CheckBox>(R.id.favorite).apply {
+ visibility = View.VISIBLE
+ }
/**
* Bind data to the view
@@ -68,9 +82,11 @@ class ControlAdapter(
* pre-populated with the [Control] information and the new favorite status.
*/
fun bindData(data: ControlStatus, callback: (ControlInfo.Builder, Boolean) -> Unit) {
+ val renderInfo = getRenderInfo(data.control.deviceType, data.favorite)
title.text = data.control.title
subtitle.text = data.control.subtitle
favorite.isChecked = data.favorite
+ removed.text = if (data.removed) "Removed" else ""
favorite.setOnClickListener {
val infoBuilder = ControlInfo.Builder().apply {
controlId = data.control.controlId
@@ -79,6 +95,25 @@ class ControlAdapter(
}
callback(infoBuilder, favorite.isChecked)
}
+ itemView.setOnClickListener {
+ favorite.performClick()
+ }
+ applyRenderInfo(renderInfo)
+ }
+
+ private fun getRenderInfo(
+ @DeviceTypes.DeviceType deviceType: Int,
+ favorite: Boolean
+ ): RenderInfo {
+ return RenderInfo.lookup(deviceType, favorite)
+ }
+
+ private fun applyRenderInfo(ri: RenderInfo) {
+ val context = itemView.context
+ val fg = context.getResources().getColorStateList(ri.foreground, context.getTheme())
+
+ icon.setImageIcon(Icon.createWithResource(context, ri.iconResourceId))
+ icon.setImageTintList(fg)
}
}
@@ -86,4 +121,23 @@ class ControlAdapter(
listOfControls = list
notifyDataSetChanged()
}
+}
+
+class MarginItemDecorator(
+ private val topMargin: Int,
+ private val sideMargins: Int
+) : RecyclerView.ItemDecoration() {
+
+ override fun getItemOffsets(
+ outRect: Rect,
+ view: View,
+ parent: RecyclerView,
+ state: RecyclerView.State
+ ) {
+ outRect.apply {
+ top = topMargin
+ left = sideMargins
+ right = sideMargins
+ }
+ }
} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt
index 7ee4fd5b059e..be5258344492 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt
@@ -20,8 +20,10 @@ import android.app.Activity
import android.content.ComponentName
import android.os.Bundle
import android.view.LayoutInflater
-import androidx.recyclerview.widget.LinearLayoutManager
+import android.widget.TextView
+import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView
+import com.android.systemui.R
import com.android.systemui.broadcast.BroadcastDispatcher
import com.android.systemui.controls.controller.ControlInfo
import com.android.systemui.controls.controller.ControlsControllerImpl
@@ -44,6 +46,7 @@ class ControlsFavoritingActivity @Inject constructor(
private lateinit var recyclerView: RecyclerView
private lateinit var adapter: ControlAdapter
+ private var component: ComponentName? = null
private val currentUserTracker = object : CurrentUserTracker(broadcastDispatcher) {
private val startingUser = controller.currentUserId
@@ -56,10 +59,9 @@ class ControlsFavoritingActivity @Inject constructor(
}
}
- private var component: ComponentName? = null
-
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
+ setContentView(R.layout.controls_management)
val app = intent.getCharSequenceExtra(EXTRA_APP)
component = intent.getParcelableExtra<ComponentName>(EXTRA_COMPONENT)
@@ -72,17 +74,17 @@ class ControlsFavoritingActivity @Inject constructor(
}
} ?: { _, _ -> Unit }
- recyclerView = RecyclerView(applicationContext)
+ recyclerView = requireViewById(R.id.list)
adapter = ControlAdapter(LayoutInflater.from(applicationContext), callback)
recyclerView.adapter = adapter
- recyclerView.layoutManager = LinearLayoutManager(applicationContext)
+ recyclerView.layoutManager = GridLayoutManager(applicationContext, 2)
+ val margin = resources.getDimensionPixelSize(R.dimen.controls_card_margin)
+ recyclerView.addItemDecoration(MarginItemDecorator(margin, margin))
- if (app != null) {
- setTitle("Controls for $app")
- } else {
- setTitle("Controls")
- }
- setContentView(recyclerView)
+ requireViewById<TextView>(R.id.title).text = app?.let { it }
+ ?: resources.getText(R.string.controls_favorite_default_title)
+ requireViewById<TextView>(R.id.subtitle).text =
+ resources.getText(R.string.controls_favorite_subtitle)
currentUserTracker.startTracking()
}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsProviderSelectorActivity.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsProviderSelectorActivity.kt
index 5ff949c98806..645e929d6a10 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsProviderSelectorActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsProviderSelectorActivity.kt
@@ -20,9 +20,12 @@ import android.content.ComponentName
import android.content.Intent
import android.os.Bundle
import android.view.LayoutInflater
+import android.widget.TextView
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
+import com.android.systemui.R
import com.android.systemui.broadcast.BroadcastDispatcher
+import com.android.systemui.controls.controller.ControlsController
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.settings.CurrentUserTracker
@@ -37,6 +40,7 @@ class ControlsProviderSelectorActivity @Inject constructor(
@Main private val executor: Executor,
@Background private val backExecutor: Executor,
private val listingController: ControlsListingController,
+ private val controlsController: ControlsController,
broadcastDispatcher: BroadcastDispatcher
) : LifecycleActivity() {
@@ -58,13 +62,19 @@ class ControlsProviderSelectorActivity @Inject constructor(
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
+ setContentView(R.layout.controls_management)
- recyclerView = RecyclerView(applicationContext)
+ recyclerView = requireViewById(R.id.list)
recyclerView.adapter = AppAdapter(executor, lifecycle, listingController,
- LayoutInflater.from(this), ::launchFavoritingActivity)
+ LayoutInflater.from(this), ::launchFavoritingActivity,
+ FavoritesRenderer(resources, controlsController::countFavoritesForComponent))
recyclerView.layoutManager = LinearLayoutManager(applicationContext)
- setContentView(recyclerView)
+ requireViewById<TextView>(R.id.title).text =
+ resources.getText(R.string.controls_providers_title)
+ requireViewById<TextView>(R.id.subtitle).text =
+ resources.getText(R.string.controls_providers_subtitle)
+
currentUserTracker.startTracking()
}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt
index 5519e32d6c10..fad2d94d6cf3 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt
@@ -36,8 +36,8 @@ import android.widget.TextView
import com.android.systemui.controls.controller.ControlsController
import com.android.systemui.R
-public const val MIN_LEVEL = 0
-public const val MAX_LEVEL = 10000
+const val MIN_LEVEL = 0
+const val MAX_LEVEL = 10000
class ControlViewHolder(
val layout: ViewGroup,
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/RenderInfo.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/RenderInfo.kt
index 24c8020529ff..093c99f57a9a 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/RenderInfo.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/RenderInfo.kt
@@ -50,7 +50,7 @@ data class RenderInfo(val iconResourceId: Int, val foreground: Int, val backgrou
private const val BUCKET_SIZE = 1000
private const val THERMOSTAT_RANGE = DeviceTypes.TYPE_THERMOSTAT * BUCKET_SIZE
-public val deviceColorMap = mapOf<Int, Pair<Int, Int>>(
+private val deviceColorMap = mapOf<Int, Pair<Int, Int>>(
(THERMOSTAT_RANGE + TemperatureControlTemplate.MODE_HEAT) to
Pair(R.color.thermo_heat_foreground, R.color.thermo_heat_background),
(THERMOSTAT_RANGE + TemperatureControlTemplate.MODE_COOL) to
@@ -60,7 +60,7 @@ public val deviceColorMap = mapOf<Int, Pair<Int, Int>>(
Pair(R.color.control_foreground, R.color.control_background)
}
-public val deviceIconMap = mapOf<Int, IconState>(
+private val deviceIconMap = mapOf<Int, IconState>(
THERMOSTAT_RANGE to IconState(
R.drawable.ic_device_thermostat_gm2_24px,
R.drawable.ic_device_thermostat_gm2_24px
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DefaultComponentBinder.java b/packages/SystemUI/src/com/android/systemui/dagger/DefaultComponentBinder.java
index 18fe3ec92827..50252460d5c1 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/DefaultComponentBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/DefaultComponentBinder.java
@@ -25,7 +25,6 @@ import dagger.Module;
*/
@Module(includes = {DefaultActivityBinder.class,
DefaultBroadcastReceiverBinder.class,
- DefaultServiceBinder.class,
- SystemUIBinder.class})
+ DefaultServiceBinder.class})
public abstract class DefaultComponentBinder {
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java
index 5c171e41db41..a57ec5b483dd 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java
@@ -56,7 +56,7 @@ import dagger.Provides;
* overridden by the System UI implementation.
*/
@Module(includes = {DividerModule.class})
-abstract class SystemUIDefaultModule {
+public abstract class SystemUIDefaultModule {
@Singleton
@Provides
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIRootComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIRootComponent.java
index e8509b366c5b..3bf5ad759267 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIRootComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIRootComponent.java
@@ -45,6 +45,7 @@ import dagger.Component;
DependencyBinder.class,
SystemServicesModule.class,
SystemUIFactory.ContextHolder.class,
+ SystemUIBinder.class,
SystemUIModule.class,
SystemUIDefaultModule.class})
public interface SystemUIRootComponent {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSColorController.kt b/packages/SystemUI/src/com/android/systemui/qs/QSColorController.kt
deleted file mode 100644
index 3f0c5bb7f620..000000000000
--- a/packages/SystemUI/src/com/android/systemui/qs/QSColorController.kt
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.qs
-
-import android.content.ContentResolver
-import android.database.ContentObserver
-import android.net.Uri
-import android.os.Handler
-import android.os.Looper
-import android.provider.Settings
-import android.util.Log
-import com.android.systemui.plugins.qs.QSTile
-
-private const val TAG = "QSColorController"
-private const val QS_COLOR_ICON = "qs_color_icon"
-private const val QS_COLOR_ENABLED = "qs_color_enabled"
-private const val QS_COLOR_OVERRIDDEN_TILES = "qs_color_overridden_tiles"
-private val qsColorIconUri = Settings.System.getUriFor(QS_COLOR_ICON)
-private val qsColorEnabledUri = Settings.System.getUriFor(QS_COLOR_ENABLED)
-class QSColorController private constructor() {
-
- private var overrideColor = false
- private var colorIcon = false
- private lateinit var colorCache: SettingBackedMap
-
- companion object {
- val instance = QSColorController()
- internal fun overrideColor() = instance.overrideColor
- internal fun colorIcon() = instance.colorIcon
-
- @QSTile.ColorTile
- private fun getColorFromSetting(setting: String): Int {
- return when (setting.toLowerCase()) {
- "red" -> QSTile.COLOR_TILE_RED
- "blue" -> QSTile.COLOR_TILE_BLUE
- "green" -> QSTile.COLOR_TILE_GREEN
- "yellow" -> QSTile.COLOR_TILE_YELLOW
- else -> QSTile.COLOR_TILE_ACCENT
- }
- }
- }
-
- private fun getBooleanSetting(key: String, default: Boolean = false): Boolean =
- try {
- Settings.System.getInt(contentResolver, key) != 0
- } catch (_: Settings.SettingNotFoundException) {
- default
- }
-
- private lateinit var tileHost: QSHost
- private lateinit var contentResolver: ContentResolver
-
- fun initQSTileHost(host: QSHost) {
- tileHost = host
- contentResolver = tileHost.context.contentResolver
- colorCache = SettingBackedMap(contentResolver, mutableMapOf())
- colorIcon = getBooleanSetting(QS_COLOR_ICON)
- overrideColor = getBooleanSetting(QS_COLOR_ENABLED)
- readExistingSettings()
- contentResolver.registerContentObserver(qsColorEnabledUri, true, settingsListener)
- contentResolver.registerContentObserver(qsColorIconUri, false, settingsListener)
- }
-
- private fun readExistingSettings() {
- Settings.System.getString(contentResolver, QS_COLOR_OVERRIDDEN_TILES)?.split(",")
- ?.mapNotNull { spec ->
- Settings.System.getString(contentResolver, "$QS_COLOR_ENABLED/$spec")?.let {
- spec to it
- }
- }?.forEach {
- modifyTileColor(it.first, getColorFromSetting(it.second))
- }
- }
-
- private val settingsListener = object : ContentObserver(Handler(Looper.getMainLooper())) {
- override fun onChange(selfChange: Boolean, uri: Uri) {
- super.onChange(selfChange, uri)
- when (uri) {
- qsColorIconUri -> colorIcon = getBooleanSetting(QS_COLOR_ICON)
- qsColorEnabledUri -> overrideColor = getBooleanSetting(QS_COLOR_ENABLED)
- else -> {
- uri.path?.drop("/system/".length)?.let {
- val color = getColorFromSetting(
- Settings.System.getString(contentResolver, it) ?: "accent")
- val tileSpec = uri.lastPathSegment ?: ""
- modifyTileColor(tileSpec, color)
- }
- }
- }
- }
- }
-
- private fun modifyTileColor(spec: String, @QSTile.ColorTile color: Int) {
- Log.w(TAG, "Setting color of tile $spec to $color")
- colorCache.put(spec, color)
- tileHost.tiles.firstOrNull { it.tileSpec == spec }?.setColor(color)
- }
-
- fun applyColorToTile(tile: QSTile) {
- colorCache.get(tile.tileSpec)?.let {
- modifyTileColor(tile.tileSpec, it)
- }
- }
-
- fun applyColorToAllTiles() = tileHost.tiles.forEach(::applyColorToTile)
-
- fun destroy() {
- contentResolver.unregisterContentObserver(settingsListener)
- }
-
- class SettingBackedMap(
- private val contentResolver: ContentResolver,
- private val map: MutableMap<String, Int>
- ) : MutableMap<String, @QSTile.ColorTile Int> by map {
- override fun put(key: String, @QSTile.ColorTile value: Int): Int? {
- return map.put(key, value).also {
- Settings.System.putString(contentResolver, QS_COLOR_OVERRIDDEN_TILES,
- map.filterValues { it != QSTile.COLOR_TILE_ACCENT }
- .keys
- .joinToString(","))
- }
- }
- }
-}
-fun overrideColor() = QSColorController.overrideColor()
-fun colorIcon() = QSColorController.colorIcon() \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
index f71150fc348c..00e09f8d4725 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
@@ -90,8 +90,6 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D
private int mCurrentUser;
private final Optional<StatusBar> mStatusBarOptional;
- private QSColorController mQSColorController = QSColorController.Companion.getInstance();
-
@Inject
public QSTileHost(Context context,
StatusBarIconController iconController,
@@ -127,8 +125,6 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D
// AutoTileManager can modify mTiles so make sure mTiles has already been initialized.
mAutoTiles = autoTiles.get();
});
-
- mQSColorController.initQSTileHost(this);
}
public StatusBarIconController getIconController() {
@@ -142,8 +138,6 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D
mServices.destroy();
mPluginManager.removePluginListener(this);
mDumpController.unregisterDumpable(this);
-
- mQSColorController.destroy();
}
@Override
@@ -280,8 +274,6 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D
mCallbacks.get(i).onTilesChanged();
}
}
-
- mQSColorController.applyColorToAllTiles();
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java
index 88c7964144c1..31526bf8f5e1 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java
@@ -14,12 +14,10 @@
package com.android.systemui.qs.tileimpl;
-import static com.android.systemui.qs.QSColorControllerKt.colorIcon;
import static com.android.systemui.qs.tileimpl.QSTileImpl.getColorForState;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
-import android.animation.ArgbEvaluator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.ColorStateList;
@@ -150,15 +148,10 @@ public class QSIconViewImpl extends QSIconView {
iv.clearColorFilter();
}
if (state.state != mState) {
- int color = getColor(state.state, state.colorActive);
+ int color = getColor(state.state);
mState = state.state;
if (mTint != 0 && allowAnimations && shouldAnimate(iv)) {
- if (colorIcon()) {
- animateColor(mTint, color, iv, () -> updateIcon(iv, state, allowAnimations));
- } else {
- animateGrayScale(mTint, color, iv,
- () -> updateIcon(iv, state, allowAnimations));
- }
+ animateGrayScale(mTint, color, iv, () -> updateIcon(iv, state, allowAnimations));
mTint = color;
} else {
if (iv instanceof AlphaControlledSlashImageView) {
@@ -175,12 +168,8 @@ public class QSIconViewImpl extends QSIconView {
}
}
- protected int getColor(int state, int colorActive) {
- return getColorForState(getContext(), state, colorActive);
- }
-
protected int getColor(int state) {
- return getColor(state, -1);
+ return getColorForState(getContext(), state);
}
private void animateGrayScale(int fromColor, int toColor, ImageView iv,
@@ -217,37 +206,6 @@ public class QSIconViewImpl extends QSIconView {
}
}
- private void animateColor(int fromColor, int toColor, ImageView iv,
- final Runnable endRunnable) {
- if (iv instanceof AlphaControlledSlashImageView) {
- ((AlphaControlledSlashImageView) iv)
- .setFinalImageTintList(ColorStateList.valueOf(toColor));
- }
- if (mAnimationEnabled && ValueAnimator.areAnimatorsEnabled()) {
-
-
- ValueAnimator anim = ValueAnimator.ofFloat(0, 1);
- anim.setDuration(QS_ANIM_LENGTH);
- anim.addUpdateListener(animation -> {
- float fraction = animation.getAnimatedFraction();
- int color = (int) ArgbEvaluator.getInstance().evaluate(fraction, fromColor,
- toColor);
-
- setTint(iv, color);
- });
- anim.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- endRunnable.run();
- }
- });
- anim.start();
- } else {
- setTint(iv, toColor);
- endRunnable.run();
- }
- }
-
public static void setTint(ImageView iv, int color) {
iv.setImageTintList(ColorStateList.valueOf(color));
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileBaseView.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileBaseView.java
index 8b7f280608a5..2fe64d26f3ac 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileBaseView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileBaseView.java
@@ -13,8 +13,6 @@
*/
package com.android.systemui.qs.tileimpl;
-import static com.android.systemui.qs.QSColorControllerKt.colorIcon;
-import static com.android.systemui.qs.QSColorControllerKt.overrideColor;
import static com.android.systemui.qs.tileimpl.QSIconViewImpl.QS_ANIM_LENGTH;
import android.animation.ValueAnimator;
@@ -76,8 +74,6 @@ public class QSTileBaseView extends com.android.systemui.plugins.qs.QSTileView {
private int mCircleColor;
private int mBgSize;
- private final boolean mQsColors = overrideColor();
- private final boolean mQSIcons = colorIcon();
public QSTileBaseView(Context context, QSIconView icon) {
this(context, icon, false);
@@ -212,7 +208,7 @@ public class QSTileBaseView extends com.android.systemui.plugins.qs.QSTileView {
}
protected void handleStateChanged(QSTile.State state) {
- int circleColor = getCircleColor(state.state, mQsColors ? state.colorActive : -1);
+ int circleColor = getCircleColor(state.state);
boolean allowAnimations = animationsEnabled();
if (circleColor != mCircleColor) {
if (allowAnimations) {
@@ -259,11 +255,10 @@ public class QSTileBaseView extends com.android.systemui.plugins.qs.QSTileView {
return mLocInScreen[1] >= -getHeight();
}
- private int getCircleColor(int state, int colorActive) {
+ private int getCircleColor(int state) {
switch (state) {
case Tile.STATE_ACTIVE:
- int color = (colorActive == -1) ? mColorActive : colorActive;
- return mQsColors && mQSIcons ? Utils.applyAlpha(0.5f, color) : color;
+ return mColorActive;
case Tile.STATE_INACTIVE:
case Tile.STATE_UNAVAILABLE:
return mColorDisabled;
@@ -273,10 +268,6 @@ public class QSTileBaseView extends com.android.systemui.plugins.qs.QSTileView {
}
}
- private int getCircleColor(int state) {
- return getCircleColor(state, -1);
- }
-
@Override
public void setClickable(boolean clickable) {
super.setClickable(clickable);
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 1d379110325a..e1b61c670a12 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
@@ -26,7 +26,6 @@ import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_STATUS_BAR_STATE;
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_ACTION;
import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
-import static com.android.systemui.qs.QSColorControllerKt.colorIcon;
import android.app.ActivityManager;
import android.content.Context;
@@ -55,7 +54,6 @@ import com.android.settingslib.Utils;
import com.android.systemui.Dependency;
import com.android.systemui.Dumpable;
import com.android.systemui.Prefs;
-import com.android.systemui.R;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.qs.DetailAdapter;
import com.android.systemui.plugins.qs.QSIconView;
@@ -432,10 +430,6 @@ public abstract class QSTileImpl<TState extends State> implements QSTile, Lifecy
public abstract CharSequence getTileLabel();
public static int getColorForState(Context context, int state) {
- return getColorForState(context, state, -1);
- }
-
- public static int getColorForState(Context context, int state, int colorActive) {
switch (state) {
case Tile.STATE_UNAVAILABLE:
return Utils.getDisabled(context,
@@ -443,25 +437,13 @@ public abstract class QSTileImpl<TState extends State> implements QSTile, Lifecy
case Tile.STATE_INACTIVE:
return Utils.getColorAttrDefaultColor(context, android.R.attr.textColorSecondary);
case Tile.STATE_ACTIVE:
- return getActiveColor(context, colorActive);
+ return Utils.getColorAttrDefaultColor(context, android.R.attr.colorPrimary);
default:
Log.e("QSTile", "Invalid state " + state);
return 0;
}
}
- private static int getActiveColor(Context context, int colorActive) {
- if (colorIcon()) {
- if (colorActive == -1) {
- return Utils.getColorAccentDefaultColor(context);
- } else {
- return colorActive;
- }
- } else {
- return Utils.getColorAttrDefaultColor(context, android.R.attr.colorPrimary);
- }
- }
-
protected final class H extends Handler {
private static final int ADD_CALLBACK = 1;
private static final int CLICK = 2;
@@ -645,27 +627,4 @@ public abstract class QSTileImpl<TState extends State> implements QSTile, Lifecy
pw.println(this.getClass().getSimpleName() + ":");
pw.print(" "); pw.println(getState().toString());
}
-
- @Override
- public void setColor(@ColorTile int color) {
- int resId;
- switch(color) {
- case COLOR_TILE_RED:
- resId = R.color.GM2_red_500;
- break;
- case COLOR_TILE_BLUE:
- resId = R.color.GM2_blue_500;
- break;
- case COLOR_TILE_GREEN:
- resId = R.color.GM2_green_500;
- break;
- case COLOR_TILE_YELLOW:
- resId = R.color.GM2_yellow_500;
- break;
- default:
- resId = -1;
- }
- mTmpState.colorActive = resId == -1 ? -1 : mContext.getColor(resId);
- refreshState();
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoveInterceptor.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoveInterceptor.java
index 930116ee4ae7..caa1e2db6ac0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoveInterceptor.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoveInterceptor.java
@@ -16,8 +16,12 @@
package com.android.systemui.statusbar;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.service.notification.NotificationListenerService;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+
/**
* Interface for anything that may need to prevent notifications from being removed. This is
* similar to a {@link NotificationLifetimeExtender} in the sense that it extends the life of
@@ -30,11 +34,15 @@ public interface NotificationRemoveInterceptor {
/**
* Called when a notification has been removed.
*
- * @param key the entry key of the notification being removed.
+ * @param key the key of the notification being removed. Never null
+ * @param entry the entry of the notification being removed.
* @param removeReason why the notification is being removed, e.g.
* {@link NotificationListenerService#REASON_CANCEL} or 0 if unknown.
*
* @return true if the removal should be ignored, false otherwise.
*/
- boolean onNotificationRemoveRequested(String key, int removeReason);
+ boolean onNotificationRemoveRequested(
+ @NonNull String key,
+ @Nullable NotificationEntry entry,
+ int removeReason);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
index 8d4a9efbcd7a..37f9f88f6328 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
@@ -34,6 +34,7 @@ import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.VisualStabilityManager;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
+import com.android.systemui.statusbar.notification.stack.ForegroundServiceSectionController;
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
@@ -81,6 +82,7 @@ public class NotificationViewHierarchyManager implements DynamicPrivacyControlle
private final BubbleController mBubbleController;
private final DynamicPrivacyController mDynamicPrivacyController;
private final KeyguardBypassController mBypassController;
+ private final ForegroundServiceSectionController mFgsSectionController;
private final Context mContext;
private NotificationPresenter mPresenter;
@@ -101,7 +103,9 @@ public class NotificationViewHierarchyManager implements DynamicPrivacyControlle
NotificationEntryManager notificationEntryManager,
KeyguardBypassController bypassController,
BubbleController bubbleController,
- DynamicPrivacyController privacyController) {
+ DynamicPrivacyController privacyController,
+ ForegroundServiceSectionController fgsSectionController
+ ) {
mContext = context;
mHandler = mainHandler;
mLockscreenUserManager = notificationLockscreenUserManager;
@@ -110,6 +114,7 @@ public class NotificationViewHierarchyManager implements DynamicPrivacyControlle
mVisualStabilityManager = visualStabilityManager;
mStatusBarStateController = (SysuiStatusBarStateController) statusBarStateController;
mEntryManager = notificationEntryManager;
+ mFgsSectionController = fgsSectionController;
Resources res = context.getResources();
mAlwaysExpandNonGroupedNotification =
res.getBoolean(R.bool.config_alwaysExpandNonGroupedNotifications);
@@ -140,7 +145,8 @@ public class NotificationViewHierarchyManager implements DynamicPrivacyControlle
boolean hideMedia = Utils.useQsMediaPlayer(mContext);
if (ent.isRowDismissed() || ent.isRowRemoved()
|| (ent.isMediaNotification() && hideMedia)
- || mBubbleController.isBubbleNotificationSuppressedFromShade(ent)) {
+ || mBubbleController.isBubbleNotificationSuppressedFromShade(ent)
+ || mFgsSectionController.hasEntry(ent)) {
// we don't want to update removed notifications because they could
// temporarily become children if they were isolated before.
continue;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ForegroundServiceDismissalFeatureController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ForegroundServiceDismissalFeatureController.kt
new file mode 100644
index 000000000000..b1d6b40fcc1e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ForegroundServiceDismissalFeatureController.kt
@@ -0,0 +1,49 @@
+/*
+ * 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.statusbar.notification
+
+import android.content.Context
+import android.provider.DeviceConfig
+import com.android.internal.config.sysui.SystemUiDeviceConfigFlags.NOTIFICATIONS_ALLOW_FGS_DISMISSAL
+import com.android.systemui.util.DeviceConfigProxy
+import javax.inject.Inject
+import javax.inject.Singleton
+
+private var sIsEnabled: Boolean? = null
+
+/**
+ * Feature controller for NOTIFICATIONS_ALLOW_FGS_DISMISSAL config.
+ */
+// TODO: this is really boilerplatey, make a base class that just wraps the device config
+@Singleton
+class ForegroundServiceDismissalFeatureController @Inject constructor(
+ val proxy: DeviceConfigProxy,
+ val context: Context
+) {
+ fun isForegroundServiceDismissalEnabled(): Boolean {
+ return isEnabled(proxy)
+ }
+}
+
+private fun isEnabled(proxy: DeviceConfigProxy): Boolean {
+ if (sIsEnabled == null) {
+ sIsEnabled = proxy.getBoolean(
+ DeviceConfig.NAMESPACE_SYSTEMUI, NOTIFICATIONS_ALLOW_FGS_DISMISSAL, false)
+ }
+
+ return sIsEnabled!!
+} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
index 4a2283171694..6bb377e89278 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
@@ -135,6 +135,7 @@ public class NotificationEntryManager implements
private final NotificationGroupManager mGroupManager;
private final NotificationRankingManager mRankingManager;
private final FeatureFlags mFeatureFlags;
+ private final ForegroundServiceDismissalFeatureController mFgsFeatureController;
private NotificationPresenter mPresenter;
private RankingMap mLatestRankingMap;
@@ -144,7 +145,7 @@ public class NotificationEntryManager implements
final ArrayList<NotificationLifetimeExtender> mNotificationLifetimeExtenders
= new ArrayList<>();
private final List<NotificationEntryListener> mNotificationEntryListeners = new ArrayList<>();
- private NotificationRemoveInterceptor mRemoveInterceptor;
+ private final List<NotificationRemoveInterceptor> mRemoveInterceptors = new ArrayList<>();
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
@@ -157,6 +158,14 @@ public class NotificationEntryManager implements
pw.println(entry.getSbn());
}
}
+ pw.println(" Remove interceptors registered:");
+ for (NotificationRemoveInterceptor interceptor : mRemoveInterceptors) {
+ pw.println(" " + interceptor.getClass().getSimpleName());
+ }
+ pw.println(" Lifetime extenders registered:");
+ for (NotificationLifetimeExtender extender : mNotificationLifetimeExtenders) {
+ pw.println(" " + extender.getClass().getSimpleName());
+ }
pw.println(" Lifetime-extended notifications:");
if (mRetainedNotifications.isEmpty()) {
pw.println(" None");
@@ -178,7 +187,8 @@ public class NotificationEntryManager implements
FeatureFlags featureFlags,
Lazy<NotificationRowBinder> notificationRowBinderLazy,
Lazy<NotificationRemoteInputManager> notificationRemoteInputManagerLazy,
- LeakDetector leakDetector) {
+ LeakDetector leakDetector,
+ ForegroundServiceDismissalFeatureController fgsFeatureController) {
mNotifLog = notifLog;
mGroupManager = groupManager;
mRankingManager = rankingManager;
@@ -187,6 +197,7 @@ public class NotificationEntryManager implements
mNotificationRowBinderLazy = notificationRowBinderLazy;
mRemoteInputManagerLazy = notificationRemoteInputManagerLazy;
mLeakDetector = leakDetector;
+ mFgsFeatureController = fgsFeatureController;
}
/** Once called, the NEM will start processing notification events from system server. */
@@ -207,9 +218,14 @@ public class NotificationEntryManager implements
mNotificationEntryListeners.remove(listener);
}
- /** Sets the {@link NotificationRemoveInterceptor}. */
- public void setNotificationRemoveInterceptor(NotificationRemoveInterceptor interceptor) {
- mRemoveInterceptor = interceptor;
+ /** Add a {@link NotificationRemoveInterceptor}. */
+ public void addNotificationRemoveInterceptor(NotificationRemoveInterceptor interceptor) {
+ mRemoveInterceptors.add(interceptor);
+ }
+
+ /** Remove a {@link NotificationRemoveInterceptor} */
+ public void removeNotificationRemoveInterceptor(NotificationRemoveInterceptor interceptor) {
+ mRemoveInterceptors.remove(interceptor);
}
public void setUpWithPresenter(NotificationPresenter presenter,
@@ -398,14 +414,16 @@ public class NotificationEntryManager implements
boolean removedByUser,
int reason) {
- if (mRemoveInterceptor != null
- && mRemoveInterceptor.onNotificationRemoveRequested(key, reason)) {
- // Remove intercepted; log and skip
- mNotifLog.log(NotifEvent.REMOVE_INTERCEPTED);
- return;
+ final NotificationEntry entry = getActiveNotificationUnfiltered(key);
+
+ for (NotificationRemoveInterceptor interceptor : mRemoveInterceptors) {
+ if (interceptor.onNotificationRemoveRequested(key, entry, reason)) {
+ // Remove intercepted; log and skip
+ mNotifLog.log(NotifEvent.REMOVE_INTERCEPTED);
+ return;
+ }
}
- final NotificationEntry entry = getActiveNotificationUnfiltered(key);
boolean lifetimeExtended = false;
// Notification was canceled before it got inflated
@@ -528,7 +546,10 @@ public class NotificationEntryManager implements
Ranking ranking = new Ranking();
rankingMap.getRanking(key, ranking);
- NotificationEntry entry = new NotificationEntry(notification, ranking);
+ NotificationEntry entry = new NotificationEntry(
+ notification,
+ ranking,
+ mFgsFeatureController.isForegroundServiceDismissalEnabled());
mLeakDetector.trackInstance(entry);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListDumper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListDumper.java
index eaa9d78c08f4..7fe229c26f3a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListDumper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListDumper.java
@@ -16,6 +16,9 @@
package com.android.systemui.statusbar.notification.collection;
+import static com.android.systemui.statusbar.notification.collection.NotifCollection.REASON_NOT_CANCELED;
+import static com.android.systemui.statusbar.notification.collection.NotificationEntry.DismissState.NOT_DISMISSED;
+
import java.util.Arrays;
import java.util.List;
@@ -132,8 +135,20 @@ public class ListDumper {
.append(" ");
}
+ if (notifEntry.mCancellationReason != REASON_NOT_CANCELED) {
+ rksb.append("cancellationReason=")
+ .append(notifEntry.mCancellationReason)
+ .append(" ");
+ }
+
if (notifEntry.hasInflationError()) {
- rksb.append("hasInflationError ");
+ rksb.append("(!)hasInflationError ");
+ }
+
+ if (notifEntry.getDismissState() != NOT_DISMISSED) {
+ rksb.append("dismissState=")
+ .append(notifEntry.getDismissState())
+ .append(" ");
}
String rkString = rksb.toString();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java
index 1b6170326bac..3b2fe9441c32 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java
@@ -35,9 +35,14 @@ import static android.service.notification.NotificationListenerService.REASON_TI
import static android.service.notification.NotificationListenerService.REASON_UNAUTOBUNDLED;
import static android.service.notification.NotificationListenerService.REASON_USER_STOPPED;
+import static com.android.systemui.statusbar.notification.collection.NotificationEntry.DismissState.DISMISSED;
+import static com.android.systemui.statusbar.notification.collection.NotificationEntry.DismissState.NOT_DISMISSED;
+import static com.android.systemui.statusbar.notification.collection.NotificationEntry.DismissState.PARENT_DISMISSED;
+
+import static java.util.Objects.requireNonNull;
+
import android.annotation.IntDef;
import android.annotation.MainThread;
-import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.RemoteException;
import android.service.notification.NotificationListenerService.Ranking;
@@ -45,6 +50,8 @@ import android.service.notification.NotificationListenerService.RankingMap;
import android.service.notification.StatusBarNotification;
import android.util.ArrayMap;
+import androidx.annotation.NonNull;
+
import com.android.internal.statusbar.IStatusBarService;
import com.android.systemui.DumpController;
import com.android.systemui.Dumpable;
@@ -172,15 +179,65 @@ public class NotifCollection implements Dumpable {
/**
* Dismiss a notification on behalf of the user.
*/
- void dismissNotification(
- NotificationEntry entry,
- @CancellationReason int reason,
- @NonNull DismissedByUserStats stats) {
+ void dismissNotification(NotificationEntry entry, @NonNull DismissedByUserStats stats) {
Assert.isMainThread();
- Objects.requireNonNull(stats);
+ requireNonNull(stats);
checkForReentrantCall();
- removeNotification(entry.getKey(), null, reason, stats);
+ if (entry != mNotificationSet.get(entry.getKey())) {
+ throw new IllegalStateException("Invalid entry: " + entry.getKey());
+ }
+
+ if (entry.getDismissState() == DISMISSED) {
+ return;
+ }
+
+ // Optimistically mark the notification as dismissed -- we'll wait for the signal from
+ // system server before removing it from our notification set.
+ entry.setDismissState(DISMISSED);
+ mLogger.logNotifDismissed(entry.getKey());
+
+ List<NotificationEntry> canceledEntries = new ArrayList<>();
+
+ if (isCanceled(entry)) {
+ canceledEntries.add(entry);
+ } else {
+ // Ask system server to remove it for us
+ try {
+ mStatusBarService.onNotificationClear(
+ entry.getSbn().getPackageName(),
+ entry.getSbn().getTag(),
+ entry.getSbn().getId(),
+ entry.getSbn().getUser().getIdentifier(),
+ entry.getSbn().getKey(),
+ stats.dismissalSurface,
+ stats.dismissalSentiment,
+ stats.notificationVisibility);
+ } catch (RemoteException e) {
+ // system process is dead if we're here.
+ }
+
+ // Also mark any children as dismissed as system server will auto-dismiss them as well
+ if (entry.getSbn().getNotification().isGroupSummary()) {
+ for (NotificationEntry otherEntry : mNotificationSet.values()) {
+ if (otherEntry.getSbn().getGroupKey().equals(entry.getSbn().getGroupKey())
+ && otherEntry.getDismissState() != DISMISSED) {
+ otherEntry.setDismissState(PARENT_DISMISSED);
+ if (isCanceled(otherEntry)) {
+ canceledEntries.add(otherEntry);
+ }
+ }
+ }
+ }
+ }
+
+ // Immediately remove any dismissed notifs that have already been canceled by system server
+ // (probably due to being lifetime-extended up until this point).
+ for (NotificationEntry canceledEntry : canceledEntries) {
+ tryRemoveNotification(canceledEntry);
+ }
+
+ rebuildList();
}
private void onNotificationPosted(StatusBarNotification sbn, RankingMap rankingMap) {
@@ -208,7 +265,15 @@ public class NotifCollection implements Dumpable {
Assert.isMainThread();
mLogger.logNotifRemoved(sbn.getKey(), reason);
- removeNotification(sbn.getKey(), rankingMap, reason, null);
+
+ final NotificationEntry entry = mNotificationSet.get(sbn.getKey());
+ if (entry == null) {
+ throw new IllegalStateException("No notification to remove with key " + sbn.getKey());
+ }
+ entry.mCancellationReason = reason;
+ applyRanking(rankingMap);
+ tryRemoveNotification(entry);
+ rebuildList();
}
private void onNotificationRankingUpdate(RankingMap rankingMap) {
@@ -242,9 +307,12 @@ public class NotifCollection implements Dumpable {
// Update to an existing entry
mLogger.logNotifUpdated(sbn.getKey());
- // Notification is updated so it is essentially re-added and thus alive again. Don't
+ cancelLocalDismissal(entry);
+
+ // Notification is updated so it is essentially re-added and thus alive again. Don't
// need to keep its lifetime extended.
cancelLifetimeExtension(entry);
+ entry.mCancellationReason = REASON_NOT_CANCELED;
entry.setSbn(sbn);
if (rankingMap != null) {
@@ -255,59 +323,42 @@ public class NotifCollection implements Dumpable {
}
}
- private void removeNotification(
- String key,
- @Nullable RankingMap rankingMap,
- @CancellationReason int reason,
- @Nullable DismissedByUserStats dismissedByUserStats) {
+ /**
+ * Tries to remove a notification from the notification set. This removal may be blocked by
+ * lifetime extenders. Does not trigger a rebuild of the list; caller must do that manually.
+ *
+ * @return True if the notification was removed, false otherwise.
+ */
+ private boolean tryRemoveNotification(NotificationEntry entry) {
+ if (mNotificationSet.get(entry.getKey()) != entry) {
+ throw new IllegalStateException("No notification to remove with key " + entry.getKey());
+ }
- NotificationEntry entry = mNotificationSet.get(key);
- if (entry == null) {
- throw new IllegalStateException("No notification to remove with key " + key);
+ if (!isCanceled(entry)) {
+ throw new IllegalStateException("Cannot remove notification " + entry.getKey()
+ + ": has not been marked for removal");
}
- entry.mLifetimeExtenders.clear();
- mAmDispatchingToOtherCode = true;
- for (NotifLifetimeExtender extender : mLifetimeExtenders) {
- if (extender.shouldExtendLifetime(entry, reason)) {
- entry.mLifetimeExtenders.add(extender);
- }
+ if (isDismissedByUser(entry)) {
+ // User-dismissed notifications cannot be lifetime-extended
+ cancelLifetimeExtension(entry);
+ } else {
+ updateLifetimeExtension(entry);
}
- mAmDispatchingToOtherCode = false;
if (!isLifetimeExtended(entry)) {
mNotificationSet.remove(entry.getKey());
-
- if (dismissedByUserStats != null) {
- try {
- mStatusBarService.onNotificationClear(
- entry.getSbn().getPackageName(),
- entry.getSbn().getTag(),
- entry.getSbn().getId(),
- entry.getSbn().getUser().getIdentifier(),
- entry.getSbn().getKey(),
- dismissedByUserStats.dismissalSurface,
- dismissedByUserStats.dismissalSentiment,
- dismissedByUserStats.notificationVisibility);
- } catch (RemoteException e) {
- // system process is dead if we're here.
- }
- }
-
- if (rankingMap != null) {
- applyRanking(rankingMap);
- }
-
- dispatchOnEntryRemoved(entry, reason, dismissedByUserStats != null /* removedByUser */);
+ dispatchOnEntryRemoved(entry, entry.mCancellationReason);
dispatchOnEntryCleanUp(entry);
+ return true;
+ } else {
+ return false;
}
-
- rebuildList();
}
private void applyRanking(@NonNull RankingMap rankingMap) {
for (NotificationEntry entry : mNotificationSet.values()) {
- if (!isLifetimeExtended(entry)) {
+ if (!isCanceled(entry)) {
// TODO: (b/148791039) We should crash if we are ever handed a ranking with
// incomplete entries. Right now, there's a race condition in NotificationListener
@@ -355,9 +406,9 @@ public class NotifCollection implements Dumpable {
}
if (!isLifetimeExtended(entry)) {
- // TODO: This doesn't need to be undefined -- we can set either EXTENDER_EXPIRED or
- // save the original reason
- removeNotification(entry.getKey(), null, REASON_UNKNOWN, null);
+ if (tryRemoveNotification(entry)) {
+ rebuildList();
+ }
}
}
@@ -374,6 +425,31 @@ public class NotifCollection implements Dumpable {
return entry.mLifetimeExtenders.size() > 0;
}
+ private void updateLifetimeExtension(NotificationEntry entry) {
+ entry.mLifetimeExtenders.clear();
+ mAmDispatchingToOtherCode = true;
+ for (NotifLifetimeExtender extender : mLifetimeExtenders) {
+ if (extender.shouldExtendLifetime(entry, entry.mCancellationReason)) {
+ entry.mLifetimeExtenders.add(extender);
+ }
+ }
+ mAmDispatchingToOtherCode = false;
+ }
+
+ private void cancelLocalDismissal(NotificationEntry entry) {
+ if (isDismissedByUser(entry)) {
+ entry.setDismissState(NOT_DISMISSED);
+ if (entry.getSbn().getNotification().isGroupSummary()) {
+ for (NotificationEntry otherEntry : mNotificationSet.values()) {
+ if (otherEntry.getSbn().getGroupKey().equals(entry.getSbn().getGroupKey())
+ && otherEntry.getDismissState() == PARENT_DISMISSED) {
+ otherEntry.setDismissState(NOT_DISMISSED);
+ }
+ }
+ }
+ }
+ }
+
private void checkForReentrantCall() {
if (mAmDispatchingToOtherCode) {
throw new IllegalStateException("Reentrant call detected");
@@ -389,6 +465,19 @@ public class NotifCollection implements Dumpable {
return ranking;
}
+ /**
+ * True if the notification has been canceled by system server. Usually, such notifications are
+ * immediately removed from the collection, but can sometimes stick around due to lifetime
+ * extenders.
+ */
+ private static boolean isCanceled(NotificationEntry entry) {
+ return entry.mCancellationReason != REASON_NOT_CANCELED;
+ }
+
+ private static boolean isDismissedByUser(NotificationEntry entry) {
+ return entry.getDismissState() != NOT_DISMISSED;
+ }
+
private void dispatchOnEntryInit(NotificationEntry entry) {
mAmDispatchingToOtherCode = true;
for (NotifCollectionListener listener : mNotifCollectionListeners) {
@@ -421,13 +510,10 @@ public class NotifCollection implements Dumpable {
mAmDispatchingToOtherCode = false;
}
- private void dispatchOnEntryRemoved(
- NotificationEntry entry,
- @CancellationReason int reason,
- boolean removedByUser) {
+ private void dispatchOnEntryRemoved(NotificationEntry entry, @CancellationReason int reason) {
mAmDispatchingToOtherCode = true;
for (NotifCollectionListener listener : mNotifCollectionListeners) {
- listener.onEntryRemoved(entry, reason, removedByUser);
+ listener.onEntryRemoved(entry, reason);
}
mAmDispatchingToOtherCode = false;
}
@@ -439,6 +525,20 @@ public class NotifCollection implements Dumpable {
}
mAmDispatchingToOtherCode = false;
}
+ @Override
+ public void dump(@NonNull FileDescriptor fd, PrintWriter pw, @NonNull String[] args) {
+ final List<NotificationEntry> entries = new ArrayList<>(getActiveNotifs());
+
+ pw.println("\t" + TAG + " unsorted/unfiltered notifications:");
+ if (entries.size() == 0) {
+ pw.println("\t\t None");
+ }
+ pw.println(
+ ListDumper.dumpList(
+ entries,
+ true,
+ "\t\t"));
+ }
private final BatchableNotificationHandler mNotifHandler = new BatchableNotificationHandler() {
@Override
@@ -494,20 +594,6 @@ public class NotifCollection implements Dumpable {
@Retention(RetentionPolicy.SOURCE)
public @interface CancellationReason {}
+ public static final int REASON_NOT_CANCELED = -1;
public static final int REASON_UNKNOWN = 0;
-
- @Override
- public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- final List<NotificationEntry> entries = new ArrayList<>(getActiveNotifs());
-
- pw.println("\t" + TAG + " unsorted/unfiltered notifications:");
- if (entries.size() == 0) {
- pw.println("\t\t None");
- }
- pw.println(
- ListDumper.dumpList(
- entries,
- true,
- "\t\t"));
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifInflaterImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifInflaterImpl.java
index e7b772f1c7b2..7a6d4f1c7d7b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifInflaterImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifInflaterImpl.java
@@ -98,13 +98,12 @@ public class NotifInflaterImpl implements NotifInflater {
@Override
public void run() {
int dismissalSurface = NotificationStats.DISMISSAL_SHADE;
- /**
+ /*
* TODO: determine dismissal surface (ie: shade / headsup / aod)
* see {@link NotificationLogger#logNotificationClear}
*/
mNotifCollection.dismissNotification(
entry,
- 0,
new DismissedByUserStats(
dismissalSurface,
DISMISS_SENTIMENT_NEUTRAL,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
index 1f77ec229041..df65dacf12dd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
@@ -22,6 +22,7 @@ import static android.app.Notification.CATEGORY_EVENT;
import static android.app.Notification.CATEGORY_MESSAGE;
import static android.app.Notification.CATEGORY_REMINDER;
import static android.app.Notification.FLAG_BUBBLE;
+import static android.app.Notification.FLAG_FOREGROUND_SERVICE;
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_AMBIENT;
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_BADGE;
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
@@ -29,9 +30,11 @@ import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_NOTIFICAT
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK;
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BAR;
+import static com.android.systemui.statusbar.notification.collection.NotifCollection.REASON_NOT_CANCELED;
import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_ALERTING;
-import android.annotation.NonNull;
+import static java.util.Objects.requireNonNull;
+
import android.app.Notification;
import android.app.Notification.MessagingStyle.Message;
import android.app.NotificationChannel;
@@ -50,6 +53,7 @@ import android.util.ArraySet;
import android.view.View;
import android.widget.ImageView;
+import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.internal.annotations.VisibleForTesting;
@@ -59,6 +63,7 @@ import com.android.internal.util.ContrastColorUtil;
import com.android.systemui.statusbar.InflationTask;
import com.android.systemui.statusbar.StatusBarIconView;
import com.android.systemui.statusbar.notification.InflationException;
+import com.android.systemui.statusbar.notification.collection.NotifCollection.CancellationReason;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifPromoter;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender;
@@ -105,9 +110,18 @@ public final class NotificationEntry extends ListEntry {
/** If this was a group child that was promoted to the top level, then who did the promoting. */
@Nullable NotifPromoter mNotifPromoter;
- /** If this notification had an issue with inflating. Only used with the NewNotifPipeline **/
+ /**
+ * If this notification was cancelled by system server, then the reason that was supplied.
+ * Uncancelled notifications always have REASON_NOT_CANCELED. Note that lifetime-extended
+ * notifications will have this set even though they are still in the active notification set.
+ */
+ @CancellationReason int mCancellationReason = REASON_NOT_CANCELED;
+
+ /** @see #hasInflationError() */
private boolean mHasInflationError;
+ /** @see #getDismissState() */
+ @NonNull private DismissState mDismissState = DismissState.NOT_DISMISSED;
/*
* Old members
@@ -164,18 +178,29 @@ public final class NotificationEntry extends ListEntry {
private Runnable mOnSensitiveChangedListener;
private boolean mAutoHeadsUp;
private boolean mPulseSupressed;
+ private boolean mAllowFgsDismissal;
private int mBucket = BUCKET_ALERTING;
public NotificationEntry(
@NonNull StatusBarNotification sbn,
@NonNull Ranking ranking) {
- super(Objects.requireNonNull(Objects.requireNonNull(sbn).getKey()));
+ this(sbn, ranking, false);
+ }
+
+ public NotificationEntry(
+ @NonNull StatusBarNotification sbn,
+ @NonNull Ranking ranking,
+ boolean allowFgsDismissal
+ ) {
+ super(requireNonNull(Objects.requireNonNull(sbn).getKey()));
- Objects.requireNonNull(ranking);
+ requireNonNull(ranking);
mKey = sbn.getKey();
setSbn(sbn);
setRanking(ranking);
+
+ mAllowFgsDismissal = allowFgsDismissal;
}
@Override
@@ -201,8 +226,8 @@ public final class NotificationEntry extends ListEntry {
* TODO: Make this package-private
*/
public void setSbn(@NonNull StatusBarNotification sbn) {
- Objects.requireNonNull(sbn);
- Objects.requireNonNull(sbn.getKey());
+ requireNonNull(sbn);
+ requireNonNull(sbn.getKey());
if (!sbn.getKey().equals(mKey)) {
throw new IllegalArgumentException("New key " + sbn.getKey()
@@ -227,8 +252,8 @@ public final class NotificationEntry extends ListEntry {
* TODO: Make this package-private
*/
public void setRanking(@NonNull Ranking ranking) {
- Objects.requireNonNull(ranking);
- Objects.requireNonNull(ranking.getKey());
+ requireNonNull(ranking);
+ requireNonNull(ranking.getKey());
if (!ranking.getKey().equals(mKey)) {
throw new IllegalArgumentException("New key " + ranking.getKey()
@@ -239,6 +264,34 @@ public final class NotificationEntry extends ListEntry {
}
/*
+ * Bookkeeping getters and setters
+ */
+
+ /**
+ * Whether this notification had an error when attempting to inflate. This is only used in
+ * the NewNotifPipeline
+ */
+ public boolean hasInflationError() {
+ return mHasInflationError;
+ }
+
+ void setHasInflationError(boolean hasError) {
+ mHasInflationError = hasError;
+ }
+
+ /**
+ * Set if the user has dismissed this notif but we haven't yet heard back from system server to
+ * confirm the dismissal.
+ */
+ @NonNull public DismissState getDismissState() {
+ return mDismissState;
+ }
+
+ void setDismissState(@NonNull DismissState dismissState) {
+ mDismissState = requireNonNull(dismissState);
+ }
+
+ /*
* Convenience getters for SBN and Ranking members
*/
@@ -275,7 +328,6 @@ public final class NotificationEntry extends ListEntry {
return mRanking.canBubble();
}
-
public @NonNull List<Notification.Action> getSmartActions() {
return mRanking.getSmartActions();
}
@@ -578,18 +630,6 @@ public final class NotificationEntry extends ListEntry {
remoteInputTextWhenReset = null;
}
- void setHasInflationError(boolean hasError) {
- mHasInflationError = hasError;
- }
-
- /**
- * Whether this notification had an error when attempting to inflate. This is only used in
- * the NewNotifPipeline
- */
- public boolean hasInflationError() {
- return mHasInflationError;
- }
-
public void setHasSentReply() {
hasSentReply = true;
}
@@ -799,8 +839,11 @@ public final class NotificationEntry extends ListEntry {
* notification can be dismissed in case notifications are sensitive on the lockscreen.
* @see #canViewBeDismissed()
*/
+ // TOOD: This logic doesn't belong on NotificationEntry. It should be moved to the
+ // ForegroundsServiceDismissalFeatureController or some other controller that can be added
+ // as a dependency to any class that needs to answer this question.
public boolean isClearable() {
- if (!mSbn.isClearable()) {
+ if (!isDismissable()) {
return false;
}
@@ -808,7 +851,7 @@ public final class NotificationEntry extends ListEntry {
if (children != null && children.size() > 0) {
for (int i = 0; i < children.size(); i++) {
NotificationEntry child = children.get(i);
- if (!child.isClearable()) {
+ if (!child.isDismissable()) {
return false;
}
}
@@ -816,6 +859,31 @@ public final class NotificationEntry extends ListEntry {
return true;
}
+ /**
+ * Notifications might have any combination of flags:
+ * - FLAG_ONGOING_EVENT
+ * - FLAG_NO_CLEAR
+ * - FLAG_FOREGROUND_SERVICE
+ *
+ * We want to allow dismissal of notifications that represent foreground services, which may
+ * have all 3 flags set. If we only find NO_CLEAR though, we don't want to allow dismissal
+ */
+ private boolean isDismissable() {
+ boolean ongoing = ((mSbn.getNotification().flags & Notification.FLAG_ONGOING_EVENT) != 0);
+ boolean noclear = ((mSbn.getNotification().flags & Notification.FLAG_NO_CLEAR) != 0);
+ boolean fgs = ((mSbn.getNotification().flags & FLAG_FOREGROUND_SERVICE) != 0);
+
+ if (mAllowFgsDismissal) {
+ if (noclear && !ongoing && !fgs) {
+ return false;
+ }
+ return true;
+ } else {
+ return mSbn.isClearable();
+ }
+
+ }
+
public boolean canViewBeDismissed() {
if (row == null) return true;
return row.canViewBeDismissed();
@@ -974,6 +1042,16 @@ public final class NotificationEntry extends ListEntry {
}
}
+ /** @see #getDismissState() */
+ public enum DismissState {
+ /** User has not dismissed this notif or its parent */
+ NOT_DISMISSED,
+ /** User has dismissed this notif specifically */
+ DISMISSED,
+ /** User has dismissed this notif's parent (which implicitly dismisses this one as well) */
+ PARENT_DISMISSED,
+ }
+
private static final long LAUNCH_COOLDOWN = 2000;
private static final long REMOTE_INPUT_COOLDOWN = 500;
private static final long INITIALIZATION_DELAY = 400;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HideLocallyDismissedNotifsCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HideLocallyDismissedNotifsCoordinator.java
new file mode 100644
index 000000000000..0059e7baa3c2
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HideLocallyDismissedNotifsCoordinator.java
@@ -0,0 +1,41 @@
+/*
+ * 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.statusbar.notification.collection.coordinator;
+
+import static com.android.systemui.statusbar.notification.collection.NotificationEntry.DismissState.NOT_DISMISSED;
+
+import com.android.systemui.statusbar.notification.collection.NotifPipeline;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
+
+/**
+ * Filters out notifications that have been dismissed locally (by the user) but that system server
+ * hasn't yet confirmed the removal of.
+ */
+public class HideLocallyDismissedNotifsCoordinator implements Coordinator {
+ @Override
+ public void attach(NotifPipeline pipeline) {
+ pipeline.addPreGroupFilter(mFilter);
+ }
+
+ private final NotifFilter mFilter = new NotifFilter("HideLocallyDismissedNotifsFilter") {
+ @Override
+ public boolean shouldFilterOut(NotificationEntry entry, long now) {
+ return entry.getDismissState() != NOT_DISMISSED;
+ }
+ };
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.java
index 8d0dd5b111ba..0a1e09f4c99d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.java
@@ -56,6 +56,7 @@ public class NotifCoordinators implements Dumpable {
PreparationCoordinator preparationCoordinator) {
dumpController.registerDumpable(TAG, this);
+ mCoordinators.add(new HideLocallyDismissedNotifsCoordinator());
mCoordinators.add(keyguardCoordinator);
mCoordinators.add(rankingCoordinator);
mCoordinators.add(foregroundCoordinator);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java
index 20c9cbc8790d..41314b86695a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java
@@ -72,7 +72,7 @@ public class PreparationCoordinator implements Coordinator {
}
@Override
- public void onEntryRemoved(NotificationEntry entry, int reason, boolean removedByUser) {
+ public void onEntryRemoved(NotificationEntry entry, int reason) {
abortInflation(entry, "entryRemoved reason=" + reason);
}
};
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionListener.java
index ff6da12bd0bc..b2c53dae16cd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionListener.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionListener.java
@@ -54,10 +54,7 @@ public interface NotifCollectionListener {
* immediately after a user dismisses a notification: we wait until we receive confirmation from
* system server before considering the notification removed.
*/
- default void onEntryRemoved(
- NotificationEntry entry,
- @CancellationReason int reason,
- boolean removedByUser) {
+ default void onEntryRemoved(NotificationEntry entry, @CancellationReason int reason) {
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionLogger.kt
index 0d0a46adb41f..14e15031056f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionLogger.kt
@@ -61,6 +61,14 @@ class NotifCollectionLogger @Inject constructor(
})
}
+ fun logNotifDismissed(key: String) {
+ buffer.log(TAG, INFO, {
+ str1 = key
+ }, {
+ "DISMISSED $str1"
+ })
+ }
+
fun logRankingMissing(key: String, rankingMap: RankingMap) {
buffer.log(TAG, WARNING, { str1 = key }, { "Ranking update is missing ranking for $str1" })
buffer.log(TAG, DEBUG, {}, { "Ranking map contents:" })
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/DungeonRow.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/DungeonRow.kt
new file mode 100644
index 000000000000..373457d4e336
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/DungeonRow.kt
@@ -0,0 +1,43 @@
+/*
+* 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.statusbar.notification.row
+
+import android.content.Context
+import android.util.AttributeSet
+import android.widget.LinearLayout
+import android.widget.TextView
+import com.android.systemui.R
+import com.android.systemui.statusbar.StatusBarIconView
+import com.android.systemui.statusbar.notification.collection.NotificationEntry
+
+class DungeonRow(context: Context, attrs: AttributeSet) : LinearLayout(context, attrs) {
+ var entry: NotificationEntry? = null
+ set(value) {
+ field = value
+ update()
+ }
+
+ private fun update() {
+ (findViewById(R.id.app_name) as TextView).apply {
+ text = entry?.row?.appName
+ }
+
+ (findViewById(R.id.icon) as StatusBarIconView).apply {
+ set(entry?.icon?.statusBarIcon)
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index b71bedaca707..253be2fcb5ca 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -745,6 +745,11 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
mPrivateLayout.setRemoteInputController(r);
}
+
+ String getAppName() {
+ return mAppName;
+ }
+
public void addChildNotification(ExpandableNotificationRow row) {
addChildNotification(row, -1);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ForegroundServiceDungeonView.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ForegroundServiceDungeonView.kt
new file mode 100644
index 000000000000..17396ad31ba2
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ForegroundServiceDungeonView.kt
@@ -0,0 +1,38 @@
+/*
+ * 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.statusbar.notification.row
+
+import android.content.Context
+import android.util.AttributeSet
+import android.view.View
+
+import com.android.systemui.R
+
+class ForegroundServiceDungeonView(context: Context, attrs: AttributeSet)
+ : StackScrollerDecorView(context, attrs) {
+ override fun findContentView(): View? {
+ return findViewById(R.id.foreground_service_dungeon)
+ }
+
+ override fun findSecondaryView(): View? {
+ return null
+ }
+
+ override fun setVisible(visible: Boolean, animate: Boolean) {
+ // Visibility is controlled by the ForegroundServiceSectionController
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ForegroundServiceSectionController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ForegroundServiceSectionController.kt
new file mode 100644
index 000000000000..5757fe8040f0
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ForegroundServiceSectionController.kt
@@ -0,0 +1,171 @@
+/*
+ * 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.statusbar.notification.stack
+
+import android.content.Context
+import android.service.notification.NotificationListenerService.REASON_APP_CANCEL
+import android.service.notification.NotificationListenerService.REASON_APP_CANCEL_ALL
+import android.service.notification.NotificationListenerService.REASON_CANCEL
+import android.service.notification.NotificationListenerService.REASON_CANCEL_ALL
+import android.service.notification.NotificationListenerService.REASON_CLICK
+import android.service.notification.NotificationListenerService.REASON_GROUP_SUMMARY_CANCELED
+import android.view.LayoutInflater
+import android.view.View
+import android.widget.LinearLayout
+
+import com.android.systemui.statusbar.notification.collection.NotificationEntry
+import com.android.systemui.R
+import com.android.systemui.statusbar.notification.ForegroundServiceDismissalFeatureController
+import com.android.systemui.statusbar.notification.NotificationEntryListener
+import com.android.systemui.statusbar.notification.NotificationEntryManager
+import com.android.systemui.statusbar.notification.row.DungeonRow
+import com.android.systemui.util.Assert
+
+import javax.inject.Inject
+import javax.inject.Singleton
+
+/**
+ * Controller for the bottom area of NotificationStackScrollLayout. It owns swiped-away foreground
+ * service notifications and can reinstantiate them when requested.
+ */
+@Singleton
+class ForegroundServiceSectionController @Inject constructor(
+ val entryManager: NotificationEntryManager,
+ val featureController: ForegroundServiceDismissalFeatureController
+) {
+ private val TAG = "FgsSectionController"
+ private var context: Context? = null
+
+ private val entries = mutableSetOf<NotificationEntry>()
+
+ private var entriesView: View? = null
+
+ init {
+ if (featureController.isForegroundServiceDismissalEnabled()) {
+ entryManager.addNotificationRemoveInterceptor(this::shouldInterceptRemoval)
+
+ entryManager.addNotificationEntryListener(object : NotificationEntryListener {
+ override fun onPostEntryUpdated(entry: NotificationEntry) {
+ if (entries.contains(entry)) {
+ removeEntry(entry)
+ addEntry(entry)
+ update()
+ }
+ }
+ })
+ }
+ }
+
+ private fun shouldInterceptRemoval(
+ key: String,
+ entry: NotificationEntry?,
+ reason: Int
+ ): Boolean {
+ Assert.isMainThread()
+ val isClearAll = reason == REASON_CANCEL_ALL
+ val isUserDismiss = reason == REASON_CANCEL || reason == REASON_CLICK
+ val isAppCancel = reason == REASON_APP_CANCEL || reason == REASON_APP_CANCEL_ALL
+ val isSummaryCancel = reason == REASON_GROUP_SUMMARY_CANCELED
+
+ if (entry == null) return false
+
+ // We only want to retain notifications that the user dismissed
+ // TODO: centralize the entry.isClearable logic and this so that it's clear when a notif is
+ // clearable
+ if (isUserDismiss && !entry.sbn.isClearable) {
+ if (!hasEntry(entry)) {
+ addEntry(entry)
+ update()
+ }
+ // TODO: This isn't ideal. Slightly better would at least be to have NEM update the
+ // notif list when an entry gets intercepted
+ entryManager.updateNotifications(
+ "FgsSectionController.onNotificationRemoveRequested")
+ return true
+ } else if ((isClearAll || isSummaryCancel) && !entry.sbn.isClearable) {
+ // In the case where a FGS notification is part of a group that is cleared or a clear
+ // all, we actually want to stop its removal but also not put it into the dungeon
+ return true
+ } else if (hasEntry(entry)) {
+ removeEntry(entry)
+ update()
+ return false
+ }
+
+ return false
+ }
+
+ private fun removeEntry(entry: NotificationEntry) {
+ Assert.isMainThread()
+ entries.remove(entry)
+ }
+
+ private fun addEntry(entry: NotificationEntry) {
+ Assert.isMainThread()
+ entries.add(entry)
+ }
+
+ fun hasEntry(entry: NotificationEntry): Boolean {
+ Assert.isMainThread()
+ return entries.contains(entry)
+ }
+
+ fun initialize(context: Context) {
+ this.context = context
+ }
+
+ fun createView(li: LayoutInflater): View {
+ entriesView = li.inflate(R.layout.foreground_service_dungeon, null)
+ // Start out gone
+ entriesView!!.visibility = View.GONE
+ return entriesView!!
+ }
+
+ private fun update() {
+ Assert.isMainThread()
+ if (entriesView == null) {
+ throw IllegalStateException("ForegroundServiceSectionController is trying to show " +
+ "dismissed fgs notifications without having been initialized!")
+ }
+
+ // TODO: these views should be recycled and not inflating on the main thread
+ (entriesView!!.findViewById(R.id.entry_list) as LinearLayout).apply {
+ removeAllViews()
+ entries.sortedBy { it.ranking.rank }.forEach { entry ->
+ val child = LayoutInflater.from(context)
+ .inflate(R.layout.foreground_service_dungeon_row, null) as DungeonRow
+
+ child.entry = entry
+ child.setOnClickListener {
+ removeEntry(child.entry!!)
+ update()
+ entry.row.unDismiss()
+ entry.row.resetTranslation()
+ entryManager.updateNotifications("ForegroundServiceSectionController.onClick")
+ }
+
+ addView(child)
+ }
+ }
+
+ if (entries.isEmpty()) {
+ entriesView?.visibility = View.GONE
+ } else {
+ entriesView?.visibility = View.VISIBLE
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index 84a293eebc95..4b9976cc2097 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -35,7 +35,6 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
import android.content.Intent;
-import android.content.pm.UserInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Canvas;
@@ -57,7 +56,6 @@ import android.util.DisplayMetrics;
import android.util.Log;
import android.util.MathUtils;
import android.util.Pair;
-import android.util.SparseArray;
import android.view.ContextThemeWrapper;
import android.view.InputDevice;
import android.view.LayoutInflater;
@@ -109,6 +107,7 @@ import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.notification.DynamicPrivacyController;
import com.android.systemui.statusbar.notification.FakeShadowView;
+import com.android.systemui.statusbar.notification.ForegroundServiceDismissalFeatureController;
import com.android.systemui.statusbar.notification.NotificationEntryListener;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.NotificationUtils;
@@ -121,6 +120,7 @@ import com.android.systemui.statusbar.notification.row.ActivatableNotificationVi
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.ExpandableView;
import com.android.systemui.statusbar.notification.row.FooterView;
+import com.android.systemui.statusbar.notification.row.ForegroundServiceDungeonView;
import com.android.systemui.statusbar.notification.row.NotificationBlockingHelperManager;
import com.android.systemui.statusbar.notification.row.NotificationGuts;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
@@ -506,6 +506,8 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
private final NotificationGutsManager mNotificationGutsManager;
private final NotificationSectionsManager mSectionsManager;
+ private final ForegroundServiceSectionController mFgsSectionController;
+ private ForegroundServiceDungeonView mFgsSectionView;
private boolean mAnimateBottomOnLayout;
private float mLastSentAppear;
private float mLastSentExpandedHeight;
@@ -525,7 +527,10 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
NotificationLockscreenUserManager notificationLockscreenUserManager,
NotificationGutsManager notificationGutsManager,
ZenModeController zenController,
- NotificationSectionsManager notificationSectionsManager) {
+ NotificationSectionsManager notificationSectionsManager,
+ ForegroundServiceSectionController fgsSectionController,
+ ForegroundServiceDismissalFeatureController fgsFeatureController
+ ) {
super(context, attrs, 0, 0);
Resources res = getResources();
@@ -541,6 +546,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
mKeyguardBypassController = keyguardBypassController;
mFalsingManager = falsingManager;
mZenController = zenController;
+ mFgsSectionController = fgsSectionController;
mSectionsManager = notificationSectionsManager;
mSectionsManager.initialize(this, LayoutInflater.from(context));
@@ -614,6 +620,17 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
dynamicPrivacyController.addListener(this);
mDynamicPrivacyController = dynamicPrivacyController;
mStatusbarStateController = statusBarStateController;
+ initializeForegroundServiceSection(fgsFeatureController);
+ }
+
+ private void initializeForegroundServiceSection(
+ ForegroundServiceDismissalFeatureController featureController) {
+ if (featureController.isForegroundServiceDismissalEnabled()) {
+ LayoutInflater li = LayoutInflater.from(mContext);
+ mFgsSectionView =
+ (ForegroundServiceDungeonView) mFgsSectionController.createView(li);
+ addView(mFgsSectionView, -1);
+ }
}
private void updateDismissRtlSetting(boolean dismissRtl) {
@@ -3374,7 +3391,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
if (currentIndex == -1) {
boolean isTransient = false;
if (child instanceof ExpandableNotificationRow
- && ((ExpandableNotificationRow) child).getTransientContainer() != null) {
+ && child.getTransientContainer() != null) {
isTransient = true;
}
Log.e(TAG, "Attempting to re-position "
@@ -3387,10 +3404,10 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
if (child != null && child.getParent() == this && currentIndex != newIndex) {
mChangePositionInProgress = true;
- ((ExpandableView) child).setChangingPosition(true);
+ child.setChangingPosition(true);
removeView(child);
addView(child, newIndex);
- ((ExpandableView) child).setChangingPosition(false);
+ child.setChangingPosition(false);
mChangePositionInProgress = false;
if (mIsExpanded && mAnimationsEnabled && child.getVisibility() != View.GONE) {
mChildrenChangingPositions.add(child);
@@ -5637,15 +5654,17 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
*/
@ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
public void onUpdateRowStates() {
- changeViewPosition(mFooterView, -1);
// The following views will be moved to the end of mStackScroller. This counter represents
// the offset from the last child. Initialized to 1 for the very last position. It is post-
// incremented in the following "changeViewPosition" calls so that its value is correct for
// subsequent calls.
int offsetFromEnd = 1;
- changeViewPosition(mEmptyShadeView,
- getChildCount() - offsetFromEnd++);
+ if (mFgsSectionView != null) {
+ changeViewPosition(mFgsSectionView, getChildCount() - offsetFromEnd++);
+ }
+ changeViewPosition(mFooterView, getChildCount() - offsetFromEnd++);
+ changeViewPosition(mEmptyShadeView, getChildCount() - offsetFromEnd++);
// No post-increment for this call because it is the last one. Make sure to add one if
// another "changeViewPosition" call is ever added.
diff --git a/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIBinder.java b/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIBinder.java
new file mode 100644
index 000000000000..264ddc026781
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIBinder.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.tv;
+
+import com.android.systemui.dagger.SystemUIRootComponent;
+
+import dagger.Binds;
+import dagger.Module;
+
+@Module
+interface TvSystemUIBinder {
+ @Binds
+ SystemUIRootComponent bindSystemUIRootComponent(TvSystemUIRootComponent systemUIRootComponent);
+}
diff --git a/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIFactory.java
new file mode 100644
index 000000000000..7d3ec678fd5f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIFactory.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.tv;
+
+import android.content.Context;
+
+import com.android.systemui.SystemUIFactory;
+import com.android.systemui.dagger.SystemUIRootComponent;
+
+/**
+ * TV variant {@link SystemUIFactory}, that substitutes default {@link SystemUIRootComponent} for
+ * {@link TvSystemUIRootComponent}
+ */
+public class TvSystemUIFactory extends SystemUIFactory {
+ @Override
+ protected SystemUIRootComponent buildSystemUIRootComponent(Context context) {
+ return DaggerTvSystemUIRootComponent.builder()
+ .context(context)
+ .build();
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIRootComponent.java b/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIRootComponent.java
new file mode 100644
index 000000000000..fcf27009883a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIRootComponent.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.tv;
+
+import android.content.Context;
+
+import com.android.systemui.dagger.DefaultComponentBinder;
+import com.android.systemui.dagger.DependencyBinder;
+import com.android.systemui.dagger.DependencyProvider;
+import com.android.systemui.dagger.SystemServicesModule;
+import com.android.systemui.dagger.SystemUIBinder;
+import com.android.systemui.dagger.SystemUIDefaultModule;
+import com.android.systemui.dagger.SystemUIModule;
+import com.android.systemui.dagger.SystemUIRootComponent;
+
+import javax.inject.Singleton;
+
+import dagger.BindsInstance;
+import dagger.Component;
+
+/**
+ * Root component for Dagger injection.
+ */
+@Singleton
+@Component(modules = {
+ DefaultComponentBinder.class,
+ DependencyProvider.class,
+ DependencyBinder.class,
+ SystemServicesModule.class,
+ SystemUIBinder.class,
+ SystemUIModule.class,
+ SystemUIDefaultModule.class,
+ TvSystemUIBinder.class})
+public interface TvSystemUIRootComponent extends SystemUIRootComponent {
+ /**
+ * Component Builder interface. This allows to bind Context instance in the component
+ */
+ @Component.Builder
+ interface Builder {
+ @BindsInstance Builder context(Context context);
+
+ TvSystemUIRootComponent build();
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/wm/DisplayLayout.java b/packages/SystemUI/src/com/android/systemui/wm/DisplayLayout.java
index 264a683f6a3d..64b0b66a47a9 100644
--- a/packages/SystemUI/src/com/android/systemui/wm/DisplayLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/wm/DisplayLayout.java
@@ -31,9 +31,11 @@ import android.annotation.NonNull;
import android.content.ContentResolver;
import android.content.Context;
import android.content.res.Resources;
+import android.graphics.Insets;
import android.graphics.Rect;
import android.os.SystemProperties;
import android.provider.Settings;
+import android.util.RotationUtils;
import android.util.Size;
import android.view.Display;
import android.view.DisplayCutout;
@@ -43,8 +45,6 @@ import android.view.Surface;
import com.android.internal.R;
-import java.util.List;
-
/**
* Contains information about the layout-properties of a display. This refers to internal layout
* like insets/cutout/rotation. In general, this can be thought of as the System-UI analog to
@@ -323,28 +323,38 @@ public class DisplayLayout {
if (cutout == null || cutout == DisplayCutout.NO_CUTOUT) {
return null;
}
+ final Insets waterfallInsets =
+ RotationUtils.rotateInsets(cutout.getWaterfallInsets(), rotation);
if (rotation == ROTATION_0) {
- return computeSafeInsets(
- cutout, displayWidth, displayHeight);
+ return computeSafeInsets(cutout, displayWidth, displayHeight);
}
final boolean rotated = (rotation == ROTATION_90 || rotation == ROTATION_270);
- Rect[] cutoutRects = computeSafeInsets(cutout, displayWidth, displayHeight)
- .getBoundingRectsAll();
+ Rect[] cutoutRects = cutout.getBoundingRectsAll();
final Rect[] newBounds = new Rect[cutoutRects.length];
final Rect displayBounds = new Rect(0, 0, displayWidth, displayHeight);
for (int i = 0; i < cutoutRects.length; ++i) {
- newBounds[i] = new Rect(cutoutRects[i]);
- rotateBounds(newBounds[i], displayBounds, rotation);
+ final Rect rect = new Rect(cutoutRects[i]);
+ if (!rect.isEmpty()) {
+ rotateBounds(rect, displayBounds, rotation);
+ }
+ newBounds[getBoundIndexFromRotation(i, rotation)] = rect;
}
- return computeSafeInsets(DisplayCutout.fromBounds(newBounds),
+ return computeSafeInsets(
+ DisplayCutout.fromBoundsAndWaterfall(newBounds, waterfallInsets),
rotated ? displayHeight : displayWidth,
rotated ? displayWidth : displayHeight);
}
+ private static int getBoundIndexFromRotation(int index, int rotation) {
+ return (index - rotation) < 0
+ ? index - rotation + DisplayCutout.BOUNDS_POSITION_LENGTH
+ : index - rotation;
+ }
+
/** Calculate safe insets. */
public static DisplayCutout computeSafeInsets(DisplayCutout inner,
int displayWidth, int displayHeight) {
- if (inner == DisplayCutout.NO_CUTOUT || inner.isBoundsEmpty()) {
+ if (inner == DisplayCutout.NO_CUTOUT) {
return null;
}
@@ -353,58 +363,44 @@ public class DisplayLayout {
return inner.replaceSafeInsets(safeInsets);
}
- private static Rect computeSafeInsets(Size displaySize, DisplayCutout cutout) {
- if (displaySize.getWidth() < displaySize.getHeight()) {
- final List<Rect> boundingRects = cutout.replaceSafeInsets(
- new Rect(0, displaySize.getHeight() / 2, 0, displaySize.getHeight() / 2))
- .getBoundingRects();
- int topInset = findInsetForSide(displaySize, boundingRects, Gravity.TOP);
- int bottomInset = findInsetForSide(displaySize, boundingRects, Gravity.BOTTOM);
- return new Rect(0, topInset, 0, bottomInset);
- } else if (displaySize.getWidth() > displaySize.getHeight()) {
- final List<Rect> boundingRects = cutout.replaceSafeInsets(
- new Rect(displaySize.getWidth() / 2, 0, displaySize.getWidth() / 2, 0))
- .getBoundingRects();
- int leftInset = findInsetForSide(displaySize, boundingRects, Gravity.LEFT);
- int right = findInsetForSide(displaySize, boundingRects, Gravity.RIGHT);
- return new Rect(leftInset, 0, right, 0);
- } else {
+ private static Rect computeSafeInsets(
+ Size displaySize, DisplayCutout cutout) {
+ if (displaySize.getWidth() == displaySize.getHeight()) {
throw new UnsupportedOperationException("not implemented: display=" + displaySize
+ " cutout=" + cutout);
}
+
+ int leftInset = Math.max(cutout.getWaterfallInsets().left,
+ findCutoutInsetForSide(displaySize, cutout.getBoundingRectLeft(), Gravity.LEFT));
+ int topInset = Math.max(cutout.getWaterfallInsets().top,
+ findCutoutInsetForSide(displaySize, cutout.getBoundingRectTop(), Gravity.TOP));
+ int rightInset = Math.max(cutout.getWaterfallInsets().right,
+ findCutoutInsetForSide(displaySize, cutout.getBoundingRectRight(), Gravity.RIGHT));
+ int bottomInset = Math.max(cutout.getWaterfallInsets().bottom,
+ findCutoutInsetForSide(displaySize, cutout.getBoundingRectBottom(),
+ Gravity.BOTTOM));
+
+ return new Rect(leftInset, topInset, rightInset, bottomInset);
}
- private static int findInsetForSide(Size display, List<Rect> boundingRects, int gravity) {
+ private static int findCutoutInsetForSide(Size display, Rect boundingRect, int gravity) {
+ if (boundingRect.isEmpty()) {
+ return 0;
+ }
+
int inset = 0;
- final int size = boundingRects.size();
- for (int i = 0; i < size; i++) {
- Rect boundingRect = boundingRects.get(i);
- switch (gravity) {
- case Gravity.TOP:
- if (boundingRect.top == 0) {
- inset = Math.max(inset, boundingRect.bottom);
- }
- break;
- case Gravity.BOTTOM:
- if (boundingRect.bottom == display.getHeight()) {
- inset = Math.max(inset, display.getHeight() - boundingRect.top);
- }
- break;
- case Gravity.LEFT:
- if (boundingRect.left == 0) {
- inset = Math.max(inset, boundingRect.right);
- }
- break;
- case Gravity.RIGHT:
- if (boundingRect.right == display.getWidth()) {
- inset = Math.max(inset, display.getWidth() - boundingRect.left);
- }
- break;
- default:
- throw new IllegalArgumentException("unknown gravity: " + gravity);
- }
+ switch (gravity) {
+ case Gravity.TOP:
+ return Math.max(inset, boundingRect.bottom);
+ case Gravity.BOTTOM:
+ return Math.max(inset, display.getHeight() - boundingRect.top);
+ case Gravity.LEFT:
+ return Math.max(inset, boundingRect.right);
+ case Gravity.RIGHT:
+ return Math.max(inset, display.getWidth() - boundingRect.left);
+ default:
+ throw new IllegalArgumentException("unknown gravity: " + gravity);
}
- return inset;
}
static boolean hasNavigationBar(DisplayInfo info, Context context, int displayId) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
index 333b4a778621..dcaf4ec6f8ae 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
@@ -237,7 +237,7 @@ public class BubbleControllerTest extends SysuiTestCase {
mEntryListener = mEntryListenerCaptor.getValue();
// And the remove interceptor
verify(mNotificationEntryManager, atLeastOnce())
- .setNotificationRemoveInterceptor(mRemoveInterceptorCaptor.capture());
+ .addNotificationRemoveInterceptor(mRemoveInterceptorCaptor.capture());
mRemoveInterceptor = mRemoveInterceptorCaptor.getValue();
}
@@ -581,7 +581,7 @@ public class BubbleControllerTest extends SysuiTestCase {
// Simulate notification cancellation.
mRemoveInterceptor.onNotificationRemoveRequested(
- mRow.getEntry().getKey(), REASON_APP_CANCEL);
+ mRow.getEntry().getKey(), mRow.getEntry(), REASON_APP_CANCEL);
mBubbleController.expandStackAndSelectBubble(key);
}
@@ -649,7 +649,7 @@ public class BubbleControllerTest extends SysuiTestCase {
assertTrue(mBubbleController.hasBubbles());
boolean intercepted = mRemoveInterceptor.onNotificationRemoveRequested(
- mRow.getEntry().getKey(), REASON_APP_CANCEL);
+ mRow.getEntry().getKey(), mRow.getEntry(), REASON_APP_CANCEL);
// Cancels always remove so no need to intercept
assertFalse(intercepted);
@@ -666,7 +666,7 @@ public class BubbleControllerTest extends SysuiTestCase {
mRow.getEntry()));
boolean intercepted = mRemoveInterceptor.onNotificationRemoveRequested(
- mRow.getEntry().getKey(), REASON_CANCEL_ALL);
+ mRow.getEntry().getKey(), mRow.getEntry(), REASON_CANCEL_ALL);
// Intercept!
assertTrue(intercepted);
@@ -689,7 +689,7 @@ public class BubbleControllerTest extends SysuiTestCase {
mRow.getEntry()));
boolean intercepted = mRemoveInterceptor.onNotificationRemoveRequested(
- mRow.getEntry().getKey(), REASON_CANCEL);
+ mRow.getEntry().getKey(), mRow.getEntry(), REASON_CANCEL);
// Intercept!
assertTrue(intercepted);
@@ -718,7 +718,7 @@ public class BubbleControllerTest extends SysuiTestCase {
// Dismiss the notification
boolean intercepted = mRemoveInterceptor.onNotificationRemoveRequested(
- mRow.getEntry().getKey(), REASON_CANCEL);
+ mRow.getEntry().getKey(), mRow.getEntry(), REASON_CANCEL);
// It's no longer a bubble so we shouldn't intercept
assertFalse(intercepted);
@@ -736,7 +736,8 @@ public class BubbleControllerTest extends SysuiTestCase {
assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
mRow.getEntry()));
- mRemoveInterceptor.onNotificationRemoveRequested(mRow.getEntry().getKey(), REASON_CANCEL);
+ mRemoveInterceptor.onNotificationRemoveRequested(
+ mRow.getEntry().getKey(), mRow.getEntry(), REASON_CANCEL);
// Should update show in shade state
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java
index c97813de8c0c..63c911b53db9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java
@@ -49,6 +49,7 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntryB
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.ExpandableView;
+import com.android.systemui.statusbar.notification.stack.ForegroundServiceSectionController;
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
@@ -104,7 +105,8 @@ public class NotificationViewHierarchyManagerTest extends SysuiTestCase {
mock(StatusBarStateControllerImpl.class), mEntryManager,
mock(KeyguardBypassController.class),
mock(BubbleController.class),
- mock(DynamicPrivacyController.class));
+ mock(DynamicPrivacyController.class),
+ mock(ForegroundServiceSectionController.class));
mViewHierarchyManager.setUpWithPresenter(mPresenter, mListContainer);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
index 296d0cef715c..20c67fae6c9d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
@@ -247,11 +247,12 @@ public class NotificationEntryManagerTest extends SysuiTestCase {
mFeatureFlags,
() -> notificationRowBinder,
() -> mRemoteInputManager,
- mLeakDetector
+ mLeakDetector,
+ mock(ForegroundServiceDismissalFeatureController.class)
);
mEntryManager.setUpWithPresenter(mPresenter, mListContainer, mHeadsUpManager);
mEntryManager.addNotificationEntryListener(mEntryListener);
- mEntryManager.setNotificationRemoveInterceptor(mRemoveInterceptor);
+ mEntryManager.addNotificationRemoveInterceptor(mRemoveInterceptor);
notificationRowBinder.setUpWithPresenter(
mPresenter, mListContainer, mHeadsUpManager, mBindCallback);
@@ -546,7 +547,8 @@ public class NotificationEntryManagerTest extends SysuiTestCase {
mEntryManager.addActiveNotificationForTest(mEntry);
// GIVEN interceptor that intercepts that entry
- when(mRemoveInterceptor.onNotificationRemoveRequested(eq(mEntry.getKey()), anyInt()))
+ when(mRemoveInterceptor.onNotificationRemoveRequested(
+ eq(mEntry.getKey()), eq(mEntry), anyInt()))
.thenReturn(true);
// WHEN the notification is removed
@@ -564,7 +566,8 @@ public class NotificationEntryManagerTest extends SysuiTestCase {
mEntryManager.addActiveNotificationForTest(mEntry);
// GIVEN interceptor that doesn't intercept
- when(mRemoveInterceptor.onNotificationRemoveRequested(eq(mEntry.getKey()), anyInt()))
+ when(mRemoveInterceptor.onNotificationRemoveRequested(
+ eq(mEntry.getKey()), eq(mEntry), anyInt()))
.thenReturn(false);
// WHEN the notification is removed
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/TestableNotificationEntryManager.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/TestableNotificationEntryManager.kt
index 29ce92074027..7431459aac8f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/TestableNotificationEntryManager.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/TestableNotificationEntryManager.kt
@@ -41,9 +41,10 @@ class TestableNotificationEntryManager(
ff: FeatureFlags,
rb: dagger.Lazy<NotificationRowBinder>,
notificationRemoteInputManagerLazy: dagger.Lazy<NotificationRemoteInputManager>,
- leakDetector: LeakDetector
+ leakDetector: LeakDetector,
+ fgsFeatureController: ForegroundServiceDismissalFeatureController
) : NotificationEntryManager(log, gm, rm, ke, ff, rb,
- notificationRemoteInputManagerLazy, leakDetector) {
+ notificationRemoteInputManagerLazy, leakDetector, fgsFeatureController) {
public var countDownLatch: CountDownLatch = CountDownLatch(1)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java
index b65298097ff1..7c94ed20e95a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java
@@ -17,9 +17,16 @@
package com.android.systemui.statusbar.notification.collection;
import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL;
+import static android.service.notification.NotificationListenerService.REASON_CANCEL;
import static android.service.notification.NotificationListenerService.REASON_CLICK;
+import static android.service.notification.NotificationStats.DISMISSAL_SHADE;
+import static android.service.notification.NotificationStats.DISMISS_SENTIMENT_NEUTRAL;
+import static com.android.systemui.statusbar.notification.collection.NotifCollection.REASON_NOT_CANCELED;
import static com.android.systemui.statusbar.notification.collection.NotifCollection.REASON_UNKNOWN;
+import static com.android.systemui.statusbar.notification.collection.NotificationEntry.DismissState.DISMISSED;
+import static com.android.systemui.statusbar.notification.collection.NotificationEntry.DismissState.NOT_DISMISSED;
+import static com.android.systemui.statusbar.notification.collection.NotificationEntry.DismissState.PARENT_DISMISSED;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -40,7 +47,6 @@ import static java.util.Objects.requireNonNull;
import android.annotation.Nullable;
import android.os.RemoteException;
import android.service.notification.NotificationListenerService.Ranking;
-import android.service.notification.NotificationStats;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.util.ArrayMap;
@@ -77,6 +83,7 @@ import org.mockito.Spy;
import java.util.Arrays;
import java.util.Collection;
+import java.util.Collections;
import java.util.List;
import java.util.Map;
@@ -236,7 +243,7 @@ public class NotifCollectionTest extends SysuiTestCase {
mNoMan.retractNotif(notif.sbn, REASON_APP_CANCEL);
// THEN the listener is notified
- verify(mCollectionListener).onEntryRemoved(entry, REASON_APP_CANCEL, false);
+ verify(mCollectionListener).onEntryRemoved(entry, REASON_APP_CANCEL);
verify(mCollectionListener).onEntryCleanUp(entry);
assertEquals(notif.sbn, entry.getSbn());
assertEquals(notif.ranking, entry.getRanking());
@@ -322,24 +329,15 @@ public class NotifCollectionTest extends SysuiTestCase {
}
@Test
- public void testDismissNotification() throws RemoteException {
- // GIVEN a collection with a couple notifications and a lifetime extender
- mCollection.addNotificationLifetimeExtender(mExtender1);
-
+ public void testDismissNotificationSentToSystemServer() throws RemoteException {
+ // GIVEN a collection with a couple notifications
NotifEvent notif1 = mNoMan.postNotif(buildNotif(TEST_PACKAGE, 47, "myTag"));
NotifEvent notif2 = mNoMan.postNotif(buildNotif(TEST_PACKAGE2, 88, "barTag"));
NotificationEntry entry2 = mCollectionListener.getEntry(notif2.key);
// WHEN a notification is manually dismissed
- DismissedByUserStats stats = new DismissedByUserStats(
- NotificationStats.DISMISSAL_SHADE,
- NotificationStats.DISMISS_SENTIMENT_NEUTRAL,
- NotificationVisibility.obtain(entry2.getKey(), 7, 2, true));
-
- mCollection.dismissNotification(entry2, REASON_CLICK, stats);
-
- // THEN we check for lifetime extension
- verify(mExtender1).shouldExtendLifetime(entry2, REASON_CLICK);
+ DismissedByUserStats stats = defaultStats(entry2);
+ mCollection.dismissNotification(entry2, defaultStats(entry2));
// THEN we send the dismissal to system server
verify(mStatusBarService).onNotificationClear(
@@ -351,9 +349,96 @@ public class NotifCollectionTest extends SysuiTestCase {
stats.dismissalSurface,
stats.dismissalSentiment,
stats.notificationVisibility);
+ }
+
+ @Test
+ public void testDismissedNotificationsAreMarkedAsDismissedLocally() {
+ // GIVEN a collection with a notification
+ NotifEvent notif1 = mNoMan.postNotif(buildNotif(TEST_PACKAGE, 47, "myTag"));
+ NotificationEntry entry1 = mCollectionListener.getEntry(notif1.key);
+
+ // WHEN a notification is manually dismissed
+ mCollection.dismissNotification(entry1, defaultStats(entry1));
- // THEN we fire a remove event
- verify(mCollectionListener).onEntryRemoved(entry2, REASON_CLICK, true);
+ // THEN the entry is marked as dismissed locally
+ assertEquals(DISMISSED, entry1.getDismissState());
+ }
+
+ @Test
+ public void testDismissedNotificationsCannotBeLifetimeExtended() {
+ // GIVEN a collection with a notification and a lifetime extender
+ mCollection.addNotificationLifetimeExtender(mExtender1);
+ NotifEvent notif1 = mNoMan.postNotif(buildNotif(TEST_PACKAGE, 47, "myTag"));
+ NotificationEntry entry1 = mCollectionListener.getEntry(notif1.key);
+
+ // WHEN a notification is manually dismissed
+ mCollection.dismissNotification(entry1, defaultStats(entry1));
+
+ // THEN lifetime extenders are never queried
+ verify(mExtender1, never()).shouldExtendLifetime(eq(entry1), anyInt());
+ }
+
+ @Test
+ public void testDismissedNotificationsDoNotTriggerRemovalEvents() {
+ // GIVEN a collection with a notification
+ NotifEvent notif1 = mNoMan.postNotif(buildNotif(TEST_PACKAGE, 47, "myTag"));
+ NotificationEntry entry1 = mCollectionListener.getEntry(notif1.key);
+
+ // WHEN a notification is manually dismissed
+ mCollection.dismissNotification(entry1, defaultStats(entry1));
+
+ // THEN onEntryRemoved is not called
+ verify(mCollectionListener, never()).onEntryRemoved(eq(entry1), anyInt());
+ }
+
+ @Test
+ public void testDismissedNotificationsStillAppearInNotificationSet() {
+ // GIVEN a collection with a notification
+ NotifEvent notif1 = mNoMan.postNotif(buildNotif(TEST_PACKAGE, 47, "myTag"));
+ NotificationEntry entry1 = mCollectionListener.getEntry(notif1.key);
+
+ // WHEN a notification is manually dismissed
+ mCollection.dismissNotification(entry1, defaultStats(entry1));
+
+ // THEN the dismissed entry still appears in the notification set
+ assertEquals(
+ new ArraySet<>(Collections.singletonList(entry1)),
+ new ArraySet<>(mCollection.getActiveNotifs()));
+ }
+
+ @Test
+ public void testDismissingLifetimeExtendedSummaryDoesNotDismissChildren() {
+ // GIVEN A notif group with one summary and two children
+ mCollection.addNotificationLifetimeExtender(mExtender1);
+ NotifEvent notif1 = mNoMan.postNotif(buildNotif(TEST_PACKAGE, 1, "myTag")
+ .setGroup(mContext, GROUP_1)
+ .setGroupSummary(mContext, true));
+ NotifEvent notif2 = mNoMan.postNotif(buildNotif(TEST_PACKAGE, 2, "myTag")
+ .setGroup(mContext, GROUP_1));
+ NotifEvent notif3 = mNoMan.postNotif(buildNotif(TEST_PACKAGE, 3, "myTag")
+ .setGroup(mContext, GROUP_1));
+
+ NotificationEntry entry1 = mCollectionListener.getEntry(notif1.key);
+ NotificationEntry entry2 = mCollectionListener.getEntry(notif2.key);
+ NotificationEntry entry3 = mCollectionListener.getEntry(notif3.key);
+
+ // GIVEN that the summary and one child are retracted, but both are lifetime-extended
+ mExtender1.shouldExtendLifetime = true;
+ mNoMan.retractNotif(notif1.sbn, REASON_CANCEL);
+ mNoMan.retractNotif(notif2.sbn, REASON_CANCEL);
+ assertEquals(
+ new ArraySet<>(List.of(entry1, entry2, entry3)),
+ new ArraySet<>(mCollection.getActiveNotifs()));
+
+ // WHEN the summary is dismissed by the user
+ mCollection.dismissNotification(entry1, defaultStats(entry1));
+
+ // THEN the summary is removed, but both children stick around
+ assertEquals(
+ new ArraySet<>(List.of(entry2, entry3)),
+ new ArraySet<>(mCollection.getActiveNotifs()));
+ assertEquals(NOT_DISMISSED, entry2.getDismissState());
+ assertEquals(NOT_DISMISSED, entry3.getDismissState());
}
@Test(expected = IllegalStateException.class)
@@ -366,15 +451,115 @@ public class NotifCollectionTest extends SysuiTestCase {
mNoMan.retractNotif(notif2.sbn, REASON_UNKNOWN);
// WHEN we try to dismiss a notification that isn't present
- mCollection.dismissNotification(
- entry2,
- REASON_CLICK,
- new DismissedByUserStats(0, 0, NotificationVisibility.obtain("foo", 47, 3, true)));
+ mCollection.dismissNotification(entry2, defaultStats(entry2));
// THEN an exception is thrown
}
@Test
+ public void testGroupChildrenAreDismissedLocallyWhenSummaryIsDismissed() {
+ // GIVEN a collection with two grouped notifs in it
+ NotifEvent notif0 = mNoMan.postNotif(
+ buildNotif(TEST_PACKAGE, 0)
+ .setGroup(mContext, GROUP_1)
+ .setGroupSummary(mContext, true));
+ NotifEvent notif1 = mNoMan.postNotif(
+ buildNotif(TEST_PACKAGE, 1)
+ .setGroup(mContext, GROUP_1));
+ NotificationEntry entry0 = mCollectionListener.getEntry(notif0.key);
+ NotificationEntry entry1 = mCollectionListener.getEntry(notif1.key);
+
+ // WHEN the summary is dismissed
+ mCollection.dismissNotification(entry0, defaultStats(entry0));
+
+ // THEN all members of the group are marked as dismissed locally
+ assertEquals(DISMISSED, entry0.getDismissState());
+ assertEquals(PARENT_DISMISSED, entry1.getDismissState());
+ }
+
+ @Test
+ public void testUpdatingDismissedSummaryBringsChildrenBack() {
+ // GIVEN a collection with two grouped notifs in it
+ NotifEvent notif0 = mNoMan.postNotif(
+ buildNotif(TEST_PACKAGE, 0)
+ .setGroup(mContext, GROUP_1)
+ .setGroupSummary(mContext, true));
+ NotifEvent notif1 = mNoMan.postNotif(
+ buildNotif(TEST_PACKAGE, 1)
+ .setGroup(mContext, GROUP_1));
+ NotificationEntry entry0 = mCollectionListener.getEntry(notif0.key);
+ NotificationEntry entry1 = mCollectionListener.getEntry(notif1.key);
+
+ // WHEN the summary is dismissed but then reposted without a group
+ mCollection.dismissNotification(entry0, defaultStats(entry0));
+ NotifEvent notif0a = mNoMan.postNotif(
+ buildNotif(TEST_PACKAGE, 0));
+
+ // THEN it and all of its previous children are no longer dismissed locally
+ assertEquals(NOT_DISMISSED, entry0.getDismissState());
+ assertEquals(NOT_DISMISSED, entry1.getDismissState());
+ }
+
+ @Test
+ public void testDismissedChildrenAreNotResetByParentUpdate() {
+ // GIVEN a collection with three grouped notifs in it
+ NotifEvent notif0 = mNoMan.postNotif(
+ buildNotif(TEST_PACKAGE, 0)
+ .setGroup(mContext, GROUP_1)
+ .setGroupSummary(mContext, true));
+ NotifEvent notif1 = mNoMan.postNotif(
+ buildNotif(TEST_PACKAGE, 1)
+ .setGroup(mContext, GROUP_1));
+ NotifEvent notif2 = mNoMan.postNotif(
+ buildNotif(TEST_PACKAGE, 2)
+ .setGroup(mContext, GROUP_1));
+ NotificationEntry entry0 = mCollectionListener.getEntry(notif0.key);
+ NotificationEntry entry1 = mCollectionListener.getEntry(notif1.key);
+ NotificationEntry entry2 = mCollectionListener.getEntry(notif2.key);
+
+ // WHEN a child is dismissed, then the parent is dismissed, then the parent is updated
+ mCollection.dismissNotification(entry1, defaultStats(entry1));
+ mCollection.dismissNotification(entry0, defaultStats(entry0));
+ NotifEvent notif0a = mNoMan.postNotif(
+ buildNotif(TEST_PACKAGE, 0));
+
+ // THEN the manually-dismissed child is still marked as dismissed
+ assertEquals(NOT_DISMISSED, entry0.getDismissState());
+ assertEquals(DISMISSED, entry1.getDismissState());
+ assertEquals(NOT_DISMISSED, entry2.getDismissState());
+ }
+
+ @Test
+ public void testUpdatingGroupKeyOfDismissedSummaryBringsChildrenBack() {
+ // GIVEN a collection with two grouped notifs in it
+ NotifEvent notif0 = mNoMan.postNotif(
+ buildNotif(TEST_PACKAGE, 0)
+ .setOverrideGroupKey(GROUP_1)
+ .setGroupSummary(mContext, true));
+ NotifEvent notif1 = mNoMan.postNotif(
+ buildNotif(TEST_PACKAGE, 1)
+ .setOverrideGroupKey(GROUP_1));
+ NotificationEntry entry0 = mCollectionListener.getEntry(notif0.key);
+ NotificationEntry entry1 = mCollectionListener.getEntry(notif1.key);
+
+ // WHEN the summary is dismissed but then reposted AND in the same update one of the
+ // children's ranking loses its override group
+ mCollection.dismissNotification(entry0, defaultStats(entry0));
+ mNoMan.setRanking(entry1.getKey(), new RankingBuilder()
+ .setKey(entry1.getKey())
+ .build());
+ mNoMan.postNotif(
+ buildNotif(TEST_PACKAGE, 0)
+ .setOverrideGroupKey(GROUP_1)
+ .setGroupSummary(mContext, true));
+
+ // THEN it and all of its previous children are no longer dismissed locally, including the
+ // child that is no longer part of the group
+ assertEquals(NOT_DISMISSED, entry0.getDismissState());
+ assertEquals(NOT_DISMISSED, entry1.getDismissState());
+ }
+
+ @Test
public void testLifetimeExtendersAreQueriedWhenNotifRemoved() {
// GIVEN a couple notifications and a few lifetime extenders
mExtender1.shouldExtendLifetime = true;
@@ -389,12 +574,12 @@ public class NotifCollectionTest extends SysuiTestCase {
NotificationEntry entry2 = mCollectionListener.getEntry(notif2.key);
// WHEN a notification is removed
- mNoMan.retractNotif(notif2.sbn, REASON_UNKNOWN);
+ mNoMan.retractNotif(notif2.sbn, REASON_CLICK);
// THEN each extender is asked whether to extend, even if earlier ones return true
- verify(mExtender1).shouldExtendLifetime(entry2, REASON_UNKNOWN);
- verify(mExtender2).shouldExtendLifetime(entry2, REASON_UNKNOWN);
- verify(mExtender3).shouldExtendLifetime(entry2, REASON_UNKNOWN);
+ verify(mExtender1).shouldExtendLifetime(entry2, REASON_CLICK);
+ verify(mExtender2).shouldExtendLifetime(entry2, REASON_CLICK);
+ verify(mExtender3).shouldExtendLifetime(entry2, REASON_CLICK);
// THEN the entry is not removed
assertTrue(mCollection.getActiveNotifs().contains(entry2));
@@ -428,9 +613,9 @@ public class NotifCollectionTest extends SysuiTestCase {
mExtender2.callback.onEndLifetimeExtension(mExtender2, entry2);
// THEN each extender is re-queried
- verify(mExtender1).shouldExtendLifetime(entry2, REASON_UNKNOWN);
- verify(mExtender2).shouldExtendLifetime(entry2, REASON_UNKNOWN);
- verify(mExtender3).shouldExtendLifetime(entry2, REASON_UNKNOWN);
+ verify(mExtender1).shouldExtendLifetime(entry2, REASON_APP_CANCEL);
+ verify(mExtender2).shouldExtendLifetime(entry2, REASON_APP_CANCEL);
+ verify(mExtender3).shouldExtendLifetime(entry2, REASON_APP_CANCEL);
// THEN the entry is not removed
assertTrue(mCollection.getActiveNotifs().contains(entry2));
@@ -466,9 +651,9 @@ public class NotifCollectionTest extends SysuiTestCase {
assertTrue(mCollection.getActiveNotifs().contains(entry2));
// THEN we don't re-query the extenders
- verify(mExtender1, never()).shouldExtendLifetime(eq(entry2), anyInt());
- verify(mExtender2, never()).shouldExtendLifetime(eq(entry2), anyInt());
- verify(mExtender3, never()).shouldExtendLifetime(eq(entry2), anyInt());
+ verify(mExtender1, never()).shouldExtendLifetime(entry2, REASON_APP_CANCEL);
+ verify(mExtender2, never()).shouldExtendLifetime(entry2, REASON_APP_CANCEL);
+ verify(mExtender3, never()).shouldExtendLifetime(entry2, REASON_APP_CANCEL);
// THEN the entry properly records all extenders that returned true
assertEquals(Arrays.asList(mExtender1), entry2.mLifetimeExtenders);
@@ -501,7 +686,7 @@ public class NotifCollectionTest extends SysuiTestCase {
// THEN the entry removed
assertFalse(mCollection.getActiveNotifs().contains(entry2));
- verify(mCollectionListener).onEntryRemoved(entry2, REASON_UNKNOWN, false);
+ verify(mCollectionListener).onEntryRemoved(entry2, REASON_UNKNOWN);
}
@Test
@@ -591,6 +776,36 @@ public class NotifCollectionTest extends SysuiTestCase {
assertEquals(notif2a.ranking, entry2.getRanking());
}
+ @Test
+ public void testCancellationReasonIsSetWhenNotifIsCancelled() {
+ // GIVEN a notification
+ NotifEvent notif0 = mNoMan.postNotif(buildNotif(TEST_PACKAGE, 3));
+ NotificationEntry entry0 = mCollectionListener.getEntry(notif0.key);
+
+ // WHEN the notification is retracted
+ mNoMan.retractNotif(notif0.sbn, REASON_APP_CANCEL);
+
+ // THEN the retraction reason is stored on the notif
+ assertEquals(REASON_APP_CANCEL, entry0.mCancellationReason);
+ }
+
+ @Test
+ public void testCancellationReasonIsClearedWhenNotifIsUpdated() {
+ // GIVEN a notification and a lifetime extender that will preserve it
+ NotifEvent notif0 = mNoMan.postNotif(buildNotif(TEST_PACKAGE, 3));
+ NotificationEntry entry0 = mCollectionListener.getEntry(notif0.key);
+ mCollection.addNotificationLifetimeExtender(mExtender1);
+ mExtender1.shouldExtendLifetime = true;
+
+ // WHEN the notification is retracted and subsequently reposted
+ mNoMan.retractNotif(notif0.sbn, REASON_APP_CANCEL);
+ assertEquals(REASON_APP_CANCEL, entry0.mCancellationReason);
+ mNoMan.postNotif(buildNotif(TEST_PACKAGE, 3));
+
+ // THEN the notification has its cancellation reason cleared
+ assertEquals(REASON_NOT_CANCELED, entry0.mCancellationReason);
+ }
+
private static NotificationEntryBuilder buildNotif(String pkg, int id, String tag) {
return new NotificationEntryBuilder()
.setPkg(pkg)
@@ -604,6 +819,13 @@ public class NotifCollectionTest extends SysuiTestCase {
.setId(id);
}
+ private static DismissedByUserStats defaultStats(NotificationEntry entry) {
+ return new DismissedByUserStats(
+ DISMISSAL_SHADE,
+ DISMISS_SENTIMENT_NEUTRAL,
+ NotificationVisibility.obtain(entry.getKey(), 7, 2, true));
+ }
+
private static class RecordingCollectionListener implements NotifCollectionListener {
private final Map<String, NotificationEntry> mLastSeenEntries = new ArrayMap<>();
@@ -621,7 +843,7 @@ public class NotifCollectionTest extends SysuiTestCase {
}
@Override
- public void onEntryRemoved(NotificationEntry entry, int reason, boolean removedByUser) {
+ public void onEntryRemoved(NotificationEntry entry, int reason) {
}
@Override
@@ -674,4 +896,6 @@ public class NotifCollectionTest extends SysuiTestCase {
private static final String TEST_PACKAGE = "com.android.test.collection";
private static final String TEST_PACKAGE2 = "com.android.test.collection2";
+
+ private static final String GROUP_1 = "group_1";
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
index 5bd5638b3d5a..70d76f0c3a52 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
@@ -63,6 +63,7 @@ import com.android.systemui.statusbar.RemoteInputController;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.notification.DynamicPrivacyController;
+import com.android.systemui.statusbar.notification.ForegroundServiceDismissalFeatureController;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.NotificationFilter;
import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager;
@@ -178,7 +179,9 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
mock(FeatureFlags.class),
() -> mock(NotificationRowBinder.class),
() -> mRemoteInputManager,
- mock(LeakDetector.class));
+ mock(LeakDetector.class),
+ mock(ForegroundServiceDismissalFeatureController.class)
+ );
mDependency.injectTestDependency(NotificationEntryManager.class, mEntryManager);
mEntryManager.setUpForTest(mock(NotificationPresenter.class), null, mHeadsUpManager);
@@ -203,7 +206,10 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
mLockscreenUserManager,
mock(NotificationGutsManager.class),
mZenModeController,
- mNotificationSectionsManager);
+ mNotificationSectionsManager,
+ mock(ForegroundServiceSectionController.class),
+ mock(ForegroundServiceDismissalFeatureController.class)
+ );
verify(mLockscreenUserManager).addUserChangedListener(userChangedCaptor.capture());
mUserChangedListener = userChangedCaptor.getValue();
mStackScroller = spy(mStackScrollerInternal);
@@ -394,8 +400,11 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
mStackScroller.onUpdateRowStates();
+ // Expecting the footer to be the last child
+ int expected = mStackScroller.getChildCount() - 1;
+
// move footer to end
- verify(mStackScroller).changeViewPosition(any(FooterView.class), eq(-1 /* end */));
+ verify(mStackScroller).changeViewPosition(any(FooterView.class), eq(expected));
}
@Test
diff --git a/packages/Tethering/res/values/config.xml b/packages/Tethering/res/values/config.xml
index c489cbcd5a1c..4af5c5371952 100644
--- a/packages/Tethering/res/values/config.xml
+++ b/packages/Tethering/res/values/config.xml
@@ -47,6 +47,7 @@
should be empty. An example would be "p2p-p2p\\d-.*" -->
<string-array translatable="false" name="config_tether_wifi_p2p_regexs">
<item>"p2p-p2p\\d-.*"</item>
+ <item>"p2p\\d"</item>
</string-array>
<!-- List of regexpressions describing the interface (if any) that represent tetherable
diff --git a/packages/overlays/Android.mk b/packages/overlays/Android.mk
index 8a3ac9404408..2bb673eba758 100644
--- a/packages/overlays/Android.mk
+++ b/packages/overlays/Android.mk
@@ -26,6 +26,7 @@ LOCAL_REQUIRED_MODULES := \
AccentColorPurpleOverlay \
DisplayCutoutEmulationCornerOverlay \
DisplayCutoutEmulationDoubleOverlay \
+ DisplayCutoutEmulationHoleOverlay \
DisplayCutoutEmulationTallOverlay \
FontNotoSerifSourceOverlay \
IconPackCircularAndroidOverlay \
diff --git a/packages/overlays/DisplayCutoutEmulationHoleOverlay/Android.mk b/packages/overlays/DisplayCutoutEmulationHoleOverlay/Android.mk
new file mode 100644
index 000000000000..6d8fc2493506
--- /dev/null
+++ b/packages/overlays/DisplayCutoutEmulationHoleOverlay/Android.mk
@@ -0,0 +1,14 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_RRO_THEME := DisplayCutoutEmulationHole
+
+
+LOCAL_PRODUCT_MODULE := true
+
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
+
+LOCAL_PACKAGE_NAME := DisplayCutoutEmulationHoleOverlay
+LOCAL_SDK_VERSION := current
+
+include $(BUILD_RRO_PACKAGE)
diff --git a/packages/overlays/DisplayCutoutEmulationHoleOverlay/AndroidManifest.xml b/packages/overlays/DisplayCutoutEmulationHoleOverlay/AndroidManifest.xml
new file mode 100644
index 000000000000..9fd82abd6c8c
--- /dev/null
+++ b/packages/overlays/DisplayCutoutEmulationHoleOverlay/AndroidManifest.xml
@@ -0,0 +1,26 @@
+<!--
+ ~ 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.internal.display.cutout.emulation.hole"
+ android:versionCode="1"
+ android:versionName="1.0">
+ <overlay android:targetPackage="android"
+ android:category="com.android.internal.display_cutout_emulation"
+ android:priority="1"/>
+
+ <application android:label="@string/display_cutout_emulation_overlay" android:hasCode="false"/>
+</manifest>
diff --git a/packages/overlays/DisplayCutoutEmulationHoleOverlay/res/values-land/config.xml b/packages/overlays/DisplayCutoutEmulationHoleOverlay/res/values-land/config.xml
new file mode 100644
index 000000000000..2e971ded2256
--- /dev/null
+++ b/packages/overlays/DisplayCutoutEmulationHoleOverlay/res/values-land/config.xml
@@ -0,0 +1,22 @@
+<!--
+ ~ 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>
+ <!-- Can't link to other dimensions here, but this should be status_bar_height_landscape -->
+ <dimen name="quick_qs_offset_height">28dp</dimen>
+ <!-- Total height of QQS in landscape; quick_qs_offset_height + 128 -->
+ <dimen name="quick_qs_total_height">156dp</dimen>
+</resources>
diff --git a/packages/overlays/DisplayCutoutEmulationHoleOverlay/res/values/config.xml b/packages/overlays/DisplayCutoutEmulationHoleOverlay/res/values/config.xml
new file mode 100644
index 000000000000..9f558d0e2bd5
--- /dev/null
+++ b/packages/overlays/DisplayCutoutEmulationHoleOverlay/res/values/config.xml
@@ -0,0 +1,61 @@
+<!--
+ ~ 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 xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+ <!-- The bounding path of the cutout region of the main built-in display.
+ Must either be empty if there is no cutout region, or a string that is parsable by
+ {@link android.util.PathParser}.
+
+ The path is assumed to be specified in display coordinates with pixel units and in
+ the display's native orientation, with the origin of the coordinate system at the
+ center top of the display.
+
+ To facilitate writing device-independent emulation overlays, the marker `@dp` can be
+ appended after the path string to interpret coordinates in dp instead of px units.
+ Note that a physical cutout should be configured in pixels for the best results.
+ -->
+ <!-- Display cutout configuration -->
+ <string translatable="false" name="config_mainBuiltInDisplayCutout">
+ M 128,83 A 44,44 0 0 1 84,127 44,44 0 0 1 40,83 44,44 0 0 1 84,39 44,44 0 0 1 128,83 Z
+ @left
+ </string>
+
+ <string translatable="false" name="config_mainBuiltInDisplayCutoutRectApproximation">
+ M 0.0,0.0
+ h 136
+ v 136
+ h -136
+ Z
+ @left
+ </string>
+
+ <!-- Whether the display cutout region of the main built-in display should be forced to
+ black in software (to avoid aliasing or emulate a cutout that is not physically existent).
+ -->
+ <bool name="config_fillMainBuiltInDisplayCutout">true</bool>
+
+ <!-- Height of the status bar -->
+ <dimen name="status_bar_height_portrait">136px</dimen>
+ <dimen name="status_bar_height_landscape">28dp</dimen>
+ <!-- Height of area above QQS where battery/time go (equal to status bar) -->
+ <dimen name="quick_qs_offset_height">136px</dimen>
+ <!-- Total height of QQS (quick_qs_offset_height + 128) -->
+ <dimen name="quick_qs_total_height">488px</dimen>
+
+</resources>
+
+
diff --git a/packages/overlays/DisplayCutoutEmulationHoleOverlay/res/values/strings.xml b/packages/overlays/DisplayCutoutEmulationHoleOverlay/res/values/strings.xml
new file mode 100644
index 000000000000..ab25695e7289
--- /dev/null
+++ b/packages/overlays/DisplayCutoutEmulationHoleOverlay/res/values/strings.xml
@@ -0,0 +1,22 @@
+<?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 xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+ <string name="display_cutout_emulation_overlay">Punch Hole cutout</string>
+
+</resources>
+
diff --git a/packages/overlays/IconShapePebbleOverlay/Android.mk b/packages/overlays/IconShapePebbleOverlay/Android.mk
new file mode 100644
index 000000000000..c163bb91f76a
--- /dev/null
+++ b/packages/overlays/IconShapePebbleOverlay/Android.mk
@@ -0,0 +1,29 @@
+#
+# 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.
+#
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_RRO_THEME := IconShapePebble
+
+LOCAL_PRODUCT_MODULE := true
+
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
+
+LOCAL_PACKAGE_NAME := IconShapePebbleOverlay
+LOCAL_SDK_VERSION := current
+
+include $(BUILD_RRO_PACKAGE)
diff --git a/packages/overlays/IconShapePebbleOverlay/AndroidManifest.xml b/packages/overlays/IconShapePebbleOverlay/AndroidManifest.xml
new file mode 100644
index 000000000000..6842dde36264
--- /dev/null
+++ b/packages/overlays/IconShapePebbleOverlay/AndroidManifest.xml
@@ -0,0 +1,29 @@
+<!--
+/**
+ * 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.theme.icon.pebble"
+ android:versionCode="1"
+ android:versionName="1.0">
+<overlay
+ android:targetPackage="android"
+ android:targetName="IconShapeCustomization"
+ android:category="android.theme.customization.adaptive_icon_shape"
+ android:priority="1"/>
+
+ <application android:label="@string/icon_shape_pebble_overlay" android:hasCode="false"/>
+</manifest>
diff --git a/packages/overlays/IconShapePebbleOverlay/res/values/config.xml b/packages/overlays/IconShapePebbleOverlay/res/values/config.xml
new file mode 100644
index 000000000000..2465fe015538
--- /dev/null
+++ b/packages/overlays/IconShapePebbleOverlay/res/values/config.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2019, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- Specifies the path that is used by AdaptiveIconDrawable class to crop launcher icons. -->
+ <string name="config_icon_mask" translatable="false">"MM55,0 C25,0 0,25 0,50 0,78 28,100 55,100 85,100 100,85 100,58 100,30 86,0 55,0 Z"</string>
+ <!-- Flag indicating whether round icons should be parsed from the application manifest. -->
+ <bool name="config_useRoundIcon">false</bool>
+ <!-- Corner radius of system dialogs -->
+ <dimen name="config_dialogCornerRadius">8dp</dimen>
+ <!-- Corner radius for bottom sheet system dialogs -->
+ <dimen name="config_bottomDialogCornerRadius">16dp</dimen>
+
+</resources>
+
diff --git a/packages/overlays/IconShapePebbleOverlay/res/values/strings.xml b/packages/overlays/IconShapePebbleOverlay/res/values/strings.xml
new file mode 100644
index 000000000000..aec4a82a6ba4
--- /dev/null
+++ b/packages/overlays/IconShapePebbleOverlay/res/values/strings.xml
@@ -0,0 +1,23 @@
+<?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.
+ */
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- Heart icon overlay -->
+ <string name="icon_shape_pebble_overlay" translatable="false">Pebble</string>
+
+</resources>
diff --git a/services/Android.bp b/services/Android.bp
index a58245361939..28c8aeea4e53 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -114,7 +114,7 @@ droidstubs {
srcs: [":services-all-sources"],
installable: false,
// TODO: remove the --hide options below
- args: " --show-annotation android.annotation.SystemApi\\(client=android.annotation.SystemApi.Client.MODULE_LIBRARIES,process=android.annotation.SystemApi.Process.SYSTEM_SERVER\\)" +
+ args: " --show-annotation android.annotation.SystemApi\\(client=android.annotation.SystemApi.Client.SYSTEM_SERVER\\)" +
" --hide-annotation android.annotation.Hide" +
" --hide-package com.google.android.startop.iorap" +
" --hide ReferencesHidden" +
diff --git a/services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java b/services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java
index 4f49fb7578a1..48d976b1504d 100644
--- a/services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java
+++ b/services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java
@@ -32,11 +32,14 @@ import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.service.appprediction.AppPredictionService;
import android.util.ArrayMap;
+import android.util.ArraySet;
import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
import com.android.server.infra.AbstractPerUserSystemService;
+import java.util.Map;
+import java.util.Set;
import java.util.function.Consumer;
/**
@@ -48,9 +51,13 @@ public class AppPredictionPerUserService extends
private static final String TAG = AppPredictionPerUserService.class.getSimpleName();
- @Nullable
+ /**
+ * A lookup of remote services in respect to their {@link ComponentName}.
+ */
+ @NonNull
@GuardedBy("mLock")
- private RemoteAppPredictionService mRemoteService;
+ private final ArrayMap<ComponentName, RemoteAppPredictionService> mRemoteServices =
+ new ArrayMap<>();
/**
* When {@code true}, remote service died but service state is kept so it's restored after
@@ -92,7 +99,7 @@ public class AppPredictionPerUserService extends
if (enabledChanged) {
if (!isEnabledLocked()) {
// Clear the remote service for the next call
- mRemoteService = null;
+ mRemoteServices.clear();
}
}
return enabledChanged;
@@ -104,14 +111,14 @@ public class AppPredictionPerUserService extends
@GuardedBy("mLock")
public void onCreatePredictionSessionLocked(@NonNull AppPredictionContext context,
@NonNull AppPredictionSessionId sessionId) {
- final RemoteAppPredictionService service = getRemoteServiceLocked();
+ if (!mSessionInfos.containsKey(sessionId)) {
+ mSessionInfos.put(sessionId, new AppPredictionSessionInfo(sessionId, context,
+ resolveComponentName(context), this::removeAppPredictionSessionInfo));
+ }
+ final RemoteAppPredictionService service = getRemoteServiceLocked(
+ getComponentName(sessionId));
if (service != null) {
service.onCreatePredictionSession(context, sessionId);
-
- if (!mSessionInfos.containsKey(sessionId)) {
- mSessionInfos.put(sessionId, new AppPredictionSessionInfo(sessionId, context,
- this::removeAppPredictionSessionInfo));
- }
}
}
@@ -121,7 +128,8 @@ public class AppPredictionPerUserService extends
@GuardedBy("mLock")
public void notifyAppTargetEventLocked(@NonNull AppPredictionSessionId sessionId,
@NonNull AppTargetEvent event) {
- final RemoteAppPredictionService service = getRemoteServiceLocked();
+ final RemoteAppPredictionService service = getRemoteServiceLocked(
+ getComponentName(sessionId));
if (service != null) {
service.notifyAppTargetEvent(sessionId, event);
}
@@ -133,7 +141,8 @@ public class AppPredictionPerUserService extends
@GuardedBy("mLock")
public void notifyLaunchLocationShownLocked(@NonNull AppPredictionSessionId sessionId,
@NonNull String launchLocation, @NonNull ParceledListSlice targetIds) {
- final RemoteAppPredictionService service = getRemoteServiceLocked();
+ final RemoteAppPredictionService service = getRemoteServiceLocked(
+ getComponentName(sessionId));
if (service != null) {
service.notifyLaunchLocationShown(sessionId, launchLocation, targetIds);
}
@@ -145,7 +154,8 @@ public class AppPredictionPerUserService extends
@GuardedBy("mLock")
public void sortAppTargetsLocked(@NonNull AppPredictionSessionId sessionId,
@NonNull ParceledListSlice targets, @NonNull IPredictionCallback callback) {
- final RemoteAppPredictionService service = getRemoteServiceLocked();
+ final RemoteAppPredictionService service = getRemoteServiceLocked(
+ getComponentName(sessionId));
if (service != null) {
service.sortAppTargets(sessionId, targets, callback);
}
@@ -157,7 +167,8 @@ public class AppPredictionPerUserService extends
@GuardedBy("mLock")
public void registerPredictionUpdatesLocked(@NonNull AppPredictionSessionId sessionId,
@NonNull IPredictionCallback callback) {
- final RemoteAppPredictionService service = getRemoteServiceLocked();
+ final RemoteAppPredictionService service = getRemoteServiceLocked(
+ getComponentName(sessionId));
if (service != null) {
service.registerPredictionUpdates(sessionId, callback);
@@ -174,7 +185,8 @@ public class AppPredictionPerUserService extends
@GuardedBy("mLock")
public void unregisterPredictionUpdatesLocked(@NonNull AppPredictionSessionId sessionId,
@NonNull IPredictionCallback callback) {
- final RemoteAppPredictionService service = getRemoteServiceLocked();
+ final RemoteAppPredictionService service = getRemoteServiceLocked(
+ getComponentName(sessionId));
if (service != null) {
service.unregisterPredictionUpdates(sessionId, callback);
@@ -190,7 +202,8 @@ public class AppPredictionPerUserService extends
*/
@GuardedBy("mLock")
public void requestPredictionUpdateLocked(@NonNull AppPredictionSessionId sessionId) {
- final RemoteAppPredictionService service = getRemoteServiceLocked();
+ final RemoteAppPredictionService service = getRemoteServiceLocked(
+ getComponentName(sessionId));
if (service != null) {
service.requestPredictionUpdate(sessionId);
}
@@ -201,7 +214,8 @@ public class AppPredictionPerUserService extends
*/
@GuardedBy("mLock")
public void onDestroyPredictionSessionLocked(@NonNull AppPredictionSessionId sessionId) {
- final RemoteAppPredictionService service = getRemoteServiceLocked();
+ final RemoteAppPredictionService service = getRemoteServiceLocked(
+ getComponentName(sessionId));
if (service != null) {
service.onDestroyPredictionSession(sessionId);
@@ -229,7 +243,7 @@ public class AppPredictionPerUserService extends
synchronized (mLock) {
if (mZombie) {
// Sanity check - shouldn't happen
- if (mRemoteService == null) {
+ if (mRemoteServices.isEmpty()) {
Slog.w(TAG, "Cannot resurrect sessions because remote service is null");
return;
}
@@ -266,22 +280,30 @@ public class AppPredictionPerUserService extends
}
private void destroyAndRebindRemoteService() {
- if (mRemoteService == null) {
+ if (mRemoteServices.isEmpty()) {
return;
}
if (isDebug()) {
Slog.d(TAG, "Destroying the old remote service.");
}
- mRemoteService.destroy();
- mRemoteService = null;
+ final Set<Map.Entry<ComponentName, RemoteAppPredictionService>> services =
+ new ArraySet<>(mRemoteServices.entrySet());
+ mRemoteServices.clear();
+ services.stream().forEach(entry -> destroyAndRebindRemoteService(
+ entry.getKey(), entry.getValue()));
+ }
- mRemoteService = getRemoteServiceLocked();
- if (mRemoteService != null) {
+ private void destroyAndRebindRemoteService(
+ @NonNull final ComponentName component,
+ @NonNull final RemoteAppPredictionService service) {
+ service.destroy();
+ final RemoteAppPredictionService newService = getRemoteServiceLocked(component);
+ if (newService != null) {
if (isDebug()) {
Slog.d(TAG, "Rebinding to the new remote service.");
}
- mRemoteService.reconnect();
+ newService.reconnect();
}
}
@@ -292,7 +314,7 @@ public class AppPredictionPerUserService extends
private void resurrectSessionsLocked() {
final int numSessions = mSessionInfos.size();
if (isDebug()) {
- Slog.d(TAG, "Resurrecting remote service (" + mRemoteService + ") on "
+ Slog.d(TAG, "Resurrecting remote service (" + mRemoteServices + ") on "
+ numSessions + " sessions.");
}
@@ -310,32 +332,49 @@ public class AppPredictionPerUserService extends
}
}
- @GuardedBy("mLock")
@Nullable
- private RemoteAppPredictionService getRemoteServiceLocked() {
- if (mRemoteService == null) {
- final String serviceName = getComponentNameLocked();
- if (serviceName == null) {
- if (mMaster.verbose) {
- Slog.v(TAG, "getRemoteServiceLocked(): not set");
- }
- return null;
+ private ComponentName resolveComponentName(@NonNull final AppPredictionContext context) {
+ // TODO: add logic to determine serviceName based on context
+ final String serviceName = getComponentNameLocked();
+ if (serviceName == null) {
+ if (mMaster.verbose) {
+ Slog.v(TAG, "getRemoteServiceLocked(): not set, context = " + context);
}
- ComponentName serviceComponent = ComponentName.unflattenFromString(serviceName);
+ return null;
+ }
+ return ComponentName.unflattenFromString(serviceName);
+ }
+
+ @Nullable
+ private ComponentName getComponentName(@NonNull final AppPredictionSessionId sessionId) {
+ AppPredictionSessionInfo sessionInfo = mSessionInfos.get(sessionId);
+ return sessionInfo == null ? null : sessionInfo.mComponentName;
+ }
- mRemoteService = new RemoteAppPredictionService(getContext(),
+ @GuardedBy("mLock")
+ @Nullable
+ private RemoteAppPredictionService getRemoteServiceLocked(
+ @Nullable final ComponentName serviceComponent) {
+ if (serviceComponent == null) return null;
+ if (!mRemoteServices.containsKey(serviceComponent)) {
+ mRemoteServices.put(serviceComponent, new RemoteAppPredictionService(getContext(),
AppPredictionService.SERVICE_INTERFACE, serviceComponent, mUserId, this,
- mMaster.isBindInstantServiceAllowed(), mMaster.verbose);
+ mMaster.isBindInstantServiceAllowed(), mMaster.verbose));
}
- return mRemoteService;
+ return mRemoteServices.get(serviceComponent);
}
private static final class AppPredictionSessionInfo {
private static final boolean DEBUG = false; // Do not submit with true
+ @NonNull
private final AppPredictionSessionId mSessionId;
+ @NonNull
private final AppPredictionContext mPredictionContext;
+ @Nullable
+ private final ComponentName mComponentName;
+ @NonNull
private final Consumer<AppPredictionSessionId> mRemoveSessionInfoAction;
private final RemoteCallbackList<IPredictionCallback> mCallbacks =
@@ -352,13 +391,17 @@ public class AppPredictionPerUserService extends
}
};
- AppPredictionSessionInfo(AppPredictionSessionId id, AppPredictionContext predictionContext,
- Consumer<AppPredictionSessionId> removeSessionInfoAction) {
+ AppPredictionSessionInfo(
+ @NonNull final AppPredictionSessionId id,
+ @NonNull final AppPredictionContext predictionContext,
+ @Nullable final ComponentName componentName,
+ @NonNull final Consumer<AppPredictionSessionId> removeSessionInfoAction) {
if (DEBUG) {
Slog.d(TAG, "Creating AppPredictionSessionInfo for session Id=" + id);
}
mSessionId = id;
mPredictionContext = predictionContext;
+ mComponentName = componentName;
mRemoveSessionInfoAction = removeSessionInfoAction;
}
@@ -390,8 +433,8 @@ public class AppPredictionPerUserService extends
void resurrectSessionLocked(AppPredictionPerUserService service) {
int callbackCount = mCallbacks.getRegisteredCallbackCount();
if (DEBUG) {
- Slog.d(TAG, "Resurrecting remote service (" + service.getRemoteServiceLocked()
- + ") for session Id=" + mSessionId + " and "
+ Slog.d(TAG, "Resurrecting remote service (" + service.getRemoteServiceLocked(
+ mComponentName) + ") for session Id=" + mSessionId + " and "
+ callbackCount + " callbacks.");
}
service.onCreatePredictionSessionLocked(mPredictionContext, mSessionId);
diff --git a/services/backup/backuplib/java/com/android/server/backup/transport/TransportClient.java b/services/backup/backuplib/java/com/android/server/backup/transport/TransportClient.java
index 7c5a57c004e4..ca89f7f69fbc 100644
--- a/services/backup/backuplib/java/com/android/server/backup/transport/TransportClient.java
+++ b/services/backup/backuplib/java/com/android/server/backup/transport/TransportClient.java
@@ -26,6 +26,7 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
+import android.os.Binder;
import android.os.DeadObjectException;
import android.os.Handler;
import android.os.IBinder;
@@ -662,6 +663,10 @@ public class TransportClient {
referenceLost("TransportConnection.onServiceConnected()");
return;
}
+ // TODO (b/147705255): Remove when binder calls to IBackupTransport are not blocking
+ // In short-term, blocking calls are OK as the transports come from the whitelist at
+ // {@link SystemConfig#getBackupTransportWhitelist()}
+ Binder.allowBlocking(binder);
transportClient.onServiceConnected(binder);
}
diff --git a/services/core/java/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java
index 27b6bfb8f5fd..bdcd832e4f4a 100644
--- a/services/core/java/android/content/pm/PackageManagerInternal.java
+++ b/services/core/java/android/content/pm/PackageManagerInternal.java
@@ -67,6 +67,7 @@ public abstract class PackageManagerInternal {
public static final int PACKAGE_TELEPHONY = 12;
public static final int PACKAGE_WIFI = 13;
public static final int PACKAGE_COMPANION = 14;
+ public static final int PACKAGE_RETAIL_DEMO = 15;
@IntDef(value = {
INTEGRITY_VERIFICATION_ALLOW,
@@ -105,6 +106,7 @@ public abstract class PackageManagerInternal {
PACKAGE_TELEPHONY,
PACKAGE_WIFI,
PACKAGE_COMPANION,
+ PACKAGE_RETAIL_DEMO,
})
@Retention(RetentionPolicy.SOURCE)
public @interface KnownPackage {}
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index a1a953f86505..2968a816835d 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -6192,12 +6192,16 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
}
- private void sendUpdatedScoreToFactories(NetworkRequest networkRequest, NetworkAgentInfo nai) {
- int score = 0;
- int serial = 0;
+ private void sendUpdatedScoreToFactories(@NonNull NetworkRequest networkRequest,
+ @Nullable NetworkAgentInfo nai) {
+ final int score;
+ final int serial;
if (nai != null) {
score = nai.getCurrentScore();
serial = nai.factorySerialNumber;
+ } else {
+ score = 0;
+ serial = 0;
}
if (VDBG || DDBG){
log("sending new Min Network Score(" + score + "): " + networkRequest.toString());
@@ -6360,20 +6364,28 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
}
- private void makeDefault(@NonNull final NetworkAgentInfo newNetwork) {
+ private void makeDefault(@Nullable final NetworkAgentInfo newNetwork) {
if (DBG) log("Switching to new default network: " + newNetwork);
+ mDefaultNetworkNai = newNetwork;
+
try {
- mNMS.setDefaultNetId(newNetwork.network.netId);
+ if (null != newNetwork) {
+ mNMS.setDefaultNetId(newNetwork.network.netId);
+ } else {
+ mNMS.clearDefaultNetId();
+ }
} catch (Exception e) {
loge("Exception setting default network :" + e);
}
- mDefaultNetworkNai = newNetwork;
notifyLockdownVpn(newNetwork);
- handleApplyDefaultProxy(newNetwork.linkProperties.getHttpProxy());
- updateTcpBufferSizes(newNetwork.linkProperties.getTcpBufferSizes());
- mDnsManager.setDefaultDnsSystemProperties(newNetwork.linkProperties.getDnsServers());
+ handleApplyDefaultProxy(null != newNetwork
+ ? newNetwork.linkProperties.getHttpProxy() : null);
+ updateTcpBufferSizes(null != newNetwork
+ ? newNetwork.linkProperties.getTcpBufferSizes() : null);
+ mDnsManager.setDefaultDnsSystemProperties(null != newNetwork
+ ? newNetwork.linkProperties.getDnsServers() : Collections.EMPTY_LIST);
notifyIfacesChangedForNetworkStats();
// Fix up the NetworkCapabilities of any VPNs that don't specify underlying networks.
updateAllVpnsCapabilities();
@@ -6452,6 +6464,16 @@ public class ConnectivityService extends IConnectivityManager.Stub
void addRematchedNetwork(@NonNull final NetworkBgStatePair network) {
mRematchedNetworks.add(network);
}
+
+ // Will return null if this reassignment does not change the network assigned to
+ // the passed request.
+ @Nullable
+ private RequestReassignment getReassignment(@NonNull final NetworkRequestInfo nri) {
+ for (final RequestReassignment event : getRequestReassignments()) {
+ if (nri == event.mRequest) return event;
+ }
+ return null;
+ }
}
private ArrayMap<NetworkRequestInfo, NetworkAgentInfo> computeRequestReassignmentForNetwork(
@@ -6518,8 +6540,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
@NonNull final NetworkAgentInfo newNetwork, final long now) {
ensureRunningOnConnectivityServiceThread();
if (!newNetwork.everConnected) return;
- boolean isNewDefault = false;
- NetworkAgentInfo oldDefaultNetwork = null;
changes.addRematchedNetwork(new NetworkReassignment.NetworkBgStatePair(newNetwork,
newNetwork.isBackgroundNetwork()));
@@ -6536,6 +6556,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
final NetworkRequestInfo nri = entry.getKey();
final NetworkAgentInfo previousSatisfier = nri.mSatisfier;
final NetworkAgentInfo newSatisfier = entry.getValue();
+ changes.addRequestReassignment(new NetworkReassignment.RequestReassignment(
+ nri, previousSatisfier, newSatisfier));
if (newSatisfier != null) {
if (VDBG) log("rematch for " + newSatisfier.name());
if (previousSatisfier != null) {
@@ -6548,25 +6570,9 @@ public class ConnectivityService extends IConnectivityManager.Stub
if (VDBG || DDBG) log(" accepting network in place of null");
}
newSatisfier.unlingerRequest(nri.request);
- nri.mSatisfier = newSatisfier;
if (!newSatisfier.addRequest(nri.request)) {
Slog.wtf(TAG, "BUG: " + newSatisfier.name() + " already has " + nri.request);
}
- changes.addRequestReassignment(new NetworkReassignment.RequestReassignment(
- nri, previousSatisfier, newSatisfier));
- // Tell NetworkProviders about the new score, so they can stop
- // trying to connect if they know they cannot match it.
- // TODO - this could get expensive if we have a lot of requests for this
- // network. Think about if there is a way to reduce this. Push
- // netid->request mapping to each provider?
- sendUpdatedScoreToFactories(nri.request, newSatisfier);
- if (isDefaultRequest(nri)) {
- isNewDefault = true;
- oldDefaultNetwork = previousSatisfier;
- if (previousSatisfier != null) {
- mLingerMonitor.noteLingerDefaultNetwork(previousSatisfier, newSatisfier);
- }
- }
} else {
// If "newNetwork" is listed as satisfying "nri" but no longer satisfies "nri",
// mark it as no longer satisfying "nri". Because networks are processed by
@@ -6580,35 +6586,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
" request " + nri.request.requestId);
}
newNetwork.removeRequest(nri.request.requestId);
- if (previousSatisfier == newNetwork) {
- nri.mSatisfier = null;
- if (isDefaultRequest(nri)) mDefaultNetworkNai = null;
- sendUpdatedScoreToFactories(nri.request, null);
- } else {
- Slog.wtf(TAG, "BUG: Removing request " + nri.request.requestId + " from " +
- newNetwork.name() +
- " without updating mSatisfier or providers!");
- }
- // TODO: Technically, sending CALLBACK_LOST here is
- // incorrect if there is a replacement network currently
- // connected that can satisfy nri, which is a request
- // (not a listen). However, the only capability that can both
- // a) be requested and b) change is NET_CAPABILITY_TRUSTED,
- // so this code is only incorrect for a network that loses
- // the TRUSTED capability, which is a rare case.
- callCallbackForRequest(nri, newNetwork, ConnectivityManager.CALLBACK_LOST, 0);
}
- }
-
- if (isNewDefault) {
- updateDataActivityTracking(newNetwork, oldDefaultNetwork);
- // Notify system services that this network is up.
- makeDefault(newNetwork);
- // Log 0 -> X and Y -> X default network transitions, where X is the new default.
- mDeps.getMetricsLogger().defaultNetworkMetrics().logDefaultNetworkEvent(
- now, newNetwork, oldDefaultNetwork);
- // Have a new default network, release the transition wakelock in
- scheduleReleaseNetworkTransitionWakelock();
+ nri.mSatisfier = newSatisfier;
}
}
@@ -6636,14 +6615,48 @@ public class ConnectivityService extends IConnectivityManager.Stub
rematchNetworkAndRequests(changes, nai, now);
}
- final NetworkAgentInfo newDefaultNetwork = getDefaultNetwork();
+ final NetworkRequestInfo defaultRequestInfo = mNetworkRequests.get(mDefaultRequest);
+ final NetworkReassignment.RequestReassignment reassignment =
+ changes.getReassignment(defaultRequestInfo);
+ final NetworkAgentInfo newDefaultNetwork =
+ null != reassignment ? reassignment.mNewNetwork : oldDefaultNetwork;
+
+ if (oldDefaultNetwork != newDefaultNetwork) {
+ if (oldDefaultNetwork != null) {
+ mLingerMonitor.noteLingerDefaultNetwork(oldDefaultNetwork, newDefaultNetwork);
+ }
+ updateDataActivityTracking(newDefaultNetwork, oldDefaultNetwork);
+ // Notify system services of the new default.
+ makeDefault(newDefaultNetwork);
+ // Log 0 -> X and Y -> X default network transitions, where X is the new default.
+ mDeps.getMetricsLogger().defaultNetworkMetrics().logDefaultNetworkEvent(
+ now, newDefaultNetwork, oldDefaultNetwork);
+ // Have a new default network, release the transition wakelock in
+ scheduleReleaseNetworkTransitionWakelock();
+ }
// Notify requested networks are available after the default net is switched, but
// before LegacyTypeTracker sends legacy broadcasts
for (final NetworkReassignment.RequestReassignment event :
changes.getRequestReassignments()) {
+ // Tell NetworkProviders about the new score, so they can stop
+ // trying to connect if they know they cannot match it.
+ // TODO - this could get expensive if there are a lot of outstanding requests for this
+ // network. Think of a way to reduce this. Push netid->request mapping to each factory?
+ sendUpdatedScoreToFactories(event.mRequest.request, event.mNewNetwork);
+
if (null != event.mNewNetwork) {
notifyNetworkAvailable(event.mNewNetwork, event.mRequest);
+ } else {
+ // TODO: Technically, sending CALLBACK_LOST here is
+ // incorrect if there is a replacement network currently
+ // connected that can satisfy nri, which is a request
+ // (not a listen). However, the only capability that can both
+ // a) be requested and b) change is NET_CAPABILITY_TRUSTED,
+ // so this code is only incorrect for a network that loses
+ // the TRUSTED capability, which is a rare case.
+ callCallbackForRequest(event.mRequest, event.mOldNetwork,
+ ConnectivityManager.CALLBACK_LOST, 0);
}
}
diff --git a/services/core/java/com/android/server/SystemService.java b/services/core/java/com/android/server/SystemService.java
index b1584fea90c1..e3c732523264 100644
--- a/services/core/java/com/android/server/SystemService.java
+++ b/services/core/java/com/android/server/SystemService.java
@@ -23,7 +23,6 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.annotation.SystemApi.Client;
-import android.annotation.SystemApi.Process;
import android.annotation.UserIdInt;
import android.app.ActivityThread;
import android.content.Context;
@@ -65,7 +64,7 @@ import java.util.List;
*
* {@hide}
*/
-@SystemApi(client = Client.MODULE_LIBRARIES, process = Process.SYSTEM_SERVER)
+@SystemApi(client = Client.SYSTEM_SERVER)
public abstract class SystemService {
/** @hide */
@@ -132,7 +131,7 @@ public abstract class SystemService {
* Class representing user in question in the lifecycle callbacks.
* @hide
*/
- @SystemApi(client = Client.MODULE_LIBRARIES, process = Process.SYSTEM_SERVER)
+ @SystemApi(client = Client.SYSTEM_SERVER)
public static final class TargetUser {
@NonNull
private final UserInfo mUserInfo;
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 56f942480eaf..cbf6c274e865 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -285,7 +285,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR
| PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR
| PhoneStateListener.LISTEN_EMERGENCY_NUMBER_LIST
- | PhoneStateListener.LISTEN_REGISTRATION_FAILURE;
+ | PhoneStateListener.LISTEN_REGISTRATION_FAILURE
+ | PhoneStateListener.LISTEN_BARRING_INFO;
static final int PRECISE_PHONE_STATE_PERMISSION_MASK =
PhoneStateListener.LISTEN_PRECISE_CALL_STATE
diff --git a/services/core/java/com/android/server/VibratorService.java b/services/core/java/com/android/server/VibratorService.java
index 79b3a7b0d114..f7d7d6c5d15f 100644
--- a/services/core/java/com/android/server/VibratorService.java
+++ b/services/core/java/com/android/server/VibratorService.java
@@ -65,13 +65,13 @@ import android.provider.Settings.SettingNotFoundException;
import android.util.DebugUtils;
import android.util.Slog;
import android.util.SparseArray;
-import android.util.StatsLog;
import android.util.proto.ProtoOutputStream;
import android.view.InputDevice;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.app.IBatteryStats;
import com.android.internal.util.DumpUtils;
+import com.android.internal.util.FrameworkStatsLog;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -1370,8 +1370,8 @@ public class VibratorService extends IVibratorService.Stub
private void noteVibratorOnLocked(int uid, long millis) {
try {
mBatteryStatsService.noteVibratorOn(uid, millis);
- StatsLog.write_non_chained(StatsLog.VIBRATOR_STATE_CHANGED, uid, null,
- StatsLog.VIBRATOR_STATE_CHANGED__STATE__ON, millis);
+ FrameworkStatsLog.write_non_chained(FrameworkStatsLog.VIBRATOR_STATE_CHANGED, uid, null,
+ FrameworkStatsLog.VIBRATOR_STATE_CHANGED__STATE__ON, millis);
mCurVibUid = uid;
mIsVibrating = true;
} catch (RemoteException e) {
@@ -1382,8 +1382,8 @@ public class VibratorService extends IVibratorService.Stub
if (mCurVibUid >= 0) {
try {
mBatteryStatsService.noteVibratorOff(mCurVibUid);
- StatsLog.write_non_chained(StatsLog.VIBRATOR_STATE_CHANGED, mCurVibUid, null,
- StatsLog.VIBRATOR_STATE_CHANGED__STATE__OFF, 0);
+ FrameworkStatsLog.write_non_chained(FrameworkStatsLog.VIBRATOR_STATE_CHANGED,
+ mCurVibUid, null, FrameworkStatsLog.VIBRATOR_STATE_CHANGED__STATE__OFF, 0);
} catch (RemoteException e) { }
mCurVibUid = -1;
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 6560777edd53..148f7de4449f 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -5143,14 +5143,12 @@ public class ActivityManagerService extends IActivityManager.Stub
checkTime(startTime, "attachApplicationLocked: after updateLruProcessLocked");
app.lastRequestedGc = app.lastLowMemory = SystemClock.uptimeMillis();
} catch (Exception e) {
- // todo: Yikes! What should we do? For now we will try to
- // start another process, but that could easily get us in
- // an infinite loop of restarting processes...
+ // We need kill the process group here. (b/148588589)
Slog.wtf(TAG, "Exception thrown during bind of " + app, e);
-
app.resetPackageList(mProcessStats);
app.unlinkDeathRecipient();
- mProcessList.startProcessLocked(app, new HostingRecord("bind-fail", processName));
+ app.kill("error during bind", ApplicationExitInfo.REASON_INITIALIZATION_FAILURE, true);
+ handleAppDiedLocked(app, false, true);
return false;
}
@@ -18924,19 +18922,16 @@ public class ActivityManagerService extends IActivityManager.Stub
}
// The arguments here are untyped because the base ActivityManagerInternal class
- // doesn't have compile-time visiblity into ActivityServiceConnectionHolder or
+ // doesn't have compile-time visibility into ActivityServiceConnectionHolder or
// ConnectionRecord.
@Override
- public void disconnectActivityFromServices(Object connectionHolder, Object conns) {
+ public void disconnectActivityFromServices(Object connectionHolder) {
// 'connectionHolder' is an untyped ActivityServiceConnectionsHolder
- // 'conns' is an untyped HashSet<ConnectionRecord>
final ActivityServiceConnectionsHolder holder =
(ActivityServiceConnectionsHolder) connectionHolder;
- final HashSet<ConnectionRecord> toDisconnect = (HashSet<ConnectionRecord>) conns;
- synchronized(ActivityManagerService.this) {
- for (ConnectionRecord cr : toDisconnect) {
- mServices.removeConnectionLocked(cr, null, holder);
- }
+ synchronized (ActivityManagerService.this) {
+ holder.forEachConnection(cr -> mServices.removeConnectionLocked(
+ (ConnectionRecord) cr, null /* skipApp */, holder /* skipAct */));
}
}
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 3c7d6b80f557..71486d3686f3 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -1572,8 +1572,11 @@ public final class ProcessList {
if (userGid != UserHandle.ERR_GID) {
gidList.add(userGid);
}
- if (mountExternal == Zygote.MOUNT_EXTERNAL_ANDROID_WRITABLE) {
+ if (mountExternal == Zygote.MOUNT_EXTERNAL_ANDROID_WRITABLE
+ || mountExternal == Zygote.MOUNT_EXTERNAL_PASS_THROUGH) {
// For DownloadProviders and MTP: To grant access to /sdcard/Android/
+ // And a special case for the FUSE daemon since it runs an MTP server and should have
+ // access to Android/
gidList.add(UserHandle.getUid(UserHandle.getUserId(uid), Process.SDCARD_RW_GID));
}
if (mountExternal == Zygote.MOUNT_EXTERNAL_PASS_THROUGH) {
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index fc33c25c4eaf..2b4d15eda9f0 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -615,13 +615,20 @@ class ProcessRecord implements WindowProcessListener {
int _uid) {
mService = _service;
info = _info;
+ ProcessInfo procInfo = null;
if (_service.mPackageManagerInt != null) {
ArrayMap<String, ProcessInfo> processes =
_service.mPackageManagerInt.getProcessesForUid(_uid);
- processInfo = processes != null ? processes.get(_processName) : null;
- } else {
- processInfo = null;
+ if (processes != null) {
+ procInfo = processes.get(_processName);
+ if (procInfo != null && procInfo.deniedPermissions == null) {
+ // If this process hasn't asked for permissions to be denied, then
+ // we don't care about it.
+ procInfo = null;
+ }
+ }
}
+ processInfo = procInfo;
isolated = _info.uid != _uid;
appZygote = (UserHandle.getAppId(_uid) >= Process.FIRST_APP_ZYGOTE_ISOLATED_UID
&& UserHandle.getAppId(_uid) <= Process.LAST_APP_ZYGOTE_ISOLATED_UID);
diff --git a/services/core/java/com/android/server/am/TEST_MAPPING b/services/core/java/com/android/server/am/TEST_MAPPING
index bc4707f04724..4061df4f3f62 100644
--- a/services/core/java/com/android/server/am/TEST_MAPPING
+++ b/services/core/java/com/android/server/am/TEST_MAPPING
@@ -54,6 +54,14 @@
"include-filter": "com.android.server.am."
}
]
+ },
+ {
+ "name": "CtsAppSecurityHostTestCases",
+ "options": [
+ {
+ "include-filter": "android.appsecurity.cts.AppDataIsolationTests"
+ }
+ ]
}
]
}
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index 531bc5d1c7df..ee2d7fcd5d62 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -846,7 +846,12 @@ public class AppOpsService extends IAppOpsService.Stub {
*/
public void started(@NonNull IBinder clientId, @AppOpsManager.UidState int uidState)
throws RemoteException {
- if (!parent.isRunning()) {
+ started(clientId, uidState, true);
+ }
+
+ private void started(@NonNull IBinder clientId, @AppOpsManager.UidState int uidState,
+ boolean triggerCallbackIfNeeded) throws RemoteException {
+ if (triggerCallbackIfNeeded && !parent.isRunning()) {
scheduleOpActiveChangedIfNeededLocked(parent.op, parent.uid,
parent.packageName, true);
}
@@ -965,8 +970,16 @@ public class AppOpsService extends IAppOpsService.Stub {
if (event.getUidState() != newState) {
try {
+ // Remove all but one unfinished start count and then call finished() to
+ // remove start event object
+ int numPreviousUnfinishedStarts = event.numUnfinishedStarts;
+ event.numUnfinishedStarts = 1;
finished(event.getClientId(), false);
- started(event.getClientId(), newState);
+
+ // Call started() to add a new start event object and then add the
+ // previously removed unfinished start counts back
+ started(event.getClientId(), newState, false);
+ event.numUnfinishedStarts += numPreviousUnfinishedStarts - 1;
} catch (RemoteException e) {
if (DEBUG) Slog.e(TAG, "Cannot switch to new uidState " + newState);
}
@@ -1948,6 +1961,11 @@ public class AppOpsService extends IAppOpsService.Stub {
@Override
public void setUidMode(int code, int uid, int mode) {
+ setUidMode(code, uid, mode, null);
+ }
+
+ private void setUidMode(int code, int uid, int mode,
+ @Nullable IAppOpsCallback callbackToIgnore) {
if (DEBUG) {
Slog.i(TAG, "uid " + uid + " OP_" + opToName(code) + " := " + modeToName(mode)
+ " by uid " + Binder.getCallingUid());
@@ -2031,6 +2049,10 @@ public class AppOpsService extends IAppOpsService.Stub {
}
}
}
+
+ if (callbackSpecs != null && callbackToIgnore != null) {
+ callbackSpecs.remove(mModeWatchers.get(callbackToIgnore.asBinder()));
+ }
}
if (callbackSpecs == null) {
@@ -2078,6 +2100,11 @@ public class AppOpsService extends IAppOpsService.Stub {
continue;
}
+ if (packageManager.checkPermission(permissionName, packageName)
+ != PackageManager.PERMISSION_GRANTED) {
+ continue;
+ }
+
PermissionInfo permissionInfo;
try {
permissionInfo = packageManager.getPermissionInfo(permissionName, 0);
@@ -2158,6 +2185,11 @@ public class AppOpsService extends IAppOpsService.Stub {
*/
@Override
public void setMode(int code, int uid, @NonNull String packageName, int mode) {
+ setMode(code, uid, packageName, mode, null);
+ }
+
+ private void setMode(int code, int uid, @NonNull String packageName, int mode,
+ @Nullable IAppOpsCallback callbackToIgnore) {
enforceManageAppOpsModes(Binder.getCallingPid(), Binder.getCallingUid(), uid);
verifyIncomingOp(code);
ArraySet<ModeCallback> repCbs = null;
@@ -2201,6 +2233,9 @@ public class AppOpsService extends IAppOpsService.Stub {
}
repCbs.addAll(cbs);
}
+ if (repCbs != null && callbackToIgnore != null) {
+ repCbs.remove(mModeWatchers.get(callbackToIgnore.asBinder()));
+ }
if (mode == AppOpsManager.opToDefaultMode(op.op)) {
// If going into the default mode, prune this op
// if there is nothing else interesting in it.
@@ -5587,5 +5622,17 @@ public class AppOpsService extends IAppOpsService.Stub {
boolean visible) {
AppOpsService.this.updateAppWidgetVisibility(uidPackageNames, visible);
}
+
+ @Override
+ public void setUidModeIgnoringCallback(int code, int uid, int mode,
+ @Nullable IAppOpsCallback callbackToIgnore) {
+ setUidMode(code, uid, mode, callbackToIgnore);
+ }
+
+ @Override
+ public void setModeIgnoringCallback(int code, int uid, @NonNull String packageName,
+ int mode, @Nullable IAppOpsCallback callbackToIgnore) {
+ setMode(code, uid, packageName, mode, callbackToIgnore);
+ }
}
}
diff --git a/services/core/java/com/android/server/connectivity/LingerMonitor.java b/services/core/java/com/android/server/connectivity/LingerMonitor.java
index 929dfc4d1511..707151059869 100644
--- a/services/core/java/com/android/server/connectivity/LingerMonitor.java
+++ b/services/core/java/com/android/server/connectivity/LingerMonitor.java
@@ -16,6 +16,10 @@
package com.android.server.connectivity;
+import static android.net.ConnectivityManager.NETID_UNSET;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.Context;
@@ -27,18 +31,16 @@ import android.text.TextUtils;
import android.text.format.DateUtils;
import android.util.Log;
import android.util.SparseArray;
-import android.util.SparseIntArray;
import android.util.SparseBooleanArray;
-import java.util.Arrays;
-import java.util.HashMap;
+import android.util.SparseIntArray;
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.MessageUtils;
-import com.android.server.connectivity.NetworkNotificationManager;
import com.android.server.connectivity.NetworkNotificationManager.NotificationType;
-import static android.net.ConnectivityManager.NETID_UNSET;
+import java.util.Arrays;
+import java.util.HashMap;
/**
* Class that monitors default network linger events and possibly notifies the user of network
@@ -206,8 +208,19 @@ public class LingerMonitor {
mEverNotified.put(fromNai.network.netId, true);
}
+ /**
+ * Put up or dismiss a notification or toast for of a change in the default network if needed.
+ *
+ * Putting up a notification when switching from no network to some network is not supported
+ * and as such this method can't be called with a null |fromNai|. It can be called with a
+ * null |toNai| if there isn't a default network any more.
+ *
+ * @param fromNai switching from this NAI
+ * @param toNai switching to this NAI
+ */
// The default network changed from fromNai to toNai due to a change in score.
- public void noteLingerDefaultNetwork(NetworkAgentInfo fromNai, NetworkAgentInfo toNai) {
+ public void noteLingerDefaultNetwork(@NonNull final NetworkAgentInfo fromNai,
+ @Nullable final NetworkAgentInfo toNai) {
if (VDBG) {
Log.d(TAG, "noteLingerDefaultNetwork from=" + fromNai.name() +
" everValidated=" + fromNai.everValidated +
@@ -221,6 +234,10 @@ public class LingerMonitor {
// Internet access).
maybeStopNotifying(fromNai);
+ // If the network was simply lost (either because it disconnected or because it stopped
+ // being the default with no replacement), then don't show a notification.
+ if (null == toNai) return;
+
// If this network never validated, don't notify. Otherwise, we could do things like:
//
// 1. Unvalidated wifi connects.
diff --git a/services/core/java/com/android/server/incremental/IncrementalManagerService.java b/services/core/java/com/android/server/incremental/IncrementalManagerService.java
index 5876d433face..64f25dd6f9fd 100644
--- a/services/core/java/com/android/server/incremental/IncrementalManagerService.java
+++ b/services/core/java/com/android/server/incremental/IncrementalManagerService.java
@@ -32,7 +32,10 @@ import android.os.ShellCallback;
import android.os.incremental.IIncrementalManager;
import android.util.Slog;
+import com.android.internal.util.DumpUtils;
+
import java.io.FileDescriptor;
+import java.io.PrintWriter;
/**
* This service has the following purposes:
@@ -71,6 +74,13 @@ public class IncrementalManagerService extends IIncrementalManager.Stub {
mNativeInstance = nativeStartService();
}
+ @SuppressWarnings("resource")
+ @Override
+ protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, TAG, pw)) return;
+ nativeDump(mNativeInstance, fd.getInt$());
+ }
+
/**
* Notifies native IIncrementalManager service that system is ready.
*/
@@ -158,4 +168,6 @@ public class IncrementalManagerService extends IIncrementalManager.Stub {
private static native long nativeStartService();
private static native void nativeSystemReady(long nativeInstance);
+
+ private static native void nativeDump(long nativeInstance, int fd);
}
diff --git a/services/core/java/com/android/server/media/MediaKeyDispatcher.java b/services/core/java/com/android/server/media/MediaKeyDispatcher.java
new file mode 100644
index 000000000000..16b9eb910ec1
--- /dev/null
+++ b/services/core/java/com/android/server/media/MediaKeyDispatcher.java
@@ -0,0 +1,39 @@
+/*
+ * 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.annotation.Nullable;
+import android.media.session.MediaSession;
+import android.view.KeyEvent;
+
+/**
+ * Provides a way to customize behavior for media key events.
+ */
+public interface MediaKeyDispatcher {
+ /**
+ * Implement this to customize the logic for which MediaSession should consume which key event.
+ *
+ * @param keyEvent a non-null KeyEvent whose key code is one of the supported media buttons.
+ * @param asSystemService {@code true} if the event came from the system service via hardware
+ * devices. {@code false} if the event came from the app process through key injection.
+ * @return a {@link MediaSession.Token} instance that should consume the given key event.
+ */
+ @Nullable
+ MediaSession.Token getSessionForKeyEvent(@NonNull KeyEvent keyEvent,
+ boolean asSystemService);
+}
diff --git a/services/core/java/com/android/server/media/MediaSession2Record.java b/services/core/java/com/android/server/media/MediaSession2Record.java
index b21d2e789555..820731d20c00 100644
--- a/services/core/java/com/android/server/media/MediaSession2Record.java
+++ b/services/core/java/com/android/server/media/MediaSession2Record.java
@@ -50,15 +50,18 @@ public class MediaSession2Record implements MediaSessionRecordImpl {
private final MediaSessionService mService;
@GuardedBy("mLock")
private boolean mIsConnected;
+ @GuardedBy("mLock")
+ private int mPolicies;
public MediaSession2Record(Session2Token sessionToken, MediaSessionService service,
- Looper handlerLooper) {
+ Looper handlerLooper, int policies) {
mSessionToken = sessionToken;
mService = service;
mHandlerExecutor = new HandlerExecutor(new Handler(handlerLooper));
mController = new MediaController2.Builder(service.getContext(), sessionToken)
.setControllerCallback(mHandlerExecutor, new Controller2Callback())
.build();
+ mPolicies = policies;
}
@Override
@@ -129,6 +132,21 @@ public class MediaSession2Record implements MediaSessionRecordImpl {
return false;
}
+
+ @Override
+ public int getSessionPolicies() {
+ synchronized (mLock) {
+ return mPolicies;
+ }
+ }
+
+ @Override
+ public void setSessionPolicies(int policies) {
+ synchronized (mLock) {
+ mPolicies = policies;
+ }
+ }
+
@Override
public void dump(PrintWriter pw, String prefix) {
pw.println(prefix + "token=" + mSessionToken);
diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java
index 46fb24048a20..05f7e1d7c3a5 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecord.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecord.java
@@ -159,9 +159,12 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR
private long mDuration = -1;
private String mMetadataDescription;
+ private int mPolicies;
+
public MediaSessionRecord(int ownerPid, int ownerUid, int userId, String ownerPackageName,
ISessionCallback cb, String tag, Bundle sessionInfo,
- MediaSessionService service, Looper handlerLooper) throws RemoteException {
+ MediaSessionService service, Looper handlerLooper, int policies)
+ throws RemoteException {
mOwnerPid = ownerPid;
mOwnerUid = ownerUid;
mUserId = userId;
@@ -178,6 +181,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR
mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
mAudioManagerInternal = LocalServices.getService(AudioManagerInternal.class);
mAudioAttrs = DEFAULT_ATTRIBUTES;
+ mPolicies = policies;
// May throw RemoteException if the session app is killed.
mSessionCb.mCb.asBinder().linkToDeath(this, 0);
@@ -438,6 +442,20 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR
}
@Override
+ public int getSessionPolicies() {
+ synchronized (mLock) {
+ return mPolicies;
+ }
+ }
+
+ @Override
+ public void setSessionPolicies(int policies) {
+ synchronized (mLock) {
+ mPolicies = policies;
+ }
+ }
+
+ @Override
public void dump(PrintWriter pw, String prefix) {
pw.println(prefix + mTag + " " + this);
@@ -808,6 +826,9 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR
@Override
public void setMediaButtonReceiver(PendingIntent pi) throws RemoteException {
+ if ((mPolicies & SessionPolicyProvider.SESSION_POLICY_IGNORE_BUTTON_RECEIVER) == 1) {
+ return;
+ }
mMediaButtonReceiver = pi;
final long token = Binder.clearCallingIdentity();
try {
diff --git a/services/core/java/com/android/server/media/MediaSessionRecordImpl.java b/services/core/java/com/android/server/media/MediaSessionRecordImpl.java
index 2cde89a7a6f6..6e1088088ced 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecordImpl.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecordImpl.java
@@ -20,6 +20,8 @@ import android.media.AudioManager;
import android.os.ResultReceiver;
import android.view.KeyEvent;
+import com.android.server.media.SessionPolicyProvider.SessionPolicy;
+
import java.io.PrintWriter;
/**
@@ -128,6 +130,18 @@ public interface MediaSessionRecordImpl extends AutoCloseable {
KeyEvent ke, int sequenceId, ResultReceiver cb);
/**
+ * Get session policies from custom policy provider set when MediaSessionRecord is instantiated.
+ * If custom policy does not exist, will return null.
+ */
+ @SessionPolicy
+ int getSessionPolicies();
+
+ /**
+ * Overwrite session policies that have been set when MediaSessionRecord is instantiated.
+ */
+ void setSessionPolicies(@SessionPolicy int policies);
+
+ /**
* Dumps internal state
*
* @param pw print writer
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index a6ad57a7ae3a..d0efef041180 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -141,6 +141,9 @@ public class MediaSessionService extends SystemService implements Monitor {
final RemoteCallbackList<IRemoteVolumeController> mRemoteVolumeControllers =
new RemoteCallbackList<>();
+ private SessionPolicyProvider mCustomSessionPolicyProvider;
+ private MediaKeyDispatcher mCustomMediaKeyDispatcher;
+
public MediaSessionService(Context context) {
super(context);
mContext = context;
@@ -179,6 +182,9 @@ public class MediaSessionService extends SystemService implements Monitor {
mSettingsObserver.observe();
mHasFeatureLeanback = mContext.getPackageManager().hasSystemFeature(
PackageManager.FEATURE_LEANBACK);
+
+ // TODO: (jinpark) check if config value for custom MediaKeyDispatcher and
+ // SessionPolicyProvider have been overlayed and instantiate using reflection.
updateUser();
}
@@ -555,7 +561,8 @@ public class MediaSessionService extends SystemService implements Monitor {
* 4. It needs to be added to the relevant user record.
*/
private MediaSessionRecord createSessionInternal(int callerPid, int callerUid, int userId,
- String callerPackageName, ISessionCallback cb, String tag, Bundle sessionInfo) {
+ String callerPackageName, ISessionCallback cb, String tag, Bundle sessionInfo,
+ int policies) {
synchronized (mLock) {
FullUserRecord user = getFullUserRecordLocked(userId);
if (user == null) {
@@ -566,7 +573,8 @@ public class MediaSessionService extends SystemService implements Monitor {
final MediaSessionRecord session;
try {
session = new MediaSessionRecord(callerPid, callerUid, userId,
- callerPackageName, cb, tag, sessionInfo, this, mHandler.getLooper());
+ callerPackageName, cb, tag, sessionInfo, this, mHandler.getLooper(),
+ policies);
} catch (RemoteException e) {
throw new RuntimeException("Media Session owner died prematurely.", e);
}
@@ -1127,8 +1135,11 @@ public class MediaSessionService extends SystemService implements Monitor {
if (cb == null) {
throw new IllegalArgumentException("Controller callback cannot be null");
}
+ int policies = (mCustomSessionPolicyProvider != null)
+ ? mCustomSessionPolicyProvider.getSessionPoliciesForApplication(
+ uid, packageName) : 0;
return createSessionInternal(pid, uid, resolvedUserId, packageName, cb, tag,
- sessionInfo).getSessionBinder();
+ sessionInfo, policies).getSessionBinder();
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -1148,7 +1159,7 @@ public class MediaSessionService extends SystemService implements Monitor {
+ " but actually=" + sessionToken.getUid());
}
MediaSession2Record record = new MediaSession2Record(
- sessionToken, MediaSessionService.this, mHandler.getLooper());
+ sessionToken, MediaSessionService.this, mHandler.getLooper(), 0);
synchronized (mLock) {
FullUserRecord user = getFullUserRecordLocked(record.getUserId());
user.mPriorityStack.addSession(record);
@@ -1308,12 +1319,11 @@ public class MediaSessionService extends SystemService implements Monitor {
* ACTION_MEDIA_BUTTON intent to the rest of the system.
*
* @param packageName The caller package
- * @param asSystemService {@code true} if the event sent to the session as if it was come
- * from the system service instead of the app process. This helps sessions to
- * distinguish between the key injection by the app and key events from the
- * hardware devices. Should be used only when the volume key events aren't handled
- * by foreground activity. {@code false} otherwise to tell session about the real
- * caller.
+ * @param asSystemService {@code true} if the event sent to the session came from the
+ * service instead of the app process. This helps sessions to distinguish between
+ * the key injection by the app and key events from the hardware devices. Should be
+ * used only when the hardware key events aren't handled by foreground activity.
+ * {@code false} otherwise to tell session about the real caller.
* @param keyEvent a non-null KeyEvent whose key code is one of the
* supported media buttons
* @param needWakeLock true if a PARTIAL_WAKE_LOCK needs to be held
@@ -2115,14 +2125,27 @@ public class MediaSessionService extends SystemService implements Monitor {
// TODO(jaewan): Implement
return;
}
- MediaSessionRecord session =
- (MediaSessionRecord) mCurrentFullUserRecord.getMediaButtonSessionLocked();
+ MediaSessionRecord session = null;
+
+ // Retrieve custom session for key event if it exists.
+ if (mCustomMediaKeyDispatcher != null) {
+ MediaSession.Token token =
+ mCustomMediaKeyDispatcher.getSessionForKeyEvent(keyEvent, asSystemService);
+ if (token != null) {
+ session = getMediaSessionRecordLocked(token);
+ }
+ }
+
+ if (session == null) {
+ session = (MediaSessionRecord) mCurrentFullUserRecord.getMediaButtonSessionLocked();
+ }
+
if (session != null) {
if (DEBUG_KEY_EVENT) {
Log.d(TAG, "Sending " + keyEvent + " to " + session);
}
if (needWakeLock) {
- mKeyEventReceiver.aquireWakeLockLocked();
+ mKeyEventReceiver.acquireWakeLockLocked();
}
// If we don't need a wakelock use -1 as the id so we won't release it later.
session.sendMediaButton(packageName, pid, uid, asSystemService, keyEvent,
@@ -2140,7 +2163,7 @@ public class MediaSessionService extends SystemService implements Monitor {
} else if (mCurrentFullUserRecord.mLastMediaButtonReceiver != null
|| mCurrentFullUserRecord.mRestoredMediaButtonReceiver != null) {
if (needWakeLock) {
- mKeyEventReceiver.aquireWakeLockLocked();
+ mKeyEventReceiver.acquireWakeLockLocked();
}
Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
mediaButtonIntent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
@@ -2349,7 +2372,7 @@ public class MediaSessionService extends SystemService implements Monitor {
}
}
- public void aquireWakeLockLocked() {
+ public void acquireWakeLockLocked() {
if (mRefCount == 0) {
mMediaEventWakeLock.acquire();
}
diff --git a/services/core/java/com/android/server/media/MediaSessionStack.java b/services/core/java/com/android/server/media/MediaSessionStack.java
index 7bb7cf4b74ad..07b1a1acf466 100644
--- a/services/core/java/com/android/server/media/MediaSessionStack.java
+++ b/services/core/java/com/android/server/media/MediaSessionStack.java
@@ -274,6 +274,15 @@ class MediaSessionStack {
}
private void updateMediaButtonSession(MediaSessionRecordImpl newMediaButtonSession) {
+ // Check if the policy states that this session should not be updated as a media button
+ // session.
+ if (newMediaButtonSession != null) {
+ int policies = newMediaButtonSession.getSessionPolicies();
+ if ((policies & SessionPolicyProvider.SESSION_POLICY_IGNORE_BUTTON_SESSION) == 1) {
+ return;
+ }
+ }
+
MediaSessionRecordImpl oldMediaButtonSession = mMediaButtonSession;
mMediaButtonSession = newMediaButtonSession;
mOnMediaButtonSessionChangedListener.onMediaButtonSessionChanged(
diff --git a/services/core/java/com/android/server/media/SessionPolicyProvider.java b/services/core/java/com/android/server/media/SessionPolicyProvider.java
new file mode 100644
index 000000000000..6eb79ef8dd71
--- /dev/null
+++ b/services/core/java/com/android/server/media/SessionPolicyProvider.java
@@ -0,0 +1,63 @@
+/*
+ * 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.IntDef;
+import android.annotation.NonNull;
+import android.media.session.MediaSession;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Interface for customizing {@link MediaSessionService}
+ */
+public interface SessionPolicyProvider {
+ @IntDef(value = {
+ SESSION_POLICY_IGNORE_BUTTON_RECEIVER,
+ SESSION_POLICY_IGNORE_BUTTON_SESSION
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ @interface SessionPolicy {}
+
+ /**
+ * Policy to ignore media button receiver, to not revive the media app when its media session is
+ * released or the app is dead.
+ *
+ * @see MediaSession#setMediaButtonReceiver
+ */
+ int SESSION_POLICY_IGNORE_BUTTON_RECEIVER = 1 << 0;
+
+ /**
+ * Policy to ignore sessions that should not respond to media key events via
+ * {@link MediaSessionService}. A typical use case is to explicitly
+ * ignore sessions that should not respond to media key events even if their playback state has
+ * changed most recently.
+ */
+ int SESSION_POLICY_IGNORE_BUTTON_SESSION = 1 << 1;
+
+ /**
+ * Use this to statically set policies for sessions when they are created.
+ * Use android.media.session.MediaSessionManager#setSessionPolicies(MediaSession.Token, int)
+ * to dynamically change policies at runtime.
+ *
+ * @param uid
+ * @param packageName
+ * @return list of policies
+ */
+ @SessionPolicy int getSessionPoliciesForApplication(int uid, @NonNull String packageName);
+}
diff --git a/services/core/java/com/android/server/notification/NotificationRecordLoggerImpl.java b/services/core/java/com/android/server/notification/NotificationRecordLoggerImpl.java
index 00b4c2b060ac..d61379921f2e 100644
--- a/services/core/java/com/android/server/notification/NotificationRecordLoggerImpl.java
+++ b/services/core/java/com/android/server/notification/NotificationRecordLoggerImpl.java
@@ -16,7 +16,7 @@
package com.android.server.notification;
-import android.util.StatsLog;
+import com.android.internal.util.FrameworkStatsLog;
/**
* Standard implementation of NotificationRecordLogger interface.
@@ -31,7 +31,7 @@ public class NotificationRecordLoggerImpl implements NotificationRecordLogger {
if (!p.shouldLog(buzzBeepBlink)) {
return;
}
- StatsLog.write(StatsLog.NOTIFICATION_REPORTED,
+ FrameworkStatsLog.write(FrameworkStatsLog.NOTIFICATION_REPORTED,
/* int32 event_id = 1 */ p.getUiEvent().getId(),
/* int32 uid = 2 */ r.getUid(),
/* string package_name = 3 */ r.sbn.getPackageName(),
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 38da8ab26962..bf7bebd10a13 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -101,7 +101,6 @@ import android.os.RevocableFileDescriptor;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.incremental.IncrementalFileStorages;
-import android.os.incremental.IncrementalManager;
import android.os.storage.StorageManager;
import android.provider.Settings.Secure;
import android.stats.devicepolicy.DevicePolicyEnums;
@@ -559,17 +558,6 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
mStagedSessionErrorMessage =
stagedSessionErrorMessage != null ? stagedSessionErrorMessage : "";
- // TODO(b/136132412): sanity check if session should not be incremental
- if (!params.isStaged && isIncrementalInstallation()) {
- IncrementalManager incrementalManager = (IncrementalManager) mContext.getSystemService(
- Context.INCREMENTAL_SERVICE);
- if (incrementalManager != null) {
- mIncrementalFileStorages =
- new IncrementalFileStorages(mPackageName, stageDir, incrementalManager,
- params.dataLoaderParams);
- }
- }
-
if (isStreamingInstallation()
&& this.params.dataLoaderParams.getComponentName().getPackageName()
== SYSTEM_DATA_LOADER_PACKAGE) {
@@ -1040,10 +1028,6 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
}
}
- if (mIncrementalFileStorages != null) {
- mIncrementalFileStorages.finishSetUp();
- }
-
dispatchStreamValidateAndCommit();
}
@@ -1052,11 +1036,6 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
}
private void handleStreamValidateAndCommit() {
- // TODO(b/136132412): update with new APIs
- if (mIncrementalFileStorages != null) {
- mIncrementalFileStorages.startLoading();
- }
-
boolean success = streamValidateAndCommit();
if (isMultiPackage()) {
@@ -2476,17 +2455,15 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
}
}
- if (mIncrementalFileStorages != null) {
- for (InstallationFile file : addedFiles) {
- try {
- mIncrementalFileStorages.addFile(file);
- } catch (IOException ex) {
- // TODO(b/146080380): add incremental-specific error code
- throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
- "Failed to add and configure Incremental File: " + file.getName(), ex);
- }
+ // TODO(b/136132412): update with new APIs
+ if (isIncrementalInstallation()) {
+ try {
+ mIncrementalFileStorages = IncrementalFileStorages.initialize(mContext,
+ stageDir, params.dataLoaderParams, addedFiles);
+ return true;
+ } catch (IOException e) {
+ throw new PackageManagerException(e);
}
- return true;
}
final DataLoaderManager dataLoaderManager = mContext.getSystemService(
@@ -2761,13 +2738,14 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
bridge.forceClose();
}
}
+ if (mIncrementalFileStorages != null) {
+ mIncrementalFileStorages.cleanUp();
+ mIncrementalFileStorages = null;
+ }
// For staged sessions, we don't delete the directory where the packages have been copied,
// since these packages are supposed to be read on reboot.
// Those dirs are deleted when the staged session has reached a final state.
if (stageDir != null && !params.isStaged) {
- if (mIncrementalFileStorages != null) {
- mIncrementalFileStorages.cleanUp();
- }
try {
mPm.mInstaller.rmPackageDir(stageDir.getAbsolutePath());
} catch (InstallerException ignored) {
@@ -2783,6 +2761,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
} else {
if (mIncrementalFileStorages != null) {
mIncrementalFileStorages.cleanUp();
+ mIncrementalFileStorages = null;
}
try {
mPm.mInstaller.rmPackageDir(stageDir.getAbsolutePath());
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index c09fb38c4d8a..93e724e3616c 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -55,6 +55,7 @@ import static android.content.pm.PackageManager.INSTALL_FAILED_INVALID_APK;
import static android.content.pm.PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
import static android.content.pm.PackageManager.INSTALL_FAILED_MISSING_SHARED_LIBRARY;
import static android.content.pm.PackageManager.INSTALL_FAILED_PACKAGE_CHANGED;
+import static android.content.pm.PackageManager.INSTALL_FAILED_PROCESS_NOT_DEFINED;
import static android.content.pm.PackageManager.INSTALL_FAILED_SHARED_USER_INCOMPATIBLE;
import static android.content.pm.PackageManager.INSTALL_FAILED_TEST_ONLY;
import static android.content.pm.PackageManager.INSTALL_FAILED_UPDATE_INCOMPATIBLE;
@@ -206,6 +207,7 @@ import android.content.pm.dex.DexMetadataHelper;
import android.content.pm.dex.IArtManager;
import android.content.pm.parsing.AndroidPackage;
import android.content.pm.parsing.ApkParseUtils;
+import android.content.pm.parsing.ComponentParseUtils;
import android.content.pm.parsing.ComponentParseUtils.ParsedActivity;
import android.content.pm.parsing.ComponentParseUtils.ParsedActivityIntentInfo;
import android.content.pm.parsing.ComponentParseUtils.ParsedComponent;
@@ -1544,6 +1546,7 @@ public class PackageManagerService extends IPackageManager.Stub
final @Nullable String[] mTelephonyPackages;
final @NonNull String mServicesExtensionPackageName;
final @NonNull String mSharedSystemSharedLibraryPackageName;
+ final @Nullable String mRetailDemoPackage;
private final PackageUsage mPackageUsage = new PackageUsage();
private final CompilerStats mCompilerStats = new CompilerStats();
@@ -3160,6 +3163,7 @@ public class PackageManagerService extends IPackageManager.Stub
mAppPredictionServicePackage = getAppPredictionServicePackageName();
mIncidentReportApproverPackage = getIncidentReportApproverPackageName();
mTelephonyPackages = getTelephonyPackageNames();
+ mRetailDemoPackage = getRetailDemoPackageName();
// Now that we know all of the shared libraries, update all clients to have
// the correct library paths.
@@ -11252,6 +11256,26 @@ public class PackageManagerService extends IPackageManager.Stub
return object;
}
+ private <T extends ComponentParseUtils.ParsedMainComponent>
+ void assertPackageProcesses(AndroidPackage pkg, List<T> components,
+ ArrayMap<String, ComponentParseUtils.ParsedProcess> procs, String compName)
+ throws PackageManagerException {
+ if (components == null) {
+ return;
+ }
+ for (int i = components.size() - 1; i >= 0; i--) {
+ final ComponentParseUtils.ParsedMainComponent<?> component = components.get(i);
+ if (!procs.containsKey(component.getProcessName())) {
+ throw new PackageManagerException(
+ INSTALL_FAILED_PROCESS_NOT_DEFINED,
+ "Can't install because " + compName + " " + component.className
+ + "'s process attribute " + component.getProcessName()
+ + " (in package " + pkg.getPackageName()
+ + ") is not included in the <processes> list");
+ }
+ }
+ }
+
/**
* Asserts the parsed package is valid according to the given policy. If the
* package is invalid, for whatever reason, throws {@link PackageManagerException}.
@@ -11481,6 +11505,24 @@ public class PackageManagerService extends IPackageManager.Stub
mComponentResolver.assertProvidersNotDefined(pkg);
}
+ // If this package has defined explicit processes, then ensure that these are
+ // the only processes used by its components.
+ final ArrayMap<String, ComponentParseUtils.ParsedProcess> procs = pkg.getProcesses();
+ if (procs != null) {
+ if (!procs.containsKey(pkg.getProcessName())) {
+ throw new PackageManagerException(
+ INSTALL_FAILED_PROCESS_NOT_DEFINED,
+ "Can't install because application tag's process attribute "
+ + pkg.getProcessName()
+ + " (in package " + pkg.getPackageName()
+ + ") is not included in the <processes> list");
+ }
+ assertPackageProcesses(pkg, pkg.getActivities(), procs, "activity");
+ assertPackageProcesses(pkg, pkg.getServices(), procs, "service");
+ assertPackageProcesses(pkg, pkg.getReceivers(), procs, "receiver");
+ assertPackageProcesses(pkg, pkg.getProviders(), procs, "provider");
+ }
+
// Verify that packages sharing a user with a privileged app are marked as privileged.
if (!pkg.isPrivileged() && (pkg.getSharedUserId() != null)) {
SharedUserSetting sharedUserSetting = null;
@@ -19723,6 +19765,41 @@ public class PackageManagerService extends IPackageManager.Stub
}
@Nullable
+ private String getRetailDemoPackageName() {
+ final String predefinedPkgName = mContext.getString(R.string.config_retailDemoPackage);
+ final String predefinedSignature = mContext.getString(
+ R.string.config_retailDemoPackageSignature);
+
+ if (TextUtils.isEmpty(predefinedPkgName) || TextUtils.isEmpty(predefinedSignature)) {
+ return null;
+ }
+
+ final AndroidPackage androidPkg = mPackages.get(predefinedPkgName);
+ if (androidPkg != null) {
+ final SigningDetails signingDetail = androidPkg.getSigningDetails();
+ if (signingDetail != null && signingDetail.signatures != null) {
+ try {
+ final MessageDigest msgDigest = MessageDigest.getInstance("SHA-256");
+ for (Signature signature : signingDetail.signatures) {
+ if (TextUtils.equals(predefinedSignature,
+ HexEncoding.encodeToString(msgDigest.digest(
+ signature.toByteArray()), false))) {
+ return predefinedPkgName;
+ }
+ }
+ } catch (NoSuchAlgorithmException e) {
+ Slog.e(
+ TAG,
+ "Unable to verify signatures as getting the retail demo package name",
+ e);
+ }
+ }
+ }
+
+ return null;
+ }
+
+ @Nullable
private String ensureSystemPackageName(@Nullable String packageName) {
if (packageName == null) {
return null;
@@ -23010,6 +23087,10 @@ public class PackageManagerService extends IPackageManager.Stub
return filterOnlySystemPackages(mTelephonyPackages);
case PackageManagerInternal.PACKAGE_COMPANION:
return filterOnlySystemPackages("com.android.companiondevicemanager");
+ case PackageManagerInternal.PACKAGE_RETAIL_DEMO:
+ return TextUtils.isEmpty(mRetailDemoPackage)
+ ? ArrayUtils.emptyArray(String.class)
+ : new String[] {mRetailDemoPackage};
default:
return ArrayUtils.emptyArray(String.class);
}
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index fcd8e221a9e8..fbea59570ac0 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -4570,7 +4570,7 @@ public final class Settings {
pw.print("anyDensity");
}
pw.println("]");
- List<String> libraryNames = pkg.getLibraryNames();
+ final List<String> libraryNames = pkg.getLibraryNames();
if (libraryNames != null && libraryNames.size() > 0) {
pw.print(prefix); pw.println(" dynamic libraries:");
for (int i = 0; i< libraryNames.size(); i++) {
@@ -4585,7 +4585,7 @@ public final class Settings {
pw.print(" version:"); pw.println(pkg.getStaticSharedLibVersion());
}
- List<String> usesLibraries = pkg.getUsesLibraries();
+ final List<String> usesLibraries = pkg.getUsesLibraries();
if (usesLibraries != null && usesLibraries.size() > 0) {
pw.print(prefix); pw.println(" usesLibraries:");
for (int i=0; i< usesLibraries.size(); i++) {
@@ -4593,8 +4593,8 @@ public final class Settings {
}
}
- List<String> usesStaticLibraries = pkg.getUsesStaticLibraries();
- long[] usesStaticLibrariesVersions = pkg.getUsesStaticLibrariesVersions();
+ final List<String> usesStaticLibraries = pkg.getUsesStaticLibraries();
+ final long[] usesStaticLibrariesVersions = pkg.getUsesStaticLibrariesVersions();
if (usesStaticLibraries != null
&& usesStaticLibraries.size() > 0) {
pw.print(prefix); pw.println(" usesStaticLibraries:");
@@ -4605,7 +4605,7 @@ public final class Settings {
}
}
- List<String> usesOptionalLibraries = pkg.getUsesOptionalLibraries();
+ final List<String> usesOptionalLibraries = pkg.getUsesOptionalLibraries();
if (usesOptionalLibraries != null
&& usesOptionalLibraries.size() > 0) {
pw.print(prefix); pw.println(" usesOptionalLibraries:");
@@ -4615,7 +4615,7 @@ public final class Settings {
}
}
- String[] usesLibraryFiles = pkg.getUsesLibraryFiles();
+ final String[] usesLibraryFiles = pkg.getUsesLibraryFiles();
if (usesLibraryFiles != null
&& usesLibraryFiles.length > 0) {
pw.print(prefix); pw.println(" usesLibraryFiles:");
@@ -4623,6 +4623,20 @@ public final class Settings {
pw.print(prefix); pw.print(" "); pw.println(usesLibraryFiles[i]);
}
}
+ final ArrayMap<String, ComponentParseUtils.ParsedProcess> procs = pkg.getProcesses();
+ if (procs != null) {
+ pw.print(prefix); pw.println(" processes:");
+ for (int i = 0; i < procs.size(); i++) {
+ final ComponentParseUtils.ParsedProcess proc = procs.valueAt(i);
+ pw.print(prefix); pw.print(" "); pw.println(proc.name);
+ if (proc.deniedPermissions != null) {
+ for (int j = 0; j < proc.deniedPermissions.size(); j++) {
+ pw.print(prefix); pw.print(" deny: ");
+ pw.println(proc.deniedPermissions.valueAt(j));
+ }
+ }
+ }
+ }
}
pw.print(prefix); pw.print(" timeStamp=");
date.setTime(ps.timeStamp);
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index f368666a06ba..f7889ea6141c 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -1977,10 +1977,15 @@ public class ShortcutService extends IShortcutService.Stub {
* After validating the caller, it passes the request to {@link #mShortcutRequestPinProcessor}.
* Either {@param shortcut} or {@param appWidget} should be non-null.
*/
- private boolean requestPinItem(String packageName, int userId, ShortcutInfo shortcut,
+ private boolean requestPinItem(String callingPackage, int userId, ShortcutInfo shortcut,
AppWidgetProviderInfo appWidget, Bundle extras, IntentSender resultIntent) {
- verifyCaller(packageName, userId);
- verifyShortcutInfoPackage(packageName, shortcut);
+ verifyCaller(callingPackage, userId);
+ if (shortcut == null || !injectHasAccessShortcutsPermission(
+ injectBinderCallingPid(), injectBinderCallingUid())) {
+ // Verify if caller is the shortcut owner, only if caller doesn't have ACCESS_SHORTCUTS.
+ verifyShortcutInfoPackage(callingPackage, shortcut);
+ }
+ final String shortcutPackage = shortcut.getPackage();
final boolean ret;
synchronized (mLock) {
@@ -1995,13 +2000,13 @@ public class ShortcutService extends IShortcutService.Stub {
// and then proceed the rest of the process.
if (shortcut != null) {
final ShortcutPackage ps = getPackageShortcutsForPublisherLocked(
- packageName, userId);
+ shortcutPackage, userId);
final String id = shortcut.getId();
if (ps.isShortcutExistsAndInvisibleToPublisher(id)) {
ps.updateInvisibleShortcutForPinRequestWith(shortcut);
- packageShortcutsChanged(packageName, userId);
+ packageShortcutsChanged(shortcutPackage, userId);
}
}
diff --git a/services/core/java/com/android/server/pm/permission/BasePermission.java b/services/core/java/com/android/server/pm/permission/BasePermission.java
index 565a85fd1ac1..e323c9869afb 100644
--- a/services/core/java/com/android/server/pm/permission/BasePermission.java
+++ b/services/core/java/com/android/server/pm/permission/BasePermission.java
@@ -284,6 +284,10 @@ public final class BasePermission {
return (protectionLevel & PermissionInfo.PROTECTION_FLAG_COMPANION) != 0;
}
+ public boolean isRetailDemo() {
+ return (protectionLevel & PermissionInfo.PROTECTION_FLAG_RETAIL_DEMO) != 0;
+ }
+
public void transfer(@NonNull String origPackageName, @NonNull String newPackageName) {
if (!origPackageName.equals(sourcePackageName)) {
return;
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index 6167a509b85f..1fc2dd5193e1 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -55,6 +55,8 @@ import android.annotation.UserIdInt;
import android.app.ActivityManager;
import android.app.ApplicationPackageManager;
import android.app.IActivityManager;
+import android.app.admin.DeviceAdminInfo;
+import android.app.admin.DevicePolicyManagerInternal;
import android.compat.annotation.ChangeId;
import android.compat.annotation.EnabledAfter;
import android.content.Context;
@@ -3355,10 +3357,27 @@ public class PermissionManagerService extends IPermissionManager.Stub {
// Special permissions for the system companion device manager.
allowed = true;
}
+ if (!allowed && bp.isRetailDemo()
+ && ArrayUtils.contains(mPackageManagerInt.getKnownPackageNames(
+ PackageManagerInternal.PACKAGE_RETAIL_DEMO, UserHandle.USER_SYSTEM),
+ pkg.getPackageName()) && isProfileOwner(pkg.getUid())) {
+ // Special permission granted only to the OEM specified retail demo app
+ allowed = true;
+ }
}
return allowed;
}
+ private static boolean isProfileOwner(int uid) {
+ DevicePolicyManagerInternal dpmInternal =
+ LocalServices.getService(DevicePolicyManagerInternal.class);
+ if (dpmInternal != null) {
+ return dpmInternal
+ .isActiveAdminWithPolicy(uid, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ }
+ return false;
+ }
+
private static boolean canGrantOemPermission(PackageSetting ps, String permission) {
if (!ps.isOem()) {
return false;
diff --git a/services/core/java/com/android/server/policy/PermissionPolicyService.java b/services/core/java/com/android/server/policy/PermissionPolicyService.java
index a86c8d7545b1..2c7795a6274b 100644
--- a/services/core/java/com/android/server/policy/PermissionPolicyService.java
+++ b/services/core/java/com/android/server/policy/PermissionPolicyService.java
@@ -29,6 +29,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.app.AppOpsManager;
+import android.app.AppOpsManagerInternal;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
@@ -84,6 +85,8 @@ public final class PermissionPolicyService extends SystemService {
private final Object mLock = new Object();
+ private IAppOpsCallback mAppOpsCallback;
+
/** Whether the user is started but not yet stopped */
@GuardedBy("mLock")
private final SparseBooleanArray mIsStarted = new SparseBooleanArray();
@@ -138,7 +141,7 @@ public final class PermissionPolicyService extends SystemService {
permManagerInternal.addOnRuntimePermissionStateChangedListener(
this::synchronizePackagePermissionsAndAppOpsAsyncForUser);
- IAppOpsCallback appOpsListener = new IAppOpsCallback.Stub() {
+ mAppOpsCallback = new IAppOpsCallback.Stub() {
public void opChanged(int op, int uid, String packageName) {
synchronizePackagePermissionsAndAppOpsAsyncForUser(packageName,
UserHandle.getUserId(uid));
@@ -155,7 +158,7 @@ public final class PermissionPolicyService extends SystemService {
PermissionInfo perm = dangerousPerms.get(i);
if (perm.isRuntime()) {
- appOpsService.startWatchingMode(getSwitchOp(perm.name), null, appOpsListener);
+ appOpsService.startWatchingMode(getSwitchOp(perm.name), null, mAppOpsCallback);
}
if (perm.isSoftRestricted()) {
SoftRestrictedPermissionPolicy policy =
@@ -163,7 +166,7 @@ public final class PermissionPolicyService extends SystemService {
perm.name);
int extraAppOp = policy.getExtraAppOpCode();
if (extraAppOp != OP_NONE) {
- appOpsService.startWatchingMode(extraAppOp, null, appOpsListener);
+ appOpsService.startWatchingMode(extraAppOp, null, mAppOpsCallback);
}
}
}
@@ -386,10 +389,11 @@ public final class PermissionPolicyService extends SystemService {
* Synchronizes permission to app ops. You *must* always sync all packages
* in a shared UID at the same time to ensure proper synchronization.
*/
- private static class PermissionToOpSynchroniser {
+ private class PermissionToOpSynchroniser {
private final @NonNull Context mContext;
private final @NonNull PackageManager mPackageManager;
private final @NonNull AppOpsManager mAppOpsManager;
+ private final @NonNull AppOpsManagerInternal mAppOpsManagerInternal;
private final @NonNull ArrayMap<String, PermissionInfo> mRuntimePermissionInfos;
@@ -429,6 +433,7 @@ public final class PermissionPolicyService extends SystemService {
mContext = context;
mPackageManager = context.getPackageManager();
mAppOpsManager = context.getSystemService(AppOpsManager.class);
+ mAppOpsManagerInternal = LocalServices.getService(AppOpsManagerInternal.class);
mRuntimePermissionInfos = new ArrayMap<>();
PermissionManagerServiceInternal permissionManagerInternal = LocalServices.getService(
@@ -668,7 +673,8 @@ public final class PermissionPolicyService extends SystemService {
opCode), uid, packageName);
if (currentMode != MODE_ALLOWED) {
if (currentMode != MODE_IGNORED) {
- mAppOpsManager.setUidMode(opCode, uid, MODE_IGNORED);
+ mAppOpsManagerInternal.setUidModeIgnoringCallback(opCode, uid, MODE_IGNORED,
+ mAppOpsCallback);
}
return true;
}
@@ -680,15 +686,16 @@ public final class PermissionPolicyService extends SystemService {
final int oldMode = mAppOpsManager.unsafeCheckOpRaw(AppOpsManager.opToPublicName(
opCode), uid, packageName);
if (oldMode != mode) {
- mAppOpsManager.setUidMode(opCode, uid, mode);
+ mAppOpsManagerInternal.setUidModeIgnoringCallback(opCode, uid, mode,
+ mAppOpsCallback);
final int newMode = mAppOpsManager.unsafeCheckOpRaw(AppOpsManager.opToPublicName(
opCode), uid, packageName);
if (newMode != mode) {
// Work around incorrectly-set package mode. It never makes sense for app ops
// related to runtime permissions, but can get in the way and we have to reset
// it.
- mAppOpsManager.setMode(opCode, uid, packageName, AppOpsManager.opToDefaultMode(
- opCode));
+ mAppOpsManagerInternal.setModeIgnoringCallback(opCode, uid, packageName,
+ AppOpsManager.opToDefaultMode(opCode), mAppOpsCallback);
}
}
}
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 03cb283ce447..ede04f3bbb14 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -481,6 +481,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
int mVeryLongPressTimeout;
boolean mAllowStartActivityForLongPressOnPowerDuringSetup;
MetricsLogger mLogger;
+ boolean mWakeOnDpadKeyPress;
+ boolean mWakeOnAssistKeyPress;
private boolean mHandleVolumeKeysInWM;
@@ -1729,6 +1731,13 @@ public class PhoneWindowManager implements WindowManagerPolicy {
mAccessibilityShortcutController =
new AccessibilityShortcutController(mContext, new Handler(), mCurrentUserId);
mLogger = new MetricsLogger();
+
+ Resources res = mContext.getResources();
+ mWakeOnDpadKeyPress =
+ res.getBoolean(com.android.internal.R.bool.config_wakeOnDpadKeyPress);
+ mWakeOnAssistKeyPress =
+ res.getBoolean(com.android.internal.R.bool.config_wakeOnAssistKeyPress);
+
// Init display burn-in protection
boolean burnInProtectionEnabled = context.getResources().getBoolean(
com.android.internal.R.bool.config_enableBurnInProtection);
@@ -4072,13 +4081,11 @@ public class PhoneWindowManager implements WindowManagerPolicy {
*/
private boolean isWakeKeyWhenScreenOff(int keyCode) {
switch (keyCode) {
- // ignore volume keys unless docked
case KeyEvent.KEYCODE_VOLUME_UP:
case KeyEvent.KEYCODE_VOLUME_DOWN:
case KeyEvent.KEYCODE_VOLUME_MUTE:
return mDefaultDisplayPolicy.getDockMode() != Intent.EXTRA_DOCK_STATE_UNDOCKED;
- // ignore media keys
case KeyEvent.KEYCODE_MUTE:
case KeyEvent.KEYCODE_HEADSETHOOK:
case KeyEvent.KEYCODE_MEDIA_PLAY:
@@ -4092,7 +4099,18 @@ public class PhoneWindowManager implements WindowManagerPolicy {
case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD:
case KeyEvent.KEYCODE_MEDIA_AUDIO_TRACK:
return false;
+
+ case KeyEvent.KEYCODE_DPAD_UP:
+ case KeyEvent.KEYCODE_DPAD_DOWN:
+ case KeyEvent.KEYCODE_DPAD_LEFT:
+ case KeyEvent.KEYCODE_DPAD_RIGHT:
+ case KeyEvent.KEYCODE_DPAD_CENTER:
+ return mWakeOnDpadKeyPress;
+
+ case KeyEvent.KEYCODE_ASSIST:
+ return mWakeOnAssistKeyPress;
}
+
return true;
}
diff --git a/services/core/java/com/android/server/power/AttentionDetector.java b/services/core/java/com/android/server/power/AttentionDetector.java
index eec0d5f35c5c..cc72dd69a5fa 100644
--- a/services/core/java/com/android/server/power/AttentionDetector.java
+++ b/services/core/java/com/android/server/power/AttentionDetector.java
@@ -38,9 +38,9 @@ import android.provider.DeviceConfig;
import android.provider.Settings;
import android.service.attention.AttentionService;
import android.util.Slog;
-import android.util.StatsLog;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.FrameworkStatsLog;
import com.android.server.LocalServices;
import com.android.server.wm.WindowManagerInternal;
@@ -285,7 +285,8 @@ public class AttentionDetector {
private void resetConsecutiveExtensionCount() {
final long previousCount = mConsecutiveTimeoutExtendedCount.getAndSet(0);
if (previousCount > 0) {
- StatsLog.write(StatsLog.SCREEN_TIMEOUT_EXTENSION_REPORTED, previousCount);
+ FrameworkStatsLog.write(FrameworkStatsLog.SCREEN_TIMEOUT_EXTENSION_REPORTED,
+ previousCount);
}
}
diff --git a/services/core/java/com/android/server/power/Notifier.java b/services/core/java/com/android/server/power/Notifier.java
index b45522d11a5d..0b95be15f157 100644
--- a/services/core/java/com/android/server/power/Notifier.java
+++ b/services/core/java/com/android/server/power/Notifier.java
@@ -49,13 +49,13 @@ import android.provider.Settings;
import android.telephony.TelephonyManager;
import android.util.EventLog;
import android.util.Slog;
-import android.util.StatsLog;
import android.view.WindowManagerPolicyConstants.OnReason;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.IBatteryStats;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.internal.util.FrameworkStatsLog;
import com.android.server.EventLogTags;
import com.android.server.LocalServices;
import com.android.server.inputmethod.InputMethodManagerInternal;
@@ -199,8 +199,8 @@ public class Notifier {
try {
mBatteryStats.noteInteractive(true);
} catch (RemoteException ex) { }
- StatsLog.write(StatsLog.INTERACTIVE_STATE_CHANGED,
- StatsLog.INTERACTIVE_STATE_CHANGED__STATE__ON);
+ FrameworkStatsLog.write(FrameworkStatsLog.INTERACTIVE_STATE_CHANGED,
+ FrameworkStatsLog.INTERACTIVE_STATE_CHANGED__STATE__ON);
}
/**
@@ -247,13 +247,15 @@ public class Notifier {
try {
if (workSource != null) {
mBatteryStats.noteLongPartialWakelockStartFromSource(tag, historyTag, workSource);
- StatsLog.write(StatsLog.LONG_PARTIAL_WAKELOCK_STATE_CHANGED, workSource,
- tag, historyTag, StatsLog.LONG_PARTIAL_WAKELOCK_STATE_CHANGED__STATE__ON);
+ FrameworkStatsLog.write(FrameworkStatsLog.LONG_PARTIAL_WAKELOCK_STATE_CHANGED,
+ workSource, tag, historyTag,
+ FrameworkStatsLog.LONG_PARTIAL_WAKELOCK_STATE_CHANGED__STATE__ON);
} else {
mBatteryStats.noteLongPartialWakelockStart(tag, historyTag, ownerUid);
- StatsLog.write_non_chained(StatsLog.LONG_PARTIAL_WAKELOCK_STATE_CHANGED,
- ownerUid, null, tag, historyTag,
- StatsLog.LONG_PARTIAL_WAKELOCK_STATE_CHANGED__STATE__ON);
+ FrameworkStatsLog.write_non_chained(
+ FrameworkStatsLog.LONG_PARTIAL_WAKELOCK_STATE_CHANGED, ownerUid, null, tag,
+ historyTag,
+ FrameworkStatsLog.LONG_PARTIAL_WAKELOCK_STATE_CHANGED__STATE__ON);
}
} catch (RemoteException ex) {
// Ignore
@@ -270,13 +272,15 @@ public class Notifier {
try {
if (workSource != null) {
mBatteryStats.noteLongPartialWakelockFinishFromSource(tag, historyTag, workSource);
- StatsLog.write(StatsLog.LONG_PARTIAL_WAKELOCK_STATE_CHANGED, workSource,
- tag, historyTag, StatsLog.LONG_PARTIAL_WAKELOCK_STATE_CHANGED__STATE__OFF);
+ FrameworkStatsLog.write(FrameworkStatsLog.LONG_PARTIAL_WAKELOCK_STATE_CHANGED,
+ workSource, tag, historyTag,
+ FrameworkStatsLog.LONG_PARTIAL_WAKELOCK_STATE_CHANGED__STATE__OFF);
} else {
mBatteryStats.noteLongPartialWakelockFinish(tag, historyTag, ownerUid);
- StatsLog.write_non_chained(StatsLog.LONG_PARTIAL_WAKELOCK_STATE_CHANGED,
- ownerUid, null, tag, historyTag,
- StatsLog.LONG_PARTIAL_WAKELOCK_STATE_CHANGED__STATE__OFF);
+ FrameworkStatsLog.write_non_chained(
+ FrameworkStatsLog.LONG_PARTIAL_WAKELOCK_STATE_CHANGED, ownerUid, null, tag,
+ historyTag,
+ FrameworkStatsLog.LONG_PARTIAL_WAKELOCK_STATE_CHANGED__STATE__OFF);
}
} catch (RemoteException ex) {
// Ignore
@@ -415,9 +419,9 @@ public class Notifier {
try {
mBatteryStats.noteInteractive(interactive);
} catch (RemoteException ex) { }
- StatsLog.write(StatsLog.INTERACTIVE_STATE_CHANGED,
- interactive ? StatsLog.INTERACTIVE_STATE_CHANGED__STATE__ON :
- StatsLog.INTERACTIVE_STATE_CHANGED__STATE__OFF);
+ FrameworkStatsLog.write(FrameworkStatsLog.INTERACTIVE_STATE_CHANGED,
+ interactive ? FrameworkStatsLog.INTERACTIVE_STATE_CHANGED__STATE__ON :
+ FrameworkStatsLog.INTERACTIVE_STATE_CHANGED__STATE__OFF);
// Handle early behaviors.
mInteractive = interactive;
diff --git a/services/core/java/com/android/server/rollback/Rollback.java b/services/core/java/com/android/server/rollback/Rollback.java
index e0143ae4841b..bf7413b64588 100644
--- a/services/core/java/com/android/server/rollback/Rollback.java
+++ b/services/core/java/com/android/server/rollback/Rollback.java
@@ -187,6 +187,14 @@ class Rollback {
private final int[] mPackageSessionIds;
/**
+ * The number of sessions in the install which are notified with success by
+ * {@link PackageInstaller.SessionCallback#onFinished(int, boolean)}.
+ * This rollback will be enabled only after all child sessions finished with success.
+ */
+ @GuardedBy("mLock")
+ private int mNumPackageSessionsWithSuccess;
+
+ /**
* Constructs a new, empty Rollback instance.
*
* @param rollbackId the id of the rollback.
@@ -840,6 +848,17 @@ class Rollback {
return mPackageSessionIds.length;
}
+ /**
+ * Called when a child session finished with success.
+ * Returns true when all child sessions are notified with success. This rollback will be
+ * enabled only after all child sessions finished with success.
+ */
+ boolean notifySessionWithSuccess() {
+ synchronized (mLock) {
+ return ++mNumPackageSessionsWithSuccess == mPackageSessionIds.length;
+ }
+ }
+
static String rollbackStateToString(@RollbackState int state) {
switch (state) {
case Rollback.ROLLBACK_STATE_ENABLING: return "enabling";
diff --git a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
index 4425c0acba2a..3fa114e3b7a3 100644
--- a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
+++ b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
@@ -123,7 +123,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
// Rollbacks we are in the process of enabling.
@GuardedBy("mLock")
- private final Set<NewRollback> mNewRollbacks = new ArraySet<>();
+ private final Set<Rollback> mNewRollbacks = new ArraySet<>();
// The list of all rollbacks, including available and committed rollbacks.
@GuardedBy("mLock")
@@ -240,16 +240,16 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
Slog.v(TAG, "broadcast=ACTION_CANCEL_ENABLE_ROLLBACK token=" + token);
}
synchronized (mLock) {
- NewRollback found = null;
- for (NewRollback newRollback : mNewRollbacks) {
- if (newRollback.rollback.hasToken(token)) {
+ Rollback found = null;
+ for (Rollback newRollback : mNewRollbacks) {
+ if (newRollback.hasToken(token)) {
found = newRollback;
break;
}
}
if (found != null) {
mNewRollbacks.remove(found);
- found.rollback.delete(mAppDataRollbackHelper);
+ found.delete(mAppDataRollbackHelper);
}
}
}
@@ -442,12 +442,12 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
rollback.delete(mAppDataRollbackHelper);
}
}
- Iterator<NewRollback> iter2 = mNewRollbacks.iterator();
+ Iterator<Rollback> iter2 = mNewRollbacks.iterator();
while (iter2.hasNext()) {
- NewRollback newRollback = iter2.next();
- if (newRollback.rollback.includesPackage(packageName)) {
+ Rollback newRollback = iter2.next();
+ if (newRollback.includesPackage(packageName)) {
iter2.remove();
- newRollback.rollback.delete(mAppDataRollbackHelper);
+ newRollback.delete(mAppDataRollbackHelper);
}
}
@@ -802,7 +802,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
}
}
- NewRollback newRollback;
+ Rollback newRollback;
synchronized (mLock) {
// See if we already have a NewRollback that contains this package
// session. If not, create a NewRollback for the parent session
@@ -813,9 +813,9 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
mNewRollbacks.add(newRollback);
}
}
- newRollback.rollback.addToken(token);
+ newRollback.addToken(token);
- return enableRollbackForPackageSession(newRollback.rollback, packageSession);
+ return enableRollbackForPackageSession(newRollback, packageSession);
}
@WorkerThread
@@ -825,12 +825,12 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
}
synchronized (mLock) {
- NewRollback newRollback = getNewRollbackForPackageSessionLocked(sessionId);
+ Rollback newRollback = getNewRollbackForPackageSessionLocked(sessionId);
if (newRollback != null) {
- Slog.w(TAG, "Delete new rollback id=" + newRollback.rollback.info.getRollbackId()
+ Slog.w(TAG, "Delete new rollback id=" + newRollback.info.getRollbackId()
+ " for session id=" + sessionId);
mNewRollbacks.remove(newRollback);
- newRollback.rollback.delete(mAppDataRollbackHelper);
+ newRollback.delete(mAppDataRollbackHelper);
}
Iterator<Rollback> iter = mRollbacks.iterator();
while (iter.hasNext()) {
@@ -972,9 +972,8 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
rollback.snapshotUserData(packageName, userIds, mAppDataRollbackHelper);
}
// non-staged installs
- for (NewRollback rollback : mNewRollbacks) {
- rollback.rollback.snapshotUserData(
- packageName, userIds, mAppDataRollbackHelper);
+ for (Rollback rollback : mNewRollbacks) {
+ rollback.snapshotUserData(packageName, userIds, mAppDataRollbackHelper);
}
}
}
@@ -1016,13 +1015,13 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
return;
}
- NewRollback newRollback;
+ Rollback newRollback;
synchronized (mLock) {
newRollback = createNewRollbackLocked(session);
}
if (!session.isMultiPackage()) {
- if (!enableRollbackForPackageSession(newRollback.rollback, session)) {
+ if (!enableRollbackForPackageSession(newRollback, session)) {
Slog.e(TAG, "Unable to enable rollback for session: " + sessionId);
result.offer(-1);
return;
@@ -1036,7 +1035,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
result.offer(-1);
return;
}
- if (!enableRollbackForPackageSession(newRollback.rollback, childSession)) {
+ if (!enableRollbackForPackageSession(newRollback, childSession)) {
Slog.e(TAG, "Unable to enable rollback for session: " + sessionId);
result.offer(-1);
return;
@@ -1197,7 +1196,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
}
if (success) {
- NewRollback newRollback;
+ Rollback newRollback;
synchronized (mLock) {
newRollback = getNewRollbackForPackageSessionLocked(sessionId);
if (newRollback != null && newRollback.notifySessionWithSuccess()) {
@@ -1229,8 +1228,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
* or null on error.
*/
@WorkerThread
- private Rollback completeEnableRollback(NewRollback newRollback) {
- Rollback rollback = newRollback.rollback;
+ private Rollback completeEnableRollback(Rollback rollback) {
if (LOCAL_LOGV) {
Slog.v(TAG, "completeEnableRollback id=" + rollback.info.getRollbackId());
}
@@ -1341,38 +1339,9 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
}
}
- private static class NewRollback {
- public final Rollback rollback;
-
- /**
- * The number of sessions in the install which are notified with success by
- * {@link PackageInstaller.SessionCallback#onFinished(int, boolean)}.
- * This NewRollback will be enabled only after all child sessions finished with success.
- */
- @GuardedBy("mNewRollbackLock")
- private int mNumPackageSessionsWithSuccess;
-
- private final Object mNewRollbackLock = new Object();
-
- NewRollback(Rollback rollback) {
- this.rollback = rollback;
- }
-
- /**
- * Called when a child session finished with success.
- * Returns true when all child sessions are notified with success. This NewRollback will be
- * enabled only after all child sessions finished with success.
- */
- boolean notifySessionWithSuccess() {
- synchronized (mNewRollbackLock) {
- return ++mNumPackageSessionsWithSuccess == rollback.getPackageSessionIdCount();
- }
- }
- }
-
@WorkerThread
@GuardedBy("mLock")
- private NewRollback createNewRollbackLocked(PackageInstaller.SessionInfo parentSession) {
+ private Rollback createNewRollbackLocked(PackageInstaller.SessionInfo parentSession) {
int rollbackId = allocateRollbackIdLocked();
final int userId;
if (parentSession.getUser() == UserHandle.ALL) {
@@ -1404,7 +1373,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
installerPackageName, packageSessionIds);
}
- return new NewRollback(rollback);
+ return rollback;
}
/**
@@ -1414,11 +1383,11 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
*/
@WorkerThread
@GuardedBy("mLock")
- NewRollback getNewRollbackForPackageSessionLocked(int packageSessionId) {
+ Rollback getNewRollbackForPackageSessionLocked(int packageSessionId) {
// We expect mNewRollbacks to be a very small list; linear search
// should be plenty fast.
- for (NewRollback newRollback: mNewRollbacks) {
- if (newRollback.rollback.containsSessionId(packageSessionId)) {
+ for (Rollback newRollback: mNewRollbacks) {
+ if (newRollback.containsSessionId(packageSessionId)) {
return newRollback;
}
}
diff --git a/services/core/java/com/android/server/rollback/WatchdogRollbackLogger.java b/services/core/java/com/android/server/rollback/WatchdogRollbackLogger.java
index 79e1a2912147..46ec2f8258ca 100644
--- a/services/core/java/com/android/server/rollback/WatchdogRollbackLogger.java
+++ b/services/core/java/com/android/server/rollback/WatchdogRollbackLogger.java
@@ -70,20 +70,27 @@ public final class WatchdogRollbackLogger {
}
}
+ /**
+ * Returns the logging parent of a given package if it exists, {@code null} otherwise.
+ *
+ * The logging parent is defined by the {@code android.content.pm.LOGGING_PARENT} field in the
+ * metadata of a package's AndroidManifest.xml.
+ */
@VisibleForTesting
+ @Nullable
static VersionedPackage getLogPackage(Context context,
@NonNull VersionedPackage failingPackage) {
String logPackageName;
VersionedPackage loggingParent;
logPackageName = getLoggingParentName(context, failingPackage.getPackageName());
if (logPackageName == null) {
- return failingPackage;
+ return null;
}
try {
loggingParent = new VersionedPackage(logPackageName, context.getPackageManager()
.getPackageInfo(logPackageName, 0 /* flags */).getLongVersionCode());
} catch (PackageManager.NameNotFoundException e) {
- return failingPackage;
+ return null;
}
return loggingParent;
}
@@ -105,18 +112,14 @@ public final class WatchdogRollbackLogger {
return;
}
- // Identify the logging parent for this rollback. When all configurations are correct, each
- // package in the rollback refers to the same logging parent, except for the logging parent
- // itself. If a logging parent is missing for a package, we use the package itself for
- // logging. This might result in over-logging, but we prefer this over no logging.
+ // Identify the logging parent for this rollback. When all configurations are correct,
+ // each package in the rollback has a logging parent set in metadata.
final Set<String> loggingPackageNames = new ArraySet<>();
for (PackageRollbackInfo packageRollback : rollback.getPackages()) {
final String loggingParentName = getLoggingParentName(context,
packageRollback.getPackageName());
if (loggingParentName != null) {
loggingPackageNames.add(loggingParentName);
- } else {
- loggingPackageNames.add(packageRollback.getPackageName());
}
}
@@ -168,6 +171,10 @@ public final class WatchdogRollbackLogger {
if (logPackage != null) {
StatsLog.logWatchdogRollbackOccurred(type, logPackage.getPackageName(),
logPackage.getVersionCode(), rollbackReason, failingPackageName);
+ } else {
+ // In the case that the log package is null, still log an empty string as an
+ // indication that retrieving the logging parent failed.
+ StatsLog.logWatchdogRollbackOccurred(type, "", 0, rollbackReason, failingPackageName);
}
}
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index df6dfc4d8ffe..ed38e9a73050 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -3037,6 +3037,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
// Throw away any services that have been bound by this activity.
mServiceConnectionsHolder.disconnectActivityFromServices();
+ // This activity record is removing, make sure not to disconnect twice.
+ mServiceConnectionsHolder = null;
}
@Override
diff --git a/services/core/java/com/android/server/wm/ActivityServiceConnectionsHolder.java b/services/core/java/com/android/server/wm/ActivityServiceConnectionsHolder.java
index 6e75f9c9167f..5dfc261480f2 100644
--- a/services/core/java/com/android/server/wm/ActivityServiceConnectionsHolder.java
+++ b/services/core/java/com/android/server/wm/ActivityServiceConnectionsHolder.java
@@ -18,10 +18,13 @@ package com.android.server.wm;
import static com.android.server.wm.ActivityStack.ActivityState.PAUSING;
import static com.android.server.wm.ActivityStack.ActivityState.RESUMED;
+import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_CLEANUP;
+import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
+
+import android.util.ArraySet;
+import android.util.Slog;
import java.io.PrintWriter;
-import java.util.HashSet;
-import java.util.Iterator;
import java.util.function.Consumer;
/**
@@ -30,6 +33,8 @@ import java.util.function.Consumer;
* instance of this per activity for tracking all services connected to that activity. AM will
* sometimes query this to bump the OOM score for the processes with services connected to visible
* activities.
+ * <p>
+ * Public methods are called in AM lock, otherwise in WM lock.
*/
public class ActivityServiceConnectionsHolder<T> {
@@ -44,7 +49,10 @@ public class ActivityServiceConnectionsHolder<T> {
* on the WM side since we don't perform operations on the object. Mainly here for communication
* and booking with the AM side.
*/
- private HashSet<T> mConnections;
+ private ArraySet<T> mConnections;
+
+ /** Whether all connections of {@link #mActivity} are being removed. */
+ private volatile boolean mIsDisconnecting;
ActivityServiceConnectionsHolder(ActivityTaskManagerService service, ActivityRecord activity) {
mService = service;
@@ -54,8 +62,16 @@ public class ActivityServiceConnectionsHolder<T> {
/** Adds a connection record that the activity has bound to a specific service. */
public void addConnection(T c) {
synchronized (mService.mGlobalLock) {
+ if (mIsDisconnecting) {
+ // This is unlikely to happen because the caller should create a new holder.
+ if (DEBUG_CLEANUP) {
+ Slog.e(TAG_ATM, "Skip adding connection " + c + " to a disconnecting holder of "
+ + mActivity);
+ }
+ return;
+ }
if (mConnections == null) {
- mConnections = new HashSet<>();
+ mConnections = new ArraySet<>();
}
mConnections.add(c);
}
@@ -67,6 +83,9 @@ public class ActivityServiceConnectionsHolder<T> {
if (mConnections == null) {
return;
}
+ if (DEBUG_CLEANUP && mIsDisconnecting) {
+ Slog.v(TAG_ATM, "Remove pending disconnecting " + c + " of " + mActivity);
+ }
mConnections.remove(c);
}
}
@@ -88,26 +107,33 @@ public class ActivityServiceConnectionsHolder<T> {
if (mConnections == null || mConnections.isEmpty()) {
return;
}
- final Iterator<T> it = mConnections.iterator();
- while (it.hasNext()) {
- T c = it.next();
- consumer.accept(c);
+ for (int i = mConnections.size() - 1; i >= 0; i--) {
+ consumer.accept(mConnections.valueAt(i));
}
}
}
- /** Removes the connection between the activity and all services that were connected to it. */
+ /**
+ * Removes the connection between the activity and all services that were connected to it. In
+ * general, this method is used to clean up if the activity didn't unbind services before it
+ * is destroyed.
+ */
void disconnectActivityFromServices() {
- if (mConnections == null || mConnections.isEmpty()) {
+ if (mConnections == null || mConnections.isEmpty() || mIsDisconnecting) {
return;
}
- // Capture and null out mConnections, to guarantee that we process
+ // Mark as disconnecting, to guarantee that we process
// disconnect of these specific connections exactly once even if
// we're racing with rapid activity lifecycle churn and this
// method is invoked more than once on this object.
- final Object disc = mConnections;
- mConnections = null;
- mService.mH.post(() -> mService.mAmInternal.disconnectActivityFromServices(this, disc));
+ // It is possible that {@link #removeConnection} is called while the disconnect-runnable is
+ // still in the message queue, so keep the reference of {@link #mConnections} to make sure
+ // the connection list is up-to-date.
+ mIsDisconnecting = true;
+ mService.mH.post(() -> {
+ mService.mAmInternal.disconnectActivityFromServices(this);
+ mIsDisconnecting = false;
+ });
}
public void dump(PrintWriter pw, String prefix) {
@@ -116,4 +142,9 @@ public class ActivityServiceConnectionsHolder<T> {
}
}
+ /** Used by {@link ActivityRecord#dump}. */
+ @Override
+ public String toString() {
+ return String.valueOf(mConnections);
+ }
}
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 16ac9fb41f30..810aa3438ea0 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -194,6 +194,7 @@ import android.provider.Settings;
import android.util.ArraySet;
import android.util.DisplayMetrics;
import android.util.IntArray;
+import android.util.RotationUtils;
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
@@ -1603,17 +1604,18 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
if (cutout == null || cutout == DisplayCutout.NO_CUTOUT) {
return WmDisplayCutout.NO_CUTOUT;
}
+ final Insets waterfallInsets =
+ RotationUtils.rotateInsets(cutout.getWaterfallInsets(), rotation);
if (rotation == ROTATION_0) {
return WmDisplayCutout.computeSafeInsets(
cutout, mInitialDisplayWidth, mInitialDisplayHeight);
}
final boolean rotated = (rotation == ROTATION_90 || rotation == ROTATION_270);
final Rect[] newBounds = mRotationUtil.getRotatedBounds(
- WmDisplayCutout.computeSafeInsets(
- cutout, mInitialDisplayWidth, mInitialDisplayHeight)
- .getDisplayCutout().getBoundingRectsAll(),
+ cutout.getBoundingRectsAll(),
rotation, mInitialDisplayWidth, mInitialDisplayHeight);
- return WmDisplayCutout.computeSafeInsets(DisplayCutout.fromBounds(newBounds),
+ return WmDisplayCutout.computeSafeInsets(
+ DisplayCutout.fromBoundsAndWaterfall(newBounds, waterfallInsets),
rotated ? mInitialDisplayHeight : mInitialDisplayWidth,
rotated ? mInitialDisplayWidth : mInitialDisplayHeight);
}
diff --git a/services/core/java/com/android/server/wm/utils/WmDisplayCutout.java b/services/core/java/com/android/server/wm/utils/WmDisplayCutout.java
index 3be5d3176df5..46fff032e053 100644
--- a/services/core/java/com/android/server/wm/utils/WmDisplayCutout.java
+++ b/services/core/java/com/android/server/wm/utils/WmDisplayCutout.java
@@ -21,7 +21,6 @@ import android.util.Size;
import android.view.DisplayCutout;
import android.view.Gravity;
-import java.util.List;
import java.util.Objects;
/**
@@ -41,12 +40,17 @@ public class WmDisplayCutout {
mFrameSize = frameSize;
}
- public static WmDisplayCutout computeSafeInsets(DisplayCutout inner,
- int displayWidth, int displayHeight) {
- if (inner == DisplayCutout.NO_CUTOUT || inner.isBoundsEmpty()) {
+ /**
+ * Compute the safe insets according to the given DisplayCutout and the display size.
+ *
+ * @return return a WmDisplayCutout with calculated safe insets.
+ * @hide
+ */
+ public static WmDisplayCutout computeSafeInsets(
+ DisplayCutout inner, int displayWidth, int displayHeight) {
+ if (inner == DisplayCutout.NO_CUTOUT) {
return NO_CUTOUT;
}
-
final Size displaySize = new Size(displayWidth, displayHeight);
final Rect safeInsets = computeSafeInsets(displaySize, inner);
return new WmDisplayCutout(inner.replaceSafeInsets(safeInsets), displaySize);
@@ -112,57 +116,42 @@ public class WmDisplayCutout {
}
private static Rect computeSafeInsets(Size displaySize, DisplayCutout cutout) {
- if (displaySize.getWidth() < displaySize.getHeight()) {
- final List<Rect> boundingRects = cutout.replaceSafeInsets(
- new Rect(0, displaySize.getHeight() / 2, 0, displaySize.getHeight() / 2))
- .getBoundingRects();
- int topInset = findInsetForSide(displaySize, boundingRects, Gravity.TOP);
- int bottomInset = findInsetForSide(displaySize, boundingRects, Gravity.BOTTOM);
- return new Rect(0, topInset, 0, bottomInset);
- } else if (displaySize.getWidth() > displaySize.getHeight()) {
- final List<Rect> boundingRects = cutout.replaceSafeInsets(
- new Rect(displaySize.getWidth() / 2, 0, displaySize.getWidth() / 2, 0))
- .getBoundingRects();
- int leftInset = findInsetForSide(displaySize, boundingRects, Gravity.LEFT);
- int right = findInsetForSide(displaySize, boundingRects, Gravity.RIGHT);
- return new Rect(leftInset, 0, right, 0);
- } else {
+ if (displaySize.getWidth() == displaySize.getHeight()) {
throw new UnsupportedOperationException("not implemented: display=" + displaySize +
" cutout=" + cutout);
}
+
+ int leftInset = Math.max(cutout.getWaterfallInsets().left,
+ findCutoutInsetForSide(displaySize, cutout.getBoundingRectLeft(), Gravity.LEFT));
+ int topInset = Math.max(cutout.getWaterfallInsets().top,
+ findCutoutInsetForSide(displaySize, cutout.getBoundingRectTop(), Gravity.TOP));
+ int rightInset = Math.max(cutout.getWaterfallInsets().right,
+ findCutoutInsetForSide(displaySize, cutout.getBoundingRectRight(), Gravity.RIGHT));
+ int bottomInset = Math.max(cutout.getWaterfallInsets().bottom,
+ findCutoutInsetForSide(displaySize, cutout.getBoundingRectBottom(),
+ Gravity.BOTTOM));
+
+ return new Rect(leftInset, topInset, rightInset, bottomInset);
}
- private static int findInsetForSide(Size display, List<Rect> boundingRects, int gravity) {
+ private static int findCutoutInsetForSide(Size display, Rect boundingRect, int gravity) {
+ if (boundingRect.isEmpty()) {
+ return 0;
+ }
+
int inset = 0;
- final int size = boundingRects.size();
- for (int i = 0; i < size; i++) {
- Rect boundingRect = boundingRects.get(i);
- switch (gravity) {
- case Gravity.TOP:
- if (boundingRect.top == 0) {
- inset = Math.max(inset, boundingRect.bottom);
- }
- break;
- case Gravity.BOTTOM:
- if (boundingRect.bottom == display.getHeight()) {
- inset = Math.max(inset, display.getHeight() - boundingRect.top);
- }
- break;
- case Gravity.LEFT:
- if (boundingRect.left == 0) {
- inset = Math.max(inset, boundingRect.right);
- }
- break;
- case Gravity.RIGHT:
- if (boundingRect.right == display.getWidth()) {
- inset = Math.max(inset, display.getWidth() - boundingRect.left);
- }
- break;
- default:
- throw new IllegalArgumentException("unknown gravity: " + gravity);
- }
+ switch (gravity) {
+ case Gravity.TOP:
+ return Math.max(inset, boundingRect.bottom);
+ case Gravity.BOTTOM:
+ return Math.max(inset, display.getHeight() - boundingRect.top);
+ case Gravity.LEFT:
+ return Math.max(inset, boundingRect.right);
+ case Gravity.RIGHT:
+ return Math.max(inset, display.getWidth() - boundingRect.left);
+ default:
+ throw new IllegalArgumentException("unknown gravity: " + gravity);
}
- return inset;
}
public DisplayCutout getDisplayCutout() {
diff --git a/services/core/jni/com_android_server_incremental_IncrementalManagerService.cpp b/services/core/jni/com_android_server_incremental_IncrementalManagerService.cpp
index 5e255f46fa05..10bac94f77e2 100644
--- a/services/core/jni/com_android_server_incremental_IncrementalManagerService.cpp
+++ b/services/core/jni/com_android_server_incremental_IncrementalManagerService.cpp
@@ -33,9 +33,14 @@ static void nativeSystemReady(JNIEnv* env, jclass klass, jlong self) {
Incremental_IncrementalService_OnSystemReady(self);
}
+static void nativeDump(JNIEnv* env, jclass klass, jlong self, jint fd) {
+ Incremental_IncrementalService_OnDump(self, fd);
+}
+
static const JNINativeMethod method_table[] = {
{"nativeStartService", "()J", (void*)nativeStartService},
{"nativeSystemReady", "(J)V", (void*)nativeSystemReady},
+ {"nativeDump", "(JI)V", (void*)nativeDump},
};
int register_android_server_incremental_IncrementalManagerService(JNIEnv* env) {
diff --git a/services/incremental/BinderIncrementalService.cpp b/services/incremental/BinderIncrementalService.cpp
index 91d05723a605..0941831f5299 100644
--- a/services/incremental/BinderIncrementalService.cpp
+++ b/services/incremental/BinderIncrementalService.cpp
@@ -17,12 +17,14 @@
#include "BinderIncrementalService.h"
#include <binder/IResultReceiver.h>
+#include <binder/PermissionCache.h>
#include <incfs.h>
#include "ServiceWrappers.h"
#include "jni.h"
#include "nativehelper/JNIHelp.h"
#include "path.h"
+#include <android-base/logging.h>
using namespace std::literals;
using namespace android::incremental;
@@ -90,8 +92,13 @@ BinderIncrementalService* BinderIncrementalService::start() {
return self.get();
}
-status_t BinderIncrementalService::dump(int fd, const Vector<String16>& args) {
- return OK;
+status_t BinderIncrementalService::dump(int fd, const Vector<String16>&) {
+ static const String16 kDump("android.permission.DUMP");
+ if (!PermissionCache::checkCallingPermission(kDump)) {
+ return PERMISSION_DENIED;
+ }
+ mImpl.onDump(fd);
+ return NO_ERROR;
}
void BinderIncrementalService::onSystemReady() {
@@ -280,3 +287,10 @@ void Incremental_IncrementalService_OnSystemReady(jlong self) {
((android::os::incremental::BinderIncrementalService*)self)->onSystemReady();
}
}
+void Incremental_IncrementalService_OnDump(jlong self, jint fd) {
+ if (self) {
+ ((android::os::incremental::BinderIncrementalService*)self)->dump(fd, {});
+ } else {
+ dprintf(fd, "BinderIncrementalService is stopped.");
+ }
+}
diff --git a/services/incremental/IncrementalService.cpp b/services/incremental/IncrementalService.cpp
index e4a37dde7758..dbd97cfa039a 100644
--- a/services/incremental/IncrementalService.cpp
+++ b/services/incremental/IncrementalService.cpp
@@ -35,6 +35,7 @@
#include <uuid/uuid.h>
#include <zlib.h>
+#include <ctime>
#include <iterator>
#include <span>
#include <stack>
@@ -169,7 +170,7 @@ auto IncrementalService::IncFsMount::makeStorage(StorageId id) -> StorageMap::it
base::StringAppendF(&name, "%.*s_%d_%d", int(constants().storagePrefix.size()),
constants().storagePrefix.data(), id, no);
auto fullName = path::join(root, constants().mount, name);
- if (auto err = incrementalService.mIncFs->makeDir(control, fullName); !err) {
+ if (auto err = incrementalService.mIncFs->makeDir(control, fullName, 0755); !err) {
std::lock_guard l(lock);
return storages.insert_or_assign(id, Storage{std::move(fullName)}).first;
} else if (err != EEXIST) {
@@ -256,6 +257,68 @@ FileId IncrementalService::idFromMetadata(std::span<const uint8_t> metadata) {
IncrementalService::~IncrementalService() = default;
+inline const char* toString(TimePoint t) {
+ using SystemClock = std::chrono::system_clock;
+ time_t time = SystemClock::to_time_t(SystemClock::now() + std::chrono::duration_cast<SystemClock::duration>(t - Clock::now()));
+ return std::ctime(&time);
+}
+
+inline const char* toString(IncrementalService::BindKind kind) {
+ switch (kind) {
+ case IncrementalService::BindKind::Temporary:
+ return "Temporary";
+ case IncrementalService::BindKind::Permanent:
+ return "Permanent";
+ }
+}
+
+void IncrementalService::onDump(int fd) {
+ dprintf(fd, "Incremental is %s\n", incfs::enabled() ? "ENABLED" : "DISABLED");
+ dprintf(fd, "Incremental dir: %s\n", mIncrementalDir.c_str());
+
+ std::unique_lock l(mLock);
+
+ dprintf(fd, "Mounts (%d):\n", int(mMounts.size()));
+ for (auto&& [id, ifs] : mMounts) {
+ const IncFsMount& mnt = *ifs.get();
+ dprintf(fd, "\t[%d]:\n", id);
+ dprintf(fd, "\t\tmountId: %d\n", mnt.mountId);
+ dprintf(fd, "\t\tnextStorageDirNo: %d\n", mnt.nextStorageDirNo.load());
+ dprintf(fd, "\t\tdataLoaderStatus: %d\n", mnt.dataLoaderStatus.load());
+ dprintf(fd, "\t\tconnectionLostTime: %s\n", toString(mnt.connectionLostTime));
+ if (mnt.savedDataLoaderParams) {
+ const auto& params = mnt.savedDataLoaderParams.value();
+ dprintf(fd, "\t\tsavedDataLoaderParams:\n");
+ dprintf(fd, "\t\t\ttype: %s\n", toString(params.type).c_str());
+ dprintf(fd, "\t\t\tpackageName: %s\n", params.packageName.c_str());
+ dprintf(fd, "\t\t\tclassName: %s\n", params.className.c_str());
+ dprintf(fd, "\t\t\targuments: %s\n", params.arguments.c_str());
+ dprintf(fd, "\t\t\tdynamicArgs: %d\n", int(params.dynamicArgs.size()));
+ }
+ dprintf(fd, "\t\tstorages (%d):\n", int(mnt.storages.size()));
+ for (auto&& [storageId, storage] : mnt.storages) {
+ dprintf(fd, "\t\t\t[%d] -> [%s]\n", storageId, storage.name.c_str());
+ }
+
+ dprintf(fd, "\t\tbindPoints (%d):\n", int(mnt.bindPoints.size()));
+ for (auto&& [target, bind] : mnt.bindPoints) {
+ dprintf(fd, "\t\t\t[%s]->[%d]:\n", target.c_str(), bind.storage);
+ dprintf(fd, "\t\t\t\tsavedFilename: %s\n", bind.savedFilename.c_str());
+ dprintf(fd, "\t\t\t\tsourceDir: %s\n", bind.sourceDir.c_str());
+ dprintf(fd, "\t\t\t\tkind: %s\n", toString(bind.kind));
+ }
+ }
+
+ dprintf(fd, "Sorted binds (%d):\n", int(mBindsByPath.size()));
+ for (auto&& [target, mountPairIt] : mBindsByPath) {
+ const auto& bind = mountPairIt->second;
+ dprintf(fd, "\t\t[%s]->[%d]:\n", target.c_str(), bind.storage);
+ dprintf(fd, "\t\t\tsavedFilename: %s\n", bind.savedFilename.c_str());
+ dprintf(fd, "\t\t\tsourceDir: %s\n", bind.sourceDir.c_str());
+ dprintf(fd, "\t\t\tkind: %s\n", toString(bind.kind));
+ }
+}
+
std::optional<std::future<void>> IncrementalService::onSystemReady() {
std::promise<void> threadFinished;
if (mSystemReady.exchange(true)) {
@@ -617,15 +680,7 @@ int IncrementalService::bind(StorageId storage, std::string_view source, std::st
if (storageInfo == ifs->storages.end()) {
return -EINVAL;
}
- std::string normSource;
- if (path::isAbsolute(source)) {
- normSource = path::normalize(source);
- } else {
- normSource = path::normalize(path::join(storageInfo->second.name, source));
- }
- if (!path::startsWith(normSource, storageInfo->second.name)) {
- return -EINVAL;
- }
+ std::string normSource = normalizePathToStorage(ifs, storage, source);
l.unlock();
std::unique_lock l2(mLock, std::defer_lock);
return addBindMount(*ifs, storage, storageInfo->second.name, std::move(normSource),
@@ -674,20 +729,29 @@ int IncrementalService::unbind(StorageId storage, std::string_view target) {
return 0;
}
+std::string IncrementalService::normalizePathToStorage(const IncrementalService::IfsMountPtr ifs,
+ StorageId storage, std::string_view path) {
+ const auto storageInfo = ifs->storages.find(storage);
+ if (storageInfo == ifs->storages.end()) {
+ return {};
+ }
+ std::string normPath;
+ if (path::isAbsolute(path)) {
+ normPath = path::normalize(path);
+ } else {
+ normPath = path::normalize(path::join(storageInfo->second.name, path));
+ }
+ if (!path::startsWith(normPath, storageInfo->second.name)) {
+ return {};
+ }
+ return normPath;
+}
+
int IncrementalService::makeFile(StorageId storage, std::string_view path, int mode, FileId id,
incfs::NewFileParams params) {
if (auto ifs = getIfs(storage)) {
- const auto storageInfo = ifs->storages.find(storage);
- if (storageInfo == ifs->storages.end()) {
- return -EINVAL;
- }
- std::string normPath;
- if (path::isAbsolute(path)) {
- normPath = path::normalize(path);
- } else {
- normPath = path::normalize(path::join(storageInfo->second.name, path));
- }
- if (!path::startsWith(normPath, storageInfo->second.name)) {
+ std::string normPath = normalizePathToStorage(ifs, storage, path);
+ if (normPath.empty()) {
return -EINVAL;
}
auto err = mIncFs->makeFile(ifs->control, normPath, mode, id, params);
@@ -706,7 +770,11 @@ int IncrementalService::makeFile(StorageId storage, std::string_view path, int m
int IncrementalService::makeDir(StorageId storageId, std::string_view path, int mode) {
if (auto ifs = getIfs(storageId)) {
- return mIncFs->makeDir(ifs->control, path, mode);
+ std::string normPath = normalizePathToStorage(ifs, storageId, path);
+ if (normPath.empty()) {
+ return -EINVAL;
+ }
+ return mIncFs->makeDir(ifs->control, normPath, mode);
}
return -EINVAL;
}
@@ -716,31 +784,40 @@ int IncrementalService::makeDirs(StorageId storageId, std::string_view path, int
if (!ifs) {
return -EINVAL;
}
-
- auto err = mIncFs->makeDir(ifs->control, path, mode);
+ std::string normPath = normalizePathToStorage(ifs, storageId, path);
+ if (normPath.empty()) {
+ return -EINVAL;
+ }
+ auto err = mIncFs->makeDir(ifs->control, normPath, mode);
if (err == -EEXIST) {
return 0;
} else if (err != -ENOENT) {
return err;
}
- if (auto err = makeDirs(storageId, path::dirname(path), mode)) {
+ if (auto err = makeDirs(storageId, path::dirname(normPath), mode)) {
return err;
}
- return mIncFs->makeDir(ifs->control, path, mode);
+ return mIncFs->makeDir(ifs->control, normPath, mode);
}
int IncrementalService::link(StorageId sourceStorageId, std::string_view oldPath,
StorageId destStorageId, std::string_view newPath) {
if (auto ifsSrc = getIfs(sourceStorageId), ifsDest = getIfs(destStorageId);
ifsSrc && ifsSrc == ifsDest) {
- return mIncFs->link(ifsSrc->control, oldPath, newPath);
+ std::string normOldPath = normalizePathToStorage(ifsSrc, sourceStorageId, oldPath);
+ std::string normNewPath = normalizePathToStorage(ifsDest, destStorageId, newPath);
+ if (normOldPath.empty() || normNewPath.empty()) {
+ return -EINVAL;
+ }
+ return mIncFs->link(ifsSrc->control, normOldPath, normNewPath);
}
return -EINVAL;
}
int IncrementalService::unlink(StorageId storage, std::string_view path) {
if (auto ifs = getIfs(storage)) {
- return mIncFs->unlink(ifs->control, path);
+ std::string normOldPath = normalizePathToStorage(ifs, storage, path);
+ return mIncFs->unlink(ifs->control, normOldPath);
}
return -EINVAL;
}
diff --git a/services/incremental/IncrementalService.h b/services/incremental/IncrementalService.h
index ca5e4dbd9231..dec9f64f2084 100644
--- a/services/incremental/IncrementalService.h
+++ b/services/incremental/IncrementalService.h
@@ -18,8 +18,8 @@
#include <android-base/strings.h>
#include <android-base/unique_fd.h>
-#include <android/os/incremental/IIncrementalManager.h>
#include <android/content/pm/DataLoaderParamsParcel.h>
+#include <android/os/incremental/IIncrementalManager.h>
#include <binder/IServiceManager.h>
#include <utils/String16.h>
#include <utils/StrongPointer.h>
@@ -90,10 +90,11 @@ public:
return idFromMetadata({(const uint8_t*)metadata.data(), metadata.size()});
}
+ void onDump(int fd);
+
std::optional<std::future<void>> onSystemReady();
- StorageId createStorage(std::string_view mountPoint,
- DataLoaderParamsParcel&& dataLoaderParams,
+ StorageId createStorage(std::string_view mountPoint, DataLoaderParamsParcel&& dataLoaderParams,
CreateOptions options = CreateOptions::Default);
StorageId createLinkedStorage(std::string_view mountPoint, StorageId linkedStorage,
CreateOptions options = CreateOptions::Default);
@@ -109,8 +110,8 @@ public:
int makeFile(StorageId storage, std::string_view path, int mode, FileId id,
incfs::NewFileParams params);
- int makeDir(StorageId storage, std::string_view path, int mode = 0555);
- int makeDirs(StorageId storage, std::string_view path, int mode = 0555);
+ int makeDir(StorageId storage, std::string_view path, int mode = 0755);
+ int makeDirs(StorageId storage, std::string_view path, int mode = 0755);
int link(StorageId sourceStorageId, std::string_view oldPath, StorageId destStorageId,
std::string_view newPath);
@@ -207,6 +208,8 @@ private:
void deleteStorage(IncFsMount& ifs);
void deleteStorageLocked(IncFsMount& ifs, std::unique_lock<std::mutex>&& ifsLock);
MountMap::iterator getStorageSlotLocked();
+ std::string normalizePathToStorage(const IfsMountPtr incfs, StorageId storage,
+ std::string_view path);
// Member variables
std::unique_ptr<VoldServiceWrapper> mVold;
diff --git a/services/incremental/ServiceWrappers.h b/services/incremental/ServiceWrappers.h
index ae3739dba2f0..f0b56729e8d7 100644
--- a/services/incremental/ServiceWrappers.h
+++ b/services/incremental/ServiceWrappers.h
@@ -70,7 +70,7 @@ public:
virtual ~IncFsWrapper() = default;
virtual ErrorCode makeFile(Control control, std::string_view path, int mode, FileId id,
NewFileParams params) const = 0;
- virtual ErrorCode makeDir(Control control, std::string_view path, int mode = 0555) const = 0;
+ virtual ErrorCode makeDir(Control control, std::string_view path, int mode) const = 0;
virtual RawMetadata getMetadata(Control control, FileId fileid) const = 0;
virtual RawMetadata getMetadata(Control control, std::string_view path) const = 0;
virtual FileId getFileId(Control control, std::string_view path) const = 0;
diff --git a/services/incremental/include/incremental_service.h b/services/incremental/include/incremental_service.h
index 7109d953ba4d..4a34b11261b9 100644
--- a/services/incremental/include/incremental_service.h
+++ b/services/incremental/include/incremental_service.h
@@ -26,6 +26,7 @@ __BEGIN_DECLS
jlong Incremental_IncrementalService_Start();
void Incremental_IncrementalService_OnSystemReady(jlong self);
+void Incremental_IncrementalService_OnDump(jlong self, jint fd);
__END_DECLS
diff --git a/services/incremental/test/IncrementalServiceTest.cpp b/services/incremental/test/IncrementalServiceTest.cpp
index 28268181f173..9cdc83e75055 100644
--- a/services/incremental/test/IncrementalServiceTest.cpp
+++ b/services/incremental/test/IncrementalServiceTest.cpp
@@ -406,29 +406,16 @@ TEST_F(IncrementalServiceTest, testMakeDirectory) {
int storageId =
mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
IncrementalService::CreateOptions::CreateNew);
- std::string_view dir_path("test");
- EXPECT_CALL(*mIncFs, makeDir(_, dir_path, _));
- auto res = mIncrementalService->makeDir(storageId, dir_path, 0555);
- ASSERT_EQ(res, 0);
-}
+ std::string dir_path("test");
-TEST_F(IncrementalServiceTest, testMakeDirectoryNested) {
- mVold->mountIncFsSuccess();
- mIncFs->makeFileSuccess();
- mVold->bindMountSuccess();
- mIncrementalManager->prepareDataLoaderSuccess();
- mIncrementalManager->startDataLoaderSuccess();
- TemporaryDir tempDir;
- int storageId =
- mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel),
- IncrementalService::CreateOptions::CreateNew);
- auto first = "first"sv;
- auto second = "second"sv;
- std::string dir_path = std::string(first) + "/" + std::string(second);
- EXPECT_CALL(*mIncFs, makeDir(_, first, _)).Times(0);
- EXPECT_CALL(*mIncFs, makeDir(_, second, _)).Times(0);
- EXPECT_CALL(*mIncFs, makeDir(_, std::string_view(dir_path), _)).Times(1);
+ std::string tempPath(tempDir.path);
+ std::replace(tempPath.begin(), tempPath.end(), '/', '_');
+ std::string mount_dir = std::string(mRootDir.path) + "/" + tempPath.substr(1);
+ std::string normalized_dir_path = mount_dir + "/mount/st_1_0/" + dir_path;
+ // Expecting incfs to call makeDir on a path like:
+ // /data/local/tmp/TemporaryDir-06yixG/data_local_tmp_TemporaryDir-xwdFhT/mount/st_1_0/test
+ EXPECT_CALL(*mIncFs, makeDir(_, std::string_view(normalized_dir_path), _));
auto res = mIncrementalService->makeDir(storageId, dir_path, 0555);
ASSERT_EQ(res, 0);
}
@@ -446,15 +433,29 @@ TEST_F(IncrementalServiceTest, testMakeDirectories) {
auto first = "first"sv;
auto second = "second"sv;
auto third = "third"sv;
+
+ std::string tempPath(tempDir.path);
+ std::replace(tempPath.begin(), tempPath.end(), '/', '_');
+ std::string mount_dir = std::string(mRootDir.path) + "/" + tempPath.substr(1);
+
InSequence seq;
auto parent_path = std::string(first) + "/" + std::string(second);
auto dir_path = parent_path + "/" + std::string(third);
- EXPECT_CALL(*mIncFs, makeDir(_, std::string_view(dir_path), _)).WillOnce(Return(-ENOENT));
- EXPECT_CALL(*mIncFs, makeDir(_, std::string_view(parent_path), _)).WillOnce(Return(-ENOENT));
- EXPECT_CALL(*mIncFs, makeDir(_, first, _)).WillOnce(Return(0));
- EXPECT_CALL(*mIncFs, makeDir(_, std::string_view(parent_path), _)).WillOnce(Return(0));
- EXPECT_CALL(*mIncFs, makeDir(_, std::string_view(dir_path), _)).WillOnce(Return(0));
- auto res = mIncrementalService->makeDirs(storageId, dir_path, 0555);
+
+ std::string normalized_first_path = mount_dir + "/mount/st_1_0/" + std::string(first);
+ std::string normalized_parent_path = mount_dir + "/mount/st_1_0/" + parent_path;
+ std::string normalized_dir_path = mount_dir + "/mount/st_1_0/" + dir_path;
+
+ EXPECT_CALL(*mIncFs, makeDir(_, std::string_view(normalized_dir_path), _))
+ .WillOnce(Return(-ENOENT));
+ EXPECT_CALL(*mIncFs, makeDir(_, std::string_view(normalized_parent_path), _))
+ .WillOnce(Return(-ENOENT));
+ EXPECT_CALL(*mIncFs, makeDir(_, std::string_view(normalized_first_path), _))
+ .WillOnce(Return(0));
+ EXPECT_CALL(*mIncFs, makeDir(_, std::string_view(normalized_parent_path), _))
+ .WillOnce(Return(0));
+ EXPECT_CALL(*mIncFs, makeDir(_, std::string_view(normalized_dir_path), _)).WillOnce(Return(0));
+ auto res = mIncrementalService->makeDirs(storageId, normalized_dir_path, 0555);
ASSERT_EQ(res, 0);
}
} // namespace android::os::incremental
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/CachedAppOptimizerTest.java b/services/tests/mockingservicestests/src/com/android/server/am/CachedAppOptimizerTest.java
index 1985513c4290..e5ec1f76c554 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/CachedAppOptimizerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/CachedAppOptimizerTest.java
@@ -36,6 +36,7 @@ import com.android.server.appop.AppOpsService;
import com.android.server.testables.TestableDeviceConfig;
import org.junit.After;
+import org.junit.Assume;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -122,6 +123,8 @@ public final class CachedAppOptimizerTest {
CachedAppOptimizer.DEFAULT_COMPACT_THROTTLE_4);
assertThat(mCachedAppOptimizerUnderTest.mCompactStatsdSampleRate).isEqualTo(
CachedAppOptimizer.DEFAULT_STATSD_SAMPLE_RATE);
+ assertThat(mCachedAppOptimizerUnderTest.mFreezerStatsdSampleRate).isEqualTo(
+ CachedAppOptimizer.DEFAULT_STATSD_SAMPLE_RATE);
assertThat(mCachedAppOptimizerUnderTest.mFullAnonRssThrottleKb).isEqualTo(
CachedAppOptimizer.DEFAULT_COMPACT_FULL_RSS_THROTTLE_KB);
assertThat(mCachedAppOptimizerUnderTest.mCompactThrottleBFGS).isEqualTo(
@@ -132,6 +135,8 @@ public final class CachedAppOptimizerTest {
CachedAppOptimizer.DEFAULT_COMPACT_FULL_RSS_THROTTLE_KB);
assertThat(mCachedAppOptimizerUnderTest.mFullDeltaRssThrottleKb).isEqualTo(
CachedAppOptimizer.DEFAULT_COMPACT_FULL_DELTA_RSS_THROTTLE_KB);
+ assertThat(mCachedAppOptimizerUnderTest.useFreezer()).isEqualTo(
+ CachedAppOptimizer.DEFAULT_USE_FREEZER);
Set<Integer> expected = new HashSet<>();
for (String s : TextUtils.split(
@@ -177,6 +182,9 @@ public final class CachedAppOptimizerTest {
CachedAppOptimizer.KEY_COMPACT_STATSD_SAMPLE_RATE,
Float.toString(CachedAppOptimizer.DEFAULT_STATSD_SAMPLE_RATE + 0.1f), false);
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ CachedAppOptimizer.KEY_FREEZER_STATSD_SAMPLE_RATE,
+ Float.toString(CachedAppOptimizer.DEFAULT_STATSD_SAMPLE_RATE + 0.1f), false);
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
CachedAppOptimizer.KEY_COMPACT_FULL_RSS_THROTTLE_KB,
Long.toString(CachedAppOptimizer.DEFAULT_COMPACT_FULL_RSS_THROTTLE_KB + 1), false);
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
@@ -185,6 +193,11 @@ public final class CachedAppOptimizerTest {
CachedAppOptimizer.DEFAULT_COMPACT_FULL_DELTA_RSS_THROTTLE_KB + 1), false);
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
CachedAppOptimizer.KEY_COMPACT_PROC_STATE_THROTTLE, "1,2,3", false);
+ assertThat(mCachedAppOptimizerUnderTest.useFreezer()).isEqualTo(
+ CachedAppOptimizer.DEFAULT_USE_FREEZER);
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ CachedAppOptimizer.KEY_USE_FREEZER, CachedAppOptimizer.DEFAULT_USE_FREEZER
+ ? "false" : "true" , false);
// Then calling init will read and set that flag.
mCachedAppOptimizerUnderTest.init();
@@ -211,6 +224,8 @@ public final class CachedAppOptimizerTest {
CachedAppOptimizer.DEFAULT_COMPACT_THROTTLE_6 + 1);
assertThat(mCachedAppOptimizerUnderTest.mCompactStatsdSampleRate).isEqualTo(
CachedAppOptimizer.DEFAULT_STATSD_SAMPLE_RATE + 0.1f);
+ assertThat(mCachedAppOptimizerUnderTest.mFreezerStatsdSampleRate).isEqualTo(
+ CachedAppOptimizer.DEFAULT_STATSD_SAMPLE_RATE + 0.1f);
assertThat(mCachedAppOptimizerUnderTest.mCompactThrottleBFGS).isEqualTo(
CachedAppOptimizer.DEFAULT_COMPACT_THROTTLE_5 + 1);
assertThat(mCachedAppOptimizerUnderTest.mCompactThrottlePersistent).isEqualTo(
@@ -218,6 +233,14 @@ public final class CachedAppOptimizerTest {
assertThat(mCachedAppOptimizerUnderTest.mFullAnonRssThrottleKb).isEqualTo(
CachedAppOptimizer.DEFAULT_COMPACT_FULL_RSS_THROTTLE_KB + 1);
assertThat(mCachedAppOptimizerUnderTest.mProcStateThrottle).containsExactly(1, 2, 3);
+
+ if (mCachedAppOptimizerUnderTest.isFreezerSupported()) {
+ if (CachedAppOptimizer.DEFAULT_USE_FREEZER) {
+ assertThat(mCachedAppOptimizerUnderTest.useFreezer()).isFalse();
+ } else {
+ assertThat(mCachedAppOptimizerUnderTest.useFreezer()).isTrue();
+ }
+ }
}
@Test
@@ -244,6 +267,44 @@ public final class CachedAppOptimizerTest {
}
@Test
+ public void useFreeze_doesNotListenToDeviceConfigChanges() throws InterruptedException {
+ Assume.assumeTrue(mCachedAppOptimizerUnderTest.isFreezerSupported());
+
+ assertThat(mCachedAppOptimizerUnderTest.useFreezer()).isEqualTo(
+ CachedAppOptimizer.DEFAULT_USE_FREEZER);
+
+ // The freezer DeviceConfig property is read at boot only
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ CachedAppOptimizer.KEY_USE_FREEZER, "true", false);
+ mCachedAppOptimizerUnderTest.init();
+ mCountDown = new CountDownLatch(1);
+
+ // No notifications should get to the cached app optimizer.
+ assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isFalse();
+
+ // The flag value has to be set correctly.
+ assertThat(mCachedAppOptimizerUnderTest.useFreezer()).isTrue();
+ // The cached app optimizer thread must be running.
+ assertThat(mCachedAppOptimizerUnderTest.mCachedAppOptimizerThread.isAlive()).isTrue();
+
+ // Set the flag the other way without rebooting. It shall not change.
+ mCountDown = new CountDownLatch(1);
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ CachedAppOptimizer.KEY_USE_FREEZER, "false", false);
+ assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue();
+ assertThat(mCachedAppOptimizerUnderTest.useFreezer()).isTrue();
+
+
+ // Now, set the flag to false and restart the cached app optimizer
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ CachedAppOptimizer.KEY_USE_FREEZER, "false", false);
+ mCachedAppOptimizerUnderTest.init();
+
+ // The flag value has to be set correctly.
+ assertThat(mCachedAppOptimizerUnderTest.useFreezer()).isFalse();
+ }
+
+ @Test
public void useCompaction_listensToDeviceConfigChangesBadValues() throws InterruptedException {
assertThat(mCachedAppOptimizerUnderTest.useCompaction()).isEqualTo(
CachedAppOptimizer.DEFAULT_USE_COMPACTION);
@@ -261,6 +322,22 @@ public final class CachedAppOptimizerTest {
}
@Test
+ public void useFreeze_listensToDeviceConfigChangesBadValues() throws InterruptedException {
+ assertThat(mCachedAppOptimizerUnderTest.useFreezer()).isEqualTo(
+ CachedAppOptimizer.DEFAULT_USE_FREEZER);
+
+ // When we push an invalid flag value...
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ CachedAppOptimizer.KEY_USE_FREEZER, "foobar", false);
+
+ mCachedAppOptimizerUnderTest.init();
+
+ // Then we set the default.
+ assertThat(mCachedAppOptimizerUnderTest.useFreezer()).isEqualTo(
+ CachedAppOptimizer.DEFAULT_USE_FREEZER);
+ }
+
+ @Test
public void compactAction_listensToDeviceConfigChanges() throws InterruptedException {
mCachedAppOptimizerUnderTest.init();
@@ -482,6 +559,17 @@ public final class CachedAppOptimizerTest {
// Then that override is reflected in the compactor.
assertThat(mCachedAppOptimizerUnderTest.mCompactStatsdSampleRate).isEqualTo(
CachedAppOptimizer.DEFAULT_STATSD_SAMPLE_RATE + 0.1f);
+
+ // When we override mFreezerStatsdSampleRate with a reasonable value ...
+ mCountDown = new CountDownLatch(1);
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ CachedAppOptimizer.KEY_FREEZER_STATSD_SAMPLE_RATE,
+ Float.toString(CachedAppOptimizer.DEFAULT_STATSD_SAMPLE_RATE + 0.1f), false);
+ assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue();
+
+ // Then that override is reflected in the compactor.
+ assertThat(mCachedAppOptimizerUnderTest.mFreezerStatsdSampleRate).isEqualTo(
+ CachedAppOptimizer.DEFAULT_STATSD_SAMPLE_RATE + 0.1f);
}
@Test
@@ -498,6 +586,16 @@ public final class CachedAppOptimizerTest {
// Then that override is reflected in the compactor.
assertThat(mCachedAppOptimizerUnderTest.mCompactStatsdSampleRate).isEqualTo(
CachedAppOptimizer.DEFAULT_STATSD_SAMPLE_RATE);
+
+ // When we override mFreezerStatsdSampleRate with an unreasonable value ...
+ mCountDown = new CountDownLatch(1);
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ CachedAppOptimizer.KEY_FREEZER_STATSD_SAMPLE_RATE, "foo", false);
+ assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue();
+
+ // Then that override is reflected in the freezer.
+ assertThat(mCachedAppOptimizerUnderTest.mFreezerStatsdSampleRate).isEqualTo(
+ CachedAppOptimizer.DEFAULT_STATSD_SAMPLE_RATE);
}
@Test
@@ -523,6 +621,25 @@ public final class CachedAppOptimizerTest {
// Then the values is capped in the range.
assertThat(mCachedAppOptimizerUnderTest.mCompactStatsdSampleRate).isEqualTo(1.0f);
+
+ // When we override mFreezerStatsdSampleRate with an value outside of [0..1]...
+ mCountDown = new CountDownLatch(1);
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ CachedAppOptimizer.KEY_FREEZER_STATSD_SAMPLE_RATE,
+ Float.toString(-1.0f), false);
+ assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue();
+
+ // Then the values is capped in the range.
+ assertThat(mCachedAppOptimizerUnderTest.mFreezerStatsdSampleRate).isEqualTo(0.0f);
+
+ mCountDown = new CountDownLatch(1);
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ CachedAppOptimizer.KEY_FREEZER_STATSD_SAMPLE_RATE,
+ Float.toString(1.01f), false);
+ assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue();
+
+ // Then the values is capped in the range.
+ assertThat(mCachedAppOptimizerUnderTest.mFreezerStatsdSampleRate).isEqualTo(1.0f);
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java b/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java
index fd8ccb30c98f..4a7636a179b1 100644
--- a/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java
@@ -31,6 +31,7 @@ import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
@@ -109,14 +110,21 @@ public class AppIntegrityManagerServiceImplTest {
private static final String PLAY_STORE_CERT = "play_store_cert";
private static final String ADB_CERT = "";
- @org.junit.Rule public MockitoRule mMockitoRule = MockitoJUnit.rule();
-
- @Mock PackageManagerInternal mPackageManagerInternal;
- @Mock Context mMockContext;
- @Mock Resources mMockResources;
- @Mock RuleEvaluationEngine mRuleEvaluationEngine;
- @Mock IntegrityFileManager mIntegrityFileManager;
- @Mock Handler mHandler;
+ @org.junit.Rule
+ public MockitoRule mMockitoRule = MockitoJUnit.rule();
+
+ @Mock
+ PackageManagerInternal mPackageManagerInternal;
+ @Mock
+ Context mMockContext;
+ @Mock
+ Resources mMockResources;
+ @Mock
+ RuleEvaluationEngine mRuleEvaluationEngine;
+ @Mock
+ IntegrityFileManager mIntegrityFileManager;
+ @Mock
+ Handler mHandler;
private PackageManager mSpyPackageManager;
private File mTestApk;
@@ -142,13 +150,10 @@ public class AppIntegrityManagerServiceImplTest {
// setup mocks to prevent NPE
when(mMockContext.getPackageManager()).thenReturn(mSpyPackageManager);
when(mMockContext.getResources()).thenReturn(mMockResources);
- when(mMockResources.getStringArray(anyInt())).thenReturn(new String[] {});
+ when(mMockResources.getStringArray(anyInt())).thenReturn(new String[]{});
when(mIntegrityFileManager.initialized()).thenReturn(true);
}
- // TODO(b/148370598): Implement a test to validate that allow response is retuned when the test
- // request times out.
-
@Test
public void updateRuleSet_notAuthorized() throws Exception {
makeUsSystemApp();
@@ -357,9 +362,17 @@ public class AppIntegrityManagerServiceImplTest {
public void verifierAsInstaller_skipIntegrityVerification() throws Exception {
whitelistUsAsRuleProvider();
makeUsSystemApp();
+ mService =
+ new AppIntegrityManagerServiceImpl(
+ mMockContext,
+ mPackageManagerInternal,
+ mRuleEvaluationEngine,
+ mIntegrityFileManager,
+ mHandler,
+ /* checkIntegrityForRuleProviders= */ false);
ArgumentCaptor<BroadcastReceiver> broadcastReceiverCaptor =
ArgumentCaptor.forClass(BroadcastReceiver.class);
- verify(mMockContext)
+ verify(mMockContext, atLeastOnce())
.registerReceiver(broadcastReceiverCaptor.capture(), any(), any(), any());
Intent intent = makeVerificationIntent(TEST_FRAMEWORK_PACKAGE);
when(mRuleEvaluationEngine.evaluate(any(), any()))
@@ -386,7 +399,7 @@ public class AppIntegrityManagerServiceImplTest {
private void whitelistUsAsRuleProvider() {
Resources mockResources = mock(Resources.class);
when(mockResources.getStringArray(R.array.config_integrityRuleProviderPackages))
- .thenReturn(new String[] {TEST_FRAMEWORK_PACKAGE});
+ .thenReturn(new String[]{TEST_FRAMEWORK_PACKAGE});
when(mMockContext.getResources()).thenReturn(mockResources);
}
diff --git a/services/tests/servicestests/src/com/android/server/rollback/RollbackUnitTest.java b/services/tests/servicestests/src/com/android/server/rollback/RollbackUnitTest.java
index 164c88382828..9719509659ec 100644
--- a/services/tests/servicestests/src/com/android/server/rollback/RollbackUnitTest.java
+++ b/services/tests/servicestests/src/com/android/server/rollback/RollbackUnitTest.java
@@ -291,6 +291,17 @@ public class RollbackUnitTest {
verify(mMockDataHelper).restoreAppData(123, pkgInfo1, 7, 333, "blah");
}
+ @Test
+ public void notifySessionWithSuccess() {
+ int[] sessionIds = new int[]{ 7777, 8888 };
+ Rollback rollback = new Rollback(123, new File("/test/testing"), -1, USER, INSTALLER,
+ sessionIds);
+ // The 1st invocation returns false because not all child sessions are notified.
+ assertThat(rollback.notifySessionWithSuccess()).isFalse();
+ // The 2nd invocation returns true because now all child sessions are notified.
+ assertThat(rollback.notifySessionWithSuccess()).isTrue();
+ }
+
private static PackageRollbackInfo newPkgInfoFor(
String packageName, long fromVersion, long toVersion, boolean isApex) {
return new PackageRollbackInfo(new VersionedPackage(packageName, fromVersion),
diff --git a/services/tests/servicestests/src/com/android/server/rollback/WatchdogRollbackLoggerTest.java b/services/tests/servicestests/src/com/android/server/rollback/WatchdogRollbackLoggerTest.java
index 61117f18445b..ba493d4f9646 100644
--- a/services/tests/servicestests/src/com/android/server/rollback/WatchdogRollbackLoggerTest.java
+++ b/services/tests/servicestests/src/com/android/server/rollback/WatchdogRollbackLoggerTest.java
@@ -60,18 +60,18 @@ public class WatchdogRollbackLoggerTest {
}
/**
- * Ensures that the original package is returned if the application info has no metadata.
+ * Ensures that null is returned if the application info has no metadata.
*/
@Test
public void testLogPackageHasNoMetadata() throws Exception {
when(mMockPm.getApplicationInfo(anyString(), anyInt())).thenReturn(mApplicationInfo);
VersionedPackage logPackage = WatchdogRollbackLogger.getLogPackage(mMockContext,
sTestPackageV1);
- assertThat(logPackage).isEqualTo(sTestPackageV1);
+ assertThat(logPackage).isNull();
}
/**
- * Ensures the original package is returned if the application info does not contain a logging
+ * Ensures that null is returned if the application info does not contain a logging
* parent key.
*/
@Test
@@ -81,7 +81,7 @@ public class WatchdogRollbackLoggerTest {
bundle.putString(LOGGING_PARENT_KEY, null);
VersionedPackage logPackage = WatchdogRollbackLogger.getLogPackage(mMockContext,
sTestPackageV1);
- assertThat(logPackage).isEqualTo(sTestPackageV1);
+ assertThat(logPackage).isNull();
}
/**
@@ -102,8 +102,7 @@ public class WatchdogRollbackLoggerTest {
}
/**
- * Ensures that the original package is returned if Package Manager does not know about the
- * logging parent.
+ * Ensures that null is returned if Package Manager does not know about the logging parent.
*/
@Test
public void testLogPackageNameNotFound() throws Exception {
@@ -114,6 +113,6 @@ public class WatchdogRollbackLoggerTest {
new PackageManager.NameNotFoundException());
VersionedPackage logPackage = WatchdogRollbackLogger.getLogPackage(mMockContext,
sTestPackageV1);
- assertThat(logPackage).isEqualTo(sTestPackageV1);
+ assertThat(logPackage).isNull();
}
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index 2cf5eaefcc58..34872db5cf7e 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -159,6 +159,7 @@ import com.android.server.lights.LightsManager;
import com.android.server.lights.LogicalLight;
import com.android.server.notification.NotificationManagerService.NotificationAssistants;
import com.android.server.notification.NotificationManagerService.NotificationListeners;
+import com.android.server.statusbar.StatusBarManagerInternal;
import com.android.server.uri.UriGrantsManagerInternal;
import com.android.server.wm.WindowManagerInternal;
@@ -261,6 +262,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
NotificationRecordLoggerFake mNotificationRecordLogger = new NotificationRecordLoggerFake();
private InstanceIdSequence mNotificationInstanceIdSequence = new InstanceIdSequenceFake(
1 << 30);
+ @Mock
+ StatusBarManagerInternal mStatusBar;
// Use a Testable subclass so we can simulate calls from the system without failing.
private static class TestableNotificationManagerService extends NotificationManagerService {
@@ -356,6 +359,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
LocalServices.addService(UriGrantsManagerInternal.class, mUgmInternal);
LocalServices.removeServiceForTest(WindowManagerInternal.class);
LocalServices.addService(WindowManagerInternal.class, mWindowManagerInternal);
+ LocalServices.removeServiceForTest(StatusBarManagerInternal.class);
+ LocalServices.addService(StatusBarManagerInternal.class, mStatusBar);
doNothing().when(mContext).sendBroadcastAsUser(any(), any(), any());
@@ -4483,7 +4488,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
}
@Test
- public void testAllowForegroundToasts() throws Exception {
+ public void testAllowForegroundCustomToasts() throws Exception {
final String testPackage = "testPackageName";
assertEquals(0, mService.mToastQueue.size());
mService.isSystemUid = false;
@@ -4506,6 +4511,79 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
}
@Test
+ public void testDisallowBackgroundCustomToasts() throws Exception {
+ final String testPackage = "testPackageName";
+ assertEquals(0, mService.mToastQueue.size());
+ mService.isSystemUid = false;
+
+ // package is not suspended
+ when(mPackageManager.isPackageSuspendedForUser(testPackage, UserHandle.getUserId(mUid)))
+ .thenReturn(false);
+
+ // this app is NOT in the foreground
+ when(mActivityManager.getUidImportance(mUid)).thenReturn(IMPORTANCE_NONE);
+
+ // enqueue toast -> no toasts enqueued
+ ((INotificationManager) mService.mService).enqueueToast(testPackage, new Binder(),
+ new TestableToastCallback(), 2000, 0);
+ assertEquals(0, mService.mToastQueue.size());
+ }
+
+ @Test
+ public void testAllowForegroundTextToasts() throws Exception {
+ final String testPackage = "testPackageName";
+ assertEquals(0, mService.mToastQueue.size());
+ mService.isSystemUid = false;
+
+ // package is not suspended
+ when(mPackageManager.isPackageSuspendedForUser(testPackage, UserHandle.getUserId(mUid)))
+ .thenReturn(false);
+
+ // this app is in the foreground
+ when(mActivityManager.getUidImportance(mUid)).thenReturn(IMPORTANCE_FOREGROUND);
+
+ // enqueue toast -> toast should still enqueue
+ ((INotificationManager) mService.mService).enqueueTextToast(testPackage, new Binder(),
+ "Text", 2000, 0, null);
+ assertEquals(1, mService.mToastQueue.size());
+ }
+
+ @Test
+ public void testAllowBackgroundTextToasts() throws Exception {
+ final String testPackage = "testPackageName";
+ assertEquals(0, mService.mToastQueue.size());
+ mService.isSystemUid = false;
+
+ // package is not suspended
+ when(mPackageManager.isPackageSuspendedForUser(testPackage, UserHandle.getUserId(mUid)))
+ .thenReturn(false);
+
+ // this app is NOT in the foreground
+ when(mActivityManager.getUidImportance(mUid)).thenReturn(IMPORTANCE_NONE);
+
+ // enqueue toast -> toast should still enqueue
+ ((INotificationManager) mService.mService).enqueueTextToast(testPackage, new Binder(),
+ "Text", 2000, 0, null);
+ assertEquals(1, mService.mToastQueue.size());
+ }
+
+ @Test
+ public void testTextToastsCallStatusBar() throws Exception {
+ final String testPackage = "testPackageName";
+ assertEquals(0, mService.mToastQueue.size());
+ mService.isSystemUid = false;
+
+ // package is not suspended
+ when(mPackageManager.isPackageSuspendedForUser(testPackage, UserHandle.getUserId(mUid)))
+ .thenReturn(false);
+
+ // enqueue toast -> no toasts enqueued
+ ((INotificationManager) mService.mService).enqueueTextToast(testPackage, new Binder(),
+ "Text", 2000, 0, null);
+ verify(mStatusBar).showToast(any(), any(), any(), any(), anyInt(), any());
+ }
+
+ @Test
public void testDisallowToastsFromSuspendedPackages() throws Exception {
final String testPackage = "testPackageName";
assertEquals(0, mService.mToastQueue.size());
diff --git a/services/tests/wmtests/src/com/android/server/wm/utils/WmDisplayCutoutTest.java b/services/tests/wmtests/src/com/android/server/wm/utils/WmDisplayCutoutTest.java
index fb8ba7bffd4c..a283476bfdf0 100644
--- a/services/tests/wmtests/src/com/android/server/wm/utils/WmDisplayCutoutTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/utils/WmDisplayCutoutTest.java
@@ -47,6 +47,7 @@ import org.junit.Test;
@SmallTest
@Presubmit
public class WmDisplayCutoutTest {
+ private static final Rect ZERO_RECT = new Rect();
private final DisplayCutout mCutoutTop = new DisplayCutout(
Insets.of(0, 100, 0, 0),
null /* boundLeft */, new Rect(50, 0, 75, 100) /* boundTop */,
@@ -99,41 +100,204 @@ public class WmDisplayCutoutTest {
}
@Test
- public void computeSafeInsets_top() {
+ public void computeSafeInsets_cutoutTop() {
WmDisplayCutout cutout = WmDisplayCutout.computeSafeInsets(
- fromBoundingRect(0, 0, 100, 20, BOUNDS_POSITION_TOP), 200, 400);
+ fromBoundingRect(80, 0, 120, 20, BOUNDS_POSITION_TOP), 200, 400);
assertEquals(new Rect(0, 20, 0, 0), cutout.getDisplayCutout().getSafeInsets());
}
@Test
- public void computeSafeInsets_left() {
+ public void computeSafeInsets_cutoutLeft() {
WmDisplayCutout cutout = WmDisplayCutout.computeSafeInsets(
- fromBoundingRect(0, 0, 20, 100, BOUNDS_POSITION_LEFT), 400, 200);
+ fromBoundingRect(0, 180, 20, 220, BOUNDS_POSITION_LEFT), 200, 400);
assertEquals(new Rect(20, 0, 0, 0), cutout.getDisplayCutout().getSafeInsets());
}
@Test
- public void computeSafeInsets_bottom() {
+ public void computeSafeInsets_cutoutBottom() {
WmDisplayCutout cutout = WmDisplayCutout.computeSafeInsets(
- fromBoundingRect(0, 180, 100, 200, BOUNDS_POSITION_BOTTOM), 100, 200);
+ fromBoundingRect(80, 380, 120, 400, BOUNDS_POSITION_BOTTOM), 200, 400);
assertEquals(new Rect(0, 0, 0, 20), cutout.getDisplayCutout().getSafeInsets());
}
@Test
- public void computeSafeInsets_right() {
+ public void computeSafeInsets_cutoutRight() {
WmDisplayCutout cutout = WmDisplayCutout.computeSafeInsets(
- fromBoundingRect(180, 0, 200, 100, BOUNDS_POSITION_RIGHT), 200, 100);
+ fromBoundingRect(180, 180, 200, 220, BOUNDS_POSITION_RIGHT), 200, 400);
assertEquals(new Rect(0, 0, 20, 0), cutout.getDisplayCutout().getSafeInsets());
}
@Test
+ public void computeSafeInsets_topLeftCornerCutout_portrait() {
+ WmDisplayCutout cutout = WmDisplayCutout.computeSafeInsets(
+ fromBoundingRect(0, 0, 20, 20, BOUNDS_POSITION_TOP), 200, 400);
+
+ assertEquals(new Rect(0, 20, 0, 0), cutout.getDisplayCutout().getSafeInsets());
+ }
+
+ @Test
+ public void computeSafeInsets_topRightCornerCutout_portrait() {
+ WmDisplayCutout cutout = WmDisplayCutout.computeSafeInsets(
+ fromBoundingRect(180, 0, 200, 20, BOUNDS_POSITION_TOP), 200, 400);
+
+ assertEquals(new Rect(0, 20, 0, 0), cutout.getDisplayCutout().getSafeInsets());
+ }
+
+ @Test
+ public void computeSafeInsets_bottomLeftCornerCutout_portrait() {
+ WmDisplayCutout cutout = WmDisplayCutout.computeSafeInsets(
+ fromBoundingRect(0, 380, 20, 400, BOUNDS_POSITION_BOTTOM), 200, 400);
+
+ assertEquals(new Rect(0, 0, 0, 20), cutout.getDisplayCutout().getSafeInsets());
+ }
+
+ @Test
+ public void computeSafeInsets_bottomRightCornerCutout_portrait() {
+ WmDisplayCutout cutout = WmDisplayCutout.computeSafeInsets(
+ fromBoundingRect(180, 380, 200, 400, BOUNDS_POSITION_BOTTOM), 200, 400);
+
+ assertEquals(new Rect(0, 0, 0, 20), cutout.getDisplayCutout().getSafeInsets());
+ }
+
+ @Test
+ public void computeSafeInsets_topLeftCornerCutout_landscape() {
+ WmDisplayCutout cutout = WmDisplayCutout.computeSafeInsets(
+ fromBoundingRect(0, 0, 20, 20, BOUNDS_POSITION_LEFT), 400, 200);
+
+ assertEquals(new Rect(20, 0, 0, 0), cutout.getDisplayCutout().getSafeInsets());
+ }
+
+ @Test
+ public void computeSafeInsets_topRightCornerCutout_landscape() {
+ WmDisplayCutout cutout = WmDisplayCutout.computeSafeInsets(
+ fromBoundingRect(380, 0, 400, 20, BOUNDS_POSITION_RIGHT), 400, 200);
+
+ assertEquals(new Rect(0, 0, 20, 0), cutout.getDisplayCutout().getSafeInsets());
+ }
+
+ @Test
+ public void computeSafeInsets_bottomLeftCornerCutout_landscape() {
+ WmDisplayCutout cutout = WmDisplayCutout.computeSafeInsets(
+ fromBoundingRect(0, 180, 20, 200, BOUNDS_POSITION_LEFT), 400, 200);
+
+ assertEquals(new Rect(20, 0, 0, 0), cutout.getDisplayCutout().getSafeInsets());
+ }
+
+ @Test
+ public void computeSafeInsets_bottomRightCornerCutout_landscape() {
+ WmDisplayCutout cutout = WmDisplayCutout.computeSafeInsets(
+ fromBoundingRect(380, 180, 400, 200, BOUNDS_POSITION_RIGHT), 400, 200);
+
+ assertEquals(new Rect(0, 0, 20, 0), cutout.getDisplayCutout().getSafeInsets());
+ }
+
+ @Test
+ public void computeSafeInsets_waterfall() {
+ WmDisplayCutout cutout = WmDisplayCutout.computeSafeInsets(
+ DisplayCutout.fromBoundsAndWaterfall(
+ new Rect[] {ZERO_RECT, ZERO_RECT, ZERO_RECT, ZERO_RECT},
+ Insets.of(1, 2, 3, 4)),
+ 200, 400);
+
+ assertEquals(new Rect(1, 2, 3, 4), cutout.getDisplayCutout().getSafeInsets());
+ }
+
+ @Test
+ public void computeSafeInsets_cutoutTop_greaterThan_waterfallTop() {
+ WmDisplayCutout cutout = WmDisplayCutout.computeSafeInsets(
+ DisplayCutout.fromBoundsAndWaterfall(
+ new Rect[] {ZERO_RECT, new Rect(80, 0, 120, 30), ZERO_RECT, ZERO_RECT},
+ Insets.of(0, 20, 0, 0)),
+ 200, 400);
+
+ assertEquals(new Rect(0, 30, 0, 0), cutout.getDisplayCutout().getSafeInsets());
+ }
+
+ @Test
+ public void computeSafeInsets_cutoutTop_lessThan_waterfallTop() {
+ WmDisplayCutout cutout = WmDisplayCutout.computeSafeInsets(
+ DisplayCutout.fromBoundsAndWaterfall(
+ new Rect[] {ZERO_RECT, new Rect(80, 0, 120, 30), ZERO_RECT, ZERO_RECT},
+ Insets.of(0, 40, 0, 0)),
+ 200, 400);
+
+ assertEquals(new Rect(0, 40, 0, 0), cutout.getDisplayCutout().getSafeInsets());
+ }
+
+ @Test
+ public void computeSafeInsets_cutoutLeft_greaterThan_waterfallLeft() {
+ WmDisplayCutout cutout = WmDisplayCutout.computeSafeInsets(
+ DisplayCutout.fromBoundsAndWaterfall(
+ new Rect[] {new Rect(0, 180, 30, 220), ZERO_RECT, ZERO_RECT, ZERO_RECT},
+ Insets.of(20, 0, 0, 0)),
+ 200, 400);
+
+ assertEquals(new Rect(30, 0, 0, 0), cutout.getDisplayCutout().getSafeInsets());
+ }
+
+ @Test
+ public void computeSafeInsets_cutoutLeft_lessThan_waterfallLeft() {
+ WmDisplayCutout cutout = WmDisplayCutout.computeSafeInsets(
+ DisplayCutout.fromBoundsAndWaterfall(
+ new Rect[] {new Rect(0, 180, 30, 220), ZERO_RECT, ZERO_RECT, ZERO_RECT},
+ Insets.of(40, 0, 0, 0)),
+ 200, 400);
+
+ assertEquals(new Rect(40, 0, 0, 0), cutout.getDisplayCutout().getSafeInsets());
+ }
+
+ @Test
+ public void computeSafeInsets_cutoutBottom_greaterThan_waterfallBottom() {
+ WmDisplayCutout cutout = WmDisplayCutout.computeSafeInsets(
+ DisplayCutout.fromBoundsAndWaterfall(
+ new Rect[] {ZERO_RECT, ZERO_RECT, ZERO_RECT, new Rect(80, 370, 120, 400)},
+ Insets.of(0, 0, 0, 20)),
+ 200, 400);
+
+ assertEquals(new Rect(0, 0, 0, 30), cutout.getDisplayCutout().getSafeInsets());
+ }
+
+ @Test
+ public void computeSafeInsets_cutoutBottom_lessThan_waterfallBottom() {
+ WmDisplayCutout cutout = WmDisplayCutout.computeSafeInsets(
+ DisplayCutout.fromBoundsAndWaterfall(
+ new Rect[] {ZERO_RECT, ZERO_RECT, ZERO_RECT, new Rect(80, 370, 120, 400)},
+ Insets.of(0, 0, 0, 40)),
+ 200, 400);
+
+ assertEquals(new Rect(0, 0, 0, 40), cutout.getDisplayCutout().getSafeInsets());
+ }
+
+ @Test
+ public void computeSafeInsets_cutoutRight_greaterThan_waterfallRight() {
+ WmDisplayCutout cutout = WmDisplayCutout.computeSafeInsets(
+ DisplayCutout.fromBoundsAndWaterfall(
+ new Rect[] {ZERO_RECT, ZERO_RECT, new Rect(170, 180, 200, 220), ZERO_RECT},
+ Insets.of(0, 0, 20, 0)),
+ 200, 400);
+
+ assertEquals(new Rect(0, 0, 30, 0), cutout.getDisplayCutout().getSafeInsets());
+ }
+
+ @Test
+ public void computeSafeInsets_cutoutRight_lessThan_waterfallRight() {
+ WmDisplayCutout cutout = WmDisplayCutout.computeSafeInsets(
+ DisplayCutout.fromBoundsAndWaterfall(
+ new Rect[] {ZERO_RECT, ZERO_RECT, new Rect(170, 180, 200, 220), ZERO_RECT},
+ Insets.of(0, 0, 40, 0)),
+ 200, 400);
+
+ assertEquals(new Rect(0, 0, 40, 0), cutout.getDisplayCutout().getSafeInsets());
+ }
+
+ @Test
public void computeSafeInsets_bounds() {
- DisplayCutout cutout = WmDisplayCutout.computeSafeInsets(mCutoutTop, 1000,
- 2000).getDisplayCutout();
+ DisplayCutout cutout =
+ WmDisplayCutout.computeSafeInsets(mCutoutTop, 1000, 2000).getDisplayCutout();
assertEquals(mCutoutTop.getBoundingRects(), cutout.getBoundingRects());
}
diff --git a/startop/iorap/TEST_MAPPING b/startop/iorap/TEST_MAPPING
index 8c9d4dfb0894..1d8119d91240 100644
--- a/startop/iorap/TEST_MAPPING
+++ b/startop/iorap/TEST_MAPPING
@@ -2,6 +2,9 @@
"presubmit": [
{
"name": "libiorap-java-tests"
+ },
+ {
+ "name": "iorap-functional-tests"
}
],
"imports": [
diff --git a/telephony/java/android/telephony/SmsCbMessage.java b/telephony/java/android/telephony/SmsCbMessage.java
index c0dfec9a1172..752707e5a5dc 100644
--- a/telephony/java/android/telephony/SmsCbMessage.java
+++ b/telephony/java/android/telephony/SmsCbMessage.java
@@ -586,6 +586,7 @@ public final class SmsCbMessage implements Parcelable {
cv.put(CellBroadcasts.SERIAL_NUMBER, getSerialNumber());
cv.put(CellBroadcasts.SERVICE_CATEGORY, getServiceCategory());
cv.put(CellBroadcasts.LANGUAGE_CODE, getLanguageCode());
+ cv.put(CellBroadcasts.DATA_CODING_SCHEME, getDataCodingScheme());
cv.put(CellBroadcasts.MESSAGE_BODY, getMessageBody());
cv.put(CellBroadcasts.MESSAGE_FORMAT, getMessageFormat());
cv.put(CellBroadcasts.MESSAGE_PRIORITY, getMessagePriority());
diff --git a/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java b/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java
index ce2f7c50e581..82a524be5c1e 100644
--- a/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java
+++ b/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java
@@ -329,6 +329,46 @@ public class StagedRollbackTest extends BaseHostJUnit4Test {
}
/**
+ * Tests that data in DE (user) apex data directory is restored when apex is rolled back.
+ */
+ @Test
+ public void testRollbackApexDataDirectories_DeUser() throws Exception {
+ pushTestApex();
+
+ // Push files to apex data directory
+ String oldFilePath1 = apexDataDirDeUser(
+ APK_IN_APEX_TESTAPEX_NAME, 0) + "/" + TEST_FILENAME_1;
+ String oldFilePath2 =
+ apexDataDirDeUser(APK_IN_APEX_TESTAPEX_NAME, 0) + TEST_SUBDIR + TEST_FILENAME_2;
+ assertTrue(getDevice().pushString(TEST_STRING_1, oldFilePath1));
+ assertTrue(getDevice().pushString(TEST_STRING_2, oldFilePath2));
+
+ // Install new version of the APEX with rollback enabled
+ runPhase("testRollbackApexDataDirectories_Phase1");
+ getDevice().reboot();
+
+ // Replace files in data directory
+ getDevice().deleteFile(oldFilePath1);
+ getDevice().deleteFile(oldFilePath2);
+ String newFilePath3 =
+ apexDataDirDeUser(APK_IN_APEX_TESTAPEX_NAME, 0) + "/" + TEST_FILENAME_3;
+ String newFilePath4 =
+ apexDataDirDeUser(APK_IN_APEX_TESTAPEX_NAME, 0) + TEST_SUBDIR + TEST_FILENAME_4;
+ assertTrue(getDevice().pushString(TEST_STRING_3, newFilePath3));
+ assertTrue(getDevice().pushString(TEST_STRING_4, newFilePath4));
+
+ // Roll back the APEX
+ runPhase("testRollbackApexDataDirectories_Phase2");
+ getDevice().reboot();
+
+ // Verify that old files have been restored and new files are gone
+ assertEquals(TEST_STRING_1, getDevice().pullFileContents(oldFilePath1));
+ assertEquals(TEST_STRING_2, getDevice().pullFileContents(oldFilePath2));
+ assertNull(getDevice().pullFile(newFilePath3));
+ assertNull(getDevice().pullFile(newFilePath4));
+ }
+
+ /**
* Tests that data in CE apex data directory is restored when apex is rolled back.
*/
@Test
@@ -382,6 +422,10 @@ public class StagedRollbackTest extends BaseHostJUnit4Test {
return String.format("/data/misc/apexdata/%s", apexName);
}
+ private static String apexDataDirDeUser(String apexName, int userId) {
+ return String.format("/data/misc_de/%d/apexdata/%s", userId, apexName);
+ }
+
private static String apexDataDirCe(String apexName, int userId) {
return String.format("/data/misc_ce/%d/apexdata/%s", userId, apexName);
}
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 5592cd7c2f9f..028c1dad82e4 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -5741,6 +5741,40 @@ public class ConnectivityServiceTest {
mCm.unregisterNetworkCallback(defaultCallback);
}
+ @Test
+ public final void testLoseTrusted() throws Exception {
+ final NetworkRequest trustedRequest = new NetworkRequest.Builder()
+ .addCapability(NET_CAPABILITY_TRUSTED)
+ .build();
+ final TestNetworkCallback trustedCallback = new TestNetworkCallback();
+ mCm.requestNetwork(trustedRequest, trustedCallback);
+
+ mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
+ mCellNetworkAgent.connect(true);
+ trustedCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
+ verify(mNetworkManagementService).setDefaultNetId(eq(mCellNetworkAgent.getNetwork().netId));
+
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
+ mWiFiNetworkAgent.connect(true);
+ trustedCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
+ verify(mNetworkManagementService).setDefaultNetId(eq(mWiFiNetworkAgent.getNetwork().netId));
+
+ mWiFiNetworkAgent.removeCapability(NET_CAPABILITY_TRUSTED);
+ // There is currently a bug where losing the TRUSTED capability will send a LOST
+ // callback to requests before the available callback, in spite of the semantics
+ // of the requests dictating this should not happen. This is considered benign, but
+ // ideally should be fixed in the future.
+ trustedCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
+ trustedCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
+ verify(mNetworkManagementService).setDefaultNetId(eq(mCellNetworkAgent.getNetwork().netId));
+
+ mCellNetworkAgent.removeCapability(NET_CAPABILITY_TRUSTED);
+ trustedCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
+ verify(mNetworkManagementService).clearDefaultNetId();
+
+ mCm.unregisterNetworkCallback(trustedCallback);
+ }
+
@Ignore // 40%+ flakiness : figure out why and re-enable.
@Test
public final void testBatteryStatsNetworkType() throws Exception {
diff --git a/tools/aapt2/link/ManifestFixer.cpp b/tools/aapt2/link/ManifestFixer.cpp
index 954d4010d181..2af118c40138 100644
--- a/tools/aapt2/link/ManifestFixer.cpp
+++ b/tools/aapt2/link/ManifestFixer.cpp
@@ -428,6 +428,12 @@ bool ManifestFixer::BuildRules(xml::XmlActionExecutor* executor,
application_action["meta-data"] = meta_data_action;
+ application_action["processes"];
+ application_action["processes"]["deny-permission"];
+ application_action["processes"]["allow-permission"];
+ application_action["processes"]["process"]["deny-permission"];
+ application_action["processes"]["process"]["allow-permission"];
+
application_action["activity"] = component_action;
application_action["activity"]["layout"];
diff --git a/tools/stats_log_api_gen/Android.bp b/tools/stats_log_api_gen/Android.bp
index d3958a65c704..0e32aee93ebd 100644
--- a/tools/stats_log_api_gen/Android.bp
+++ b/tools/stats_log_api_gen/Android.bp
@@ -30,7 +30,6 @@ cc_binary_host {
"utils.cpp",
],
cflags: [
- "-DSTATS_SCHEMA_LEGACY",
"-Wall",
"-Werror",
],
diff --git a/wifi/java/android/net/wifi/IScoreChangeCallback.aidl b/wifi/java/android/net/wifi/IScoreChangeCallback.aidl
index fd236107bc6e..462a97844d76 100644
--- a/wifi/java/android/net/wifi/IScoreChangeCallback.aidl
+++ b/wifi/java/android/net/wifi/IScoreChangeCallback.aidl
@@ -16,6 +16,8 @@
package android.net.wifi;
+import android.net.NetworkScore;
+
/**
* Interface for Wi-Fi network score callback.
*
@@ -23,7 +25,7 @@ package android.net.wifi;
*/
oneway interface IScoreChangeCallback
{
- void onStatusChange(int sessionId, boolean exiting);
+ void onScoreChange(int sessionId, in NetworkScore score);
void onTriggerUpdateOfWifiUsabilityStats(int sessionId);
}
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 76f97164032c..5c5471d5a1b2 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -38,6 +38,7 @@ import android.net.ConnectivityManager;
import android.net.DhcpInfo;
import android.net.MacAddress;
import android.net.Network;
+import android.net.NetworkScore;
import android.net.NetworkStack;
import android.net.wifi.hotspot2.IProvisioningCallback;
import android.net.wifi.hotspot2.OsuProvider;
@@ -256,12 +257,12 @@ public class WifiManager {
* - {@link #EXTRA_SCAN_AVAILABLE}
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_WIFI_SCAN_AVAILABLE =
- "android.net.wifi.action.WIFI_SCAN_AVAILABLE";
+ public static final String ACTION_WIFI_SCAN_AVAILABILITY_CHANGED =
+ "android.net.wifi.action.WIFI_SCAN_AVAILABILITY_CHANGED";
/**
* A boolean extra indicating whether scanning is currently available.
- * Sent in the broadcast {@link #ACTION_WIFI_SCAN_AVAILABLE}.
+ * Sent in the broadcast {@link #ACTION_WIFI_SCAN_AVAILABILITY_CHANGED}.
* Its value is true if scanning is currently available, false otherwise.
*/
public static final String EXTRA_SCAN_AVAILABLE = "android.net.wifi.extra.SCAN_AVAILABLE";
@@ -5948,10 +5949,11 @@ public class WifiManager {
*
* @param sessionId The ID to indicate current Wi-Fi network connection obtained from
* {@link WifiConnectedNetworkScorer#start(int)}.
- * @param isUsable The bit to indicate whether current Wi-Fi network is usable or not.
- * Populated by connected network scorer in applications.
+ * @param score The {@link android.net.NetworkScore} object representing the
+ * characteristics of current Wi-Fi network. Populated by connected network
+ * scorer in applications.
*/
- void onStatusChange(int sessionId, boolean isUsable);
+ void onScoreChange(int sessionId, @NonNull NetworkScore score);
/**
* Called by applications to trigger an update of {@link WifiUsabilityStatsEntry}.
@@ -5977,9 +5979,9 @@ public class WifiManager {
}
@Override
- public void onStatusChange(int sessionId, boolean isUsable) {
+ public void onScoreChange(int sessionId, @NonNull NetworkScore score) {
try {
- mScoreChangeCallback.onStatusChange(sessionId, isUsable);
+ mScoreChangeCallback.onScoreChange(sessionId, score);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/wifi/java/android/net/wifi/WifiScanner.java b/wifi/java/android/net/wifi/WifiScanner.java
index 8250a95c97a9..a85f40b3c1b8 100644
--- a/wifi/java/android/net/wifi/WifiScanner.java
+++ b/wifi/java/android/net/wifi/WifiScanner.java
@@ -837,7 +837,7 @@ public class WifiScanner {
*
* @param enable set to true to enable scanning, set to false to disable all types of scanning.
*
- * @see WifiManager#ACTION_WIFI_SCAN_AVAILABLE
+ * @see WifiManager#ACTION_WIFI_SCAN_AVAILABILITY_CHANGED
* {@hide}
*/
@SystemApi