summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.bp3
-rw-r--r--apct-tests/perftests/autofill/Android.bp1
-rw-r--r--apct-tests/perftests/autofill/AndroidManifest.xml5
-rw-r--r--apct-tests/perftests/autofill/src/android/view/autofill/AbstractAutofillPerfTestCase.java2
-rw-r--r--apct-tests/perftests/autofill/src/android/view/autofill/LoginTest.java10
-rw-r--r--apct-tests/perftests/blobstore/src/com/android/perftests/blob/BlobStorePerfTests.java10
-rw-r--r--apct-tests/perftests/contentcapture/Android.bp28
-rw-r--r--apct-tests/perftests/contentcapture/AndroidManifest.xml44
-rw-r--r--apct-tests/perftests/contentcapture/AndroidTest.xml27
-rw-r--r--apct-tests/perftests/contentcapture/res/layout/test_container_activity.xml (renamed from core/java/android/app/IRequestFinishCallback.aidl)27
-rw-r--r--apct-tests/perftests/contentcapture/res/layout/test_login_activity.xml50
-rw-r--r--apct-tests/perftests/contentcapture/src/android/view/contentcapture/AbstractContentCapturePerfTestCase.java267
-rw-r--r--apct-tests/perftests/contentcapture/src/android/view/contentcapture/CustomTestActivity.java88
-rw-r--r--apct-tests/perftests/contentcapture/src/android/view/contentcapture/LoginTest.java158
-rw-r--r--apct-tests/perftests/contentcapture/src/android/view/contentcapture/MyContentCaptureService.java181
-rw-r--r--apct-tests/perftests/core/Android.bp3
-rw-r--r--apct-tests/perftests/core/AndroidTest.xml27
-rw-r--r--apct-tests/perftests/core/src/android/view/CutoutSpecificationBenchmark.java38
-rw-r--r--apct-tests/perftests/windowmanager/Android.bp1
-rw-r--r--apex/jobscheduler/framework/java/com/android/server/DeviceIdleInternal.java2
-rw-r--r--apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java19
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java2
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/JobStore.java19
-rw-r--r--apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java23
-rw-r--r--apex/statsd/aidl/Android.bp1
-rw-r--r--apex/statsd/aidl/android/os/IStatsCompanionService.aidl11
-rw-r--r--apex/statsd/aidl/android/os/IStatsd.aidl7
-rw-r--r--apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java66
-rw-r--r--api/current.txt27
-rw-r--r--api/module-lib-current.txt13
-rw-r--r--api/test-current.txt4
-rw-r--r--cmds/statsd/Android.bp9
-rw-r--r--cmds/statsd/src/StatsLogProcessor.cpp39
-rw-r--r--cmds/statsd/src/StatsLogProcessor.h26
-rw-r--r--cmds/statsd/src/StatsService.cpp32
-rw-r--r--cmds/statsd/src/StatsService.h5
-rw-r--r--cmds/statsd/src/atoms.proto2
-rw-r--r--cmds/statsd/src/config/ConfigManager.cpp2
-rw-r--r--cmds/statsd/src/config/ConfigManager.h2
-rw-r--r--cmds/statsd/tests/LogEntryMatcher_test.cpp3
-rw-r--r--cmds/statsd/tests/e2e/Anomaly_duration_sum_e2e_test.cpp264
-rw-r--r--cmds/telecom/src/com/android/commands/telecom/Telecom.java10
-rw-r--r--cmds/uiautomator/api/current.txt389
-rw-r--r--cmds/uiautomator/api/removed.txt1
-rw-r--r--cmds/uiautomator/library/Android.bp30
-rw-r--r--cmds/uiautomator/library/testrunner-src/com/android/uiautomator/core/UiAutomationShellWrapper.java6
-rw-r--r--cmds/uiautomator/library/testrunner-src/com/android/uiautomator/testrunner/UiAutomatorTestCase.java10
-rw-r--r--config/preloaded-classes3
-rw-r--r--core/java/android/animation/AnimatorSet.java20
-rw-r--r--core/java/android/app/Activity.java22
-rw-r--r--core/java/android/app/ActivityManagerInternal.java19
-rw-r--r--core/java/android/app/IActivityTaskManager.aidl7
-rw-r--r--core/java/android/app/INotificationManager.aidl1
-rw-r--r--core/java/android/app/LoadedApk.java36
-rw-r--r--core/java/android/app/Notification.java16
-rw-r--r--core/java/android/app/NotificationChannel.java5
-rw-r--r--core/java/android/app/NotificationManager.java38
-rw-r--r--core/java/android/app/WindowConfiguration.java7
-rw-r--r--core/java/android/app/backup/BackupAgent.java2
-rw-r--r--core/java/android/app/usage/UsageStats.java5
-rw-r--r--core/java/android/bluetooth/BluetoothDevice.java4
-rw-r--r--core/java/android/content/ContentProvider.java5
-rw-r--r--core/java/android/content/ContentResolver.java2
-rw-r--r--core/java/android/content/Context.java10
-rw-r--r--core/java/android/content/SyncStatusInfo.java2
-rw-r--r--core/java/android/content/pm/PackageParser.java6
-rw-r--r--core/java/android/content/pm/dex/DexMetadataHelper.java4
-rw-r--r--core/java/android/content/res/Configuration.java2
-rw-r--r--core/java/android/database/sqlite/SQLiteDatabase.java2
-rw-r--r--core/java/android/hardware/camera2/CameraDevice.java4
-rw-r--r--core/java/android/hardware/hdmi/HdmiControlManager.java34
-rw-r--r--core/java/android/hardware/hdmi/IHdmiVendorCommandListener.aidl2
-rw-r--r--core/java/android/net/ConnectivityManager.java10
-rw-r--r--core/java/android/net/NetworkAgent.java3
-rw-r--r--core/java/android/net/NetworkState.java4
-rw-r--r--core/java/android/net/NetworkStatsHistory.java36
-rw-r--r--core/java/android/net/NetworkUtils.java31
-rw-r--r--core/java/android/net/SntpClient.java30
-rw-r--r--core/java/android/net/VpnService.java2
-rw-r--r--core/java/android/net/network-policy-restrictions.md40
-rw-r--r--core/java/android/os/Binder.java14
-rw-r--r--core/java/android/os/DropBoxManager.java2
-rw-r--r--core/java/android/os/FileUtils.java2
-rw-r--r--core/java/android/os/GraphicsEnvironment.java48
-rw-r--r--core/java/android/os/Looper.java196
-rw-r--r--core/java/android/os/Parcelable.java3
-rw-r--r--core/java/android/os/TEST_MAPPING10
-rw-r--r--core/java/android/os/VibrationAttributes.java7
-rw-r--r--[-rwxr-xr-x]core/java/android/provider/Settings.java38
-rw-r--r--core/java/android/security/net/config/NetworkSecurityConfig.java2
-rw-r--r--core/java/android/service/notification/NotificationStats.java5
-rw-r--r--core/java/android/telephony/TelephonyRegistryManager.java1
-rw-r--r--core/java/android/text/format/DateIntervalFormat.java2
-rw-r--r--core/java/android/view/Display.java13
-rw-r--r--core/java/android/view/FocusFinder.java19
-rw-r--r--core/java/android/view/Surface.java6
-rw-r--r--core/java/android/view/SurfaceControl.java284
-rw-r--r--core/java/android/view/View.java5
-rw-r--r--core/java/android/view/ViewRootImpl.java32
-rw-r--r--core/java/android/view/WindowManager.java12
-rw-r--r--core/java/android/view/WindowManagerImpl.java16
-rw-r--r--core/java/android/view/accessibility/IWindowMagnificationConnectionCallback.aidl13
-rw-r--r--core/java/android/view/inputmethod/InlineSuggestionsRequest.java20
-rw-r--r--core/java/android/view/inputmethod/InlineSuggestionsResponse.java38
-rw-r--r--core/java/android/widget/AbsListView.java3
-rw-r--r--core/java/android/widget/Gallery.java3
-rw-r--r--core/java/android/widget/RemoteViewsAdapter.java4
-rwxr-xr-xcore/java/android/widget/SearchView.java2
-rw-r--r--core/java/android/widget/TEST_MAPPING39
-rw-r--r--core/java/android/widget/inline/InlineContentView.java2
-rw-r--r--core/java/android/widget/inline/TEST_MAPPING15
-rw-r--r--core/java/com/android/internal/app/LocalePicker.java64
-rw-r--r--core/java/com/android/internal/infra/AbstractRemoteService.java2
-rw-r--r--core/java/com/android/internal/policy/GestureNavigationSettingsObserver.java7
-rw-r--r--core/jni/android_hardware_input_InputApplicationHandle.cpp23
-rw-r--r--core/jni/android_hardware_input_InputApplicationHandle.h3
-rw-r--r--core/jni/android_hardware_input_InputWindowHandle.cpp4
-rw-r--r--core/jni/android_view_InputEventSender.cpp5
-rw-r--r--core/jni/android_view_MotionEvent.cpp17
-rw-r--r--core/proto/android/app/settings_enums.proto5
-rw-r--r--core/proto/android/providers/settings/global.proto8
-rw-r--r--core/proto/android/server/windowmanagerservice.proto3
-rw-r--r--core/res/res/drawable-car/car_dialog_button_background.xml15
-rw-r--r--core/res/res/values-af/strings.xml3
-rw-r--r--core/res/res/values-am/strings.xml3
-rw-r--r--core/res/res/values-ar/strings.xml3
-rw-r--r--core/res/res/values-as/strings.xml3
-rw-r--r--core/res/res/values-az/strings.xml3
-rw-r--r--core/res/res/values-b+sr+Latn/strings.xml3
-rw-r--r--core/res/res/values-be/strings.xml7
-rw-r--r--core/res/res/values-bg/strings.xml3
-rw-r--r--core/res/res/values-bn/strings.xml3
-rw-r--r--core/res/res/values-bs/strings.xml3
-rw-r--r--core/res/res/values-ca/strings.xml4
-rw-r--r--core/res/res/values-cs/strings.xml3
-rw-r--r--core/res/res/values-da/strings.xml3
-rw-r--r--core/res/res/values-de/strings.xml3
-rw-r--r--core/res/res/values-el/strings.xml3
-rw-r--r--core/res/res/values-en-rAU/strings.xml3
-rw-r--r--core/res/res/values-en-rCA/strings.xml3
-rw-r--r--core/res/res/values-en-rGB/strings.xml3
-rw-r--r--core/res/res/values-en-rIN/strings.xml3
-rw-r--r--core/res/res/values-es-rUS/strings.xml3
-rw-r--r--core/res/res/values-es/strings.xml3
-rw-r--r--core/res/res/values-et/strings.xml3
-rw-r--r--core/res/res/values-eu/strings.xml13
-rw-r--r--core/res/res/values-fa/strings.xml7
-rw-r--r--core/res/res/values-fi/strings.xml3
-rw-r--r--core/res/res/values-fr-rCA/strings.xml3
-rw-r--r--core/res/res/values-fr/strings.xml5
-rw-r--r--core/res/res/values-gl/strings.xml3
-rw-r--r--core/res/res/values-gu/strings.xml3
-rw-r--r--core/res/res/values-hi/strings.xml3
-rw-r--r--core/res/res/values-hr/strings.xml3
-rw-r--r--core/res/res/values-hu/strings.xml3
-rw-r--r--core/res/res/values-hy/strings.xml3
-rw-r--r--core/res/res/values-in/strings.xml3
-rw-r--r--core/res/res/values-is/strings.xml3
-rw-r--r--core/res/res/values-it/strings.xml3
-rw-r--r--core/res/res/values-iw/strings.xml2
-rw-r--r--core/res/res/values-ja/strings.xml3
-rw-r--r--core/res/res/values-ka/strings.xml3
-rw-r--r--core/res/res/values-kk/strings.xml3
-rw-r--r--core/res/res/values-km/strings.xml3
-rw-r--r--core/res/res/values-kn/strings.xml3
-rw-r--r--core/res/res/values-ko/strings.xml3
-rw-r--r--core/res/res/values-ky/strings.xml9
-rw-r--r--core/res/res/values-lo/strings.xml3
-rw-r--r--core/res/res/values-lt/strings.xml3
-rw-r--r--core/res/res/values-lv/strings.xml13
-rw-r--r--core/res/res/values-mcc260/config.xml25
-rw-r--r--core/res/res/values-mcc262/config.xml25
-rw-r--r--core/res/res/values-mk/strings.xml3
-rw-r--r--core/res/res/values-ml/strings.xml3
-rw-r--r--core/res/res/values-mn/strings.xml3
-rw-r--r--core/res/res/values-mr/strings.xml3
-rw-r--r--core/res/res/values-ms/strings.xml3
-rw-r--r--core/res/res/values-my/strings.xml3
-rw-r--r--core/res/res/values-nb/strings.xml3
-rw-r--r--core/res/res/values-ne/strings.xml3
-rw-r--r--core/res/res/values-nl/strings.xml35
-rw-r--r--core/res/res/values-or/strings.xml3
-rw-r--r--core/res/res/values-pa/strings.xml3
-rw-r--r--core/res/res/values-pl/strings.xml3
-rw-r--r--core/res/res/values-pt-rBR/strings.xml3
-rw-r--r--core/res/res/values-pt-rPT/strings.xml3
-rw-r--r--core/res/res/values-pt/strings.xml3
-rw-r--r--core/res/res/values-ro/strings.xml3
-rw-r--r--core/res/res/values-ru/strings.xml3
-rw-r--r--core/res/res/values-si/strings.xml3
-rw-r--r--core/res/res/values-sk/strings.xml3
-rw-r--r--core/res/res/values-sl/strings.xml3
-rw-r--r--core/res/res/values-sq/strings.xml3
-rw-r--r--core/res/res/values-sr/strings.xml3
-rw-r--r--core/res/res/values-sv/strings.xml3
-rw-r--r--core/res/res/values-sw/strings.xml3
-rw-r--r--core/res/res/values-ta/strings.xml3
-rw-r--r--core/res/res/values-te/strings.xml3
-rw-r--r--core/res/res/values-th/strings.xml3
-rw-r--r--core/res/res/values-tl/strings.xml3
-rw-r--r--core/res/res/values-tr/strings.xml3
-rw-r--r--core/res/res/values-uk/strings.xml3
-rw-r--r--core/res/res/values-ur/strings.xml3
-rw-r--r--core/res/res/values-uz/strings.xml5
-rw-r--r--core/res/res/values-vi/strings.xml3
-rw-r--r--core/res/res/values-zh-rCN/strings.xml3
-rw-r--r--core/res/res/values-zh-rHK/strings.xml3
-rw-r--r--core/res/res/values-zh-rTW/strings.xml3
-rw-r--r--core/res/res/values-zu/strings.xml3
-rw-r--r--core/res/res/values/config.xml10
-rw-r--r--core/res/res/values/symbols.xml2
-rw-r--r--core/sysprop/Android.bp21
-rw-r--r--core/sysprop/LocalizationProperties.sysprop24
-rw-r--r--core/sysprop/api/com.android.sysprop.localization-current.txt9
-rw-r--r--core/sysprop/api/com.android.sysprop.localization-latest.txt9
-rw-r--r--core/tests/bugreports/Android.bp6
-rw-r--r--core/tests/bugreports/src/com/android/os/bugreports/tests/BugreportManagerTest.java128
-rw-r--r--core/tests/coretests/src/android/os/VintfObjectTest.java2
-rw-r--r--data/etc/privapp-permissions-platform.xml8
-rw-r--r--data/keyboards/Generic.kl1
-rw-r--r--graphics/java/android/graphics/HardwareRenderer.java31
-rw-r--r--graphics/proto/Android.bp6
-rw-r--r--graphics/proto/updatable_driver.proto (renamed from graphics/proto/game_driver.proto)12
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/sidecar/SettingsSidecarImpl.java6
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java30
-rw-r--r--libs/androidfw/Android.bp2
-rw-r--r--libs/androidfw/libandroidfw_blocklist.txt (renamed from libs/androidfw/libandroidfw_blacklist.txt)0
-rw-r--r--libs/hwui/AutoBackendTextureRelease.cpp10
-rw-r--r--libs/hwui/AutoBackendTextureRelease.h9
-rw-r--r--libs/hwui/ColorMode.h34
-rw-r--r--libs/hwui/DeferredLayerUpdater.cpp2
-rw-r--r--libs/hwui/DeferredLayerUpdater.h2
-rw-r--r--libs/hwui/HardwareBitmapUploader.cpp4
-rw-r--r--libs/hwui/Readback.cpp2
-rw-r--r--libs/hwui/jni/android_graphics_HardwareRenderer.cpp13
-rw-r--r--libs/hwui/pipeline/skia/GLFunctorDrawable.cpp2
-rw-r--r--libs/hwui/pipeline/skia/LayerDrawable.cpp10
-rw-r--r--libs/hwui/pipeline/skia/LayerDrawable.h8
-rw-r--r--libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp2
-rw-r--r--libs/hwui/pipeline/skia/SkiaPipeline.cpp26
-rw-r--r--libs/hwui/pipeline/skia/SkiaPipeline.h4
-rw-r--r--libs/hwui/renderthread/CanvasContext.cpp11
-rw-r--r--libs/hwui/renderthread/CanvasContext.h4
-rw-r--r--libs/hwui/renderthread/EglManager.cpp105
-rw-r--r--libs/hwui/renderthread/EglManager.h4
-rw-r--r--libs/hwui/renderthread/IRenderPipeline.h11
-rw-r--r--libs/hwui/renderthread/RenderProxy.cpp4
-rw-r--r--libs/hwui/renderthread/RenderProxy.h3
-rw-r--r--libs/hwui/renderthread/RenderThread.cpp15
-rw-r--r--libs/hwui/renderthread/RenderThread.h8
-rw-r--r--libs/hwui/renderthread/VulkanManager.cpp16
-rw-r--r--libs/hwui/renderthread/VulkanManager.h12
-rw-r--r--libs/hwui/tests/unit/CacheManagerTests.cpp4
-rw-r--r--libs/hwui/utils/Color.cpp22
-rw-r--r--libs/hwui/utils/Color.h1
-rwxr-xr-xmedia/java/android/media/AudioManager.java4
-rw-r--r--media/java/android/media/AudioRecord.java5
-rw-r--r--media/java/android/media/ExifInterface.java350
-rw-r--r--media/java/android/media/audiopolicy/AudioPolicy.java11
-rw-r--r--media/java/android/media/audiopolicy/AudioPolicyConfig.java6
-rw-r--r--media/jni/android_media_tv_Tuner.cpp65
-rw-r--r--non-updatable-api/current.txt27
-rw-r--r--non-updatable-api/module-lib-current.txt13
-rw-r--r--packages/BackupEncryption/src/com/android/server/backup/encryption/chunking/cdc/Hkdf.java10
-rw-r--r--packages/CarSystemUI/res/values/config.xml25
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/CarSystemUIFactory.java2
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java10
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/CarSystemUIRootComponent.java9
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBar.java125
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBarController.java12
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBarView.java28
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/navigationbar/SystemBarConfigs.java380
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/userswitcher/UserGridRecyclerView.java10
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/wm/DisplaySystemBarsController.java38
-rw-r--r--packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationBarControllerTest.java3
-rw-r--r--packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationBarTest.java2
-rw-r--r--packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/SystemBarConfigsTest.java162
-rw-r--r--packages/CarSystemUI/tests/src/com/android/systemui/wm/DisplaySystemBarsControllerTest.java4
-rw-r--r--packages/DynamicSystemInstallationService/tests/res/values/strings.xml2
-rw-r--r--packages/DynamicSystemInstallationService/tests/src/com/android/dynsystem/KeyRevocationListTest.java46
-rw-r--r--packages/SettingsLib/res/values-be/strings.xml4
-rw-r--r--packages/SettingsLib/res/values/strings.xml3
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java12
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/WriteFallbackSettingsFilesJobService.java22
-rw-r--r--packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java8
-rw-r--r--packages/Shell/AndroidManifest.xml8
-rw-r--r--packages/SimAppDialog/Android.bp1
-rw-r--r--packages/SystemUI/docs/dagger.md91
-rw-r--r--packages/SystemUI/res/drawable-hdpi/one_handed_tutorial.pngbin0 -> 1766 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/one_handed_tutorial.pngbin0 -> 1054 bytes
-rw-r--r--packages/SystemUI/res/drawable-xhdpi/one_handed_tutorial.pngbin0 -> 2215 bytes
-rw-r--r--packages/SystemUI/res/drawable-xxhdpi/one_handed_tutorial.pngbin0 -> 3649 bytes
-rw-r--r--packages/SystemUI/res/drawable-xxxhdpi/one_handed_tutorial.pngbin0 -> 5029 bytes
-rw-r--r--packages/SystemUI/res/values-af/strings.xml7
-rw-r--r--packages/SystemUI/res/values-am/strings.xml7
-rw-r--r--packages/SystemUI/res/values-ar/strings.xml7
-rw-r--r--packages/SystemUI/res/values-as/strings.xml7
-rw-r--r--packages/SystemUI/res/values-az/strings.xml7
-rw-r--r--packages/SystemUI/res/values-b+sr+Latn/strings.xml7
-rw-r--r--packages/SystemUI/res/values-be/strings.xml9
-rw-r--r--packages/SystemUI/res/values-bg/strings.xml7
-rw-r--r--packages/SystemUI/res/values-bn/strings.xml7
-rw-r--r--packages/SystemUI/res/values-bs/strings.xml7
-rw-r--r--packages/SystemUI/res/values-ca/strings.xml7
-rw-r--r--packages/SystemUI/res/values-cs/strings.xml7
-rw-r--r--packages/SystemUI/res/values-da/strings.xml7
-rw-r--r--packages/SystemUI/res/values-de/strings.xml7
-rw-r--r--packages/SystemUI/res/values-el/strings.xml7
-rw-r--r--packages/SystemUI/res/values-en-rAU/strings.xml7
-rw-r--r--packages/SystemUI/res/values-en-rCA/strings.xml7
-rw-r--r--packages/SystemUI/res/values-en-rGB/strings.xml7
-rw-r--r--packages/SystemUI/res/values-en-rIN/strings.xml7
-rw-r--r--packages/SystemUI/res/values-en-rXC/strings.xml7
-rw-r--r--packages/SystemUI/res/values-es-rUS/strings.xml7
-rw-r--r--packages/SystemUI/res/values-es/strings.xml7
-rw-r--r--packages/SystemUI/res/values-et/strings.xml7
-rw-r--r--packages/SystemUI/res/values-eu/strings.xml7
-rw-r--r--packages/SystemUI/res/values-fa/strings.xml7
-rw-r--r--packages/SystemUI/res/values-fi/strings.xml7
-rw-r--r--packages/SystemUI/res/values-fr-rCA/strings.xml7
-rw-r--r--packages/SystemUI/res/values-fr/strings.xml13
-rw-r--r--packages/SystemUI/res/values-gl/strings.xml7
-rw-r--r--packages/SystemUI/res/values-gu/strings.xml7
-rw-r--r--packages/SystemUI/res/values-hi/strings.xml7
-rw-r--r--packages/SystemUI/res/values-hr/strings.xml7
-rw-r--r--packages/SystemUI/res/values-hu/strings.xml7
-rw-r--r--packages/SystemUI/res/values-hy/strings.xml9
-rw-r--r--packages/SystemUI/res/values-in/strings.xml7
-rw-r--r--packages/SystemUI/res/values-is/strings.xml7
-rw-r--r--packages/SystemUI/res/values-it/strings.xml7
-rw-r--r--packages/SystemUI/res/values-iw/strings.xml7
-rw-r--r--packages/SystemUI/res/values-ja/strings.xml7
-rw-r--r--packages/SystemUI/res/values-ka/strings.xml7
-rw-r--r--packages/SystemUI/res/values-kk/strings.xml7
-rw-r--r--packages/SystemUI/res/values-km/strings.xml7
-rw-r--r--packages/SystemUI/res/values-kn/strings.xml7
-rw-r--r--packages/SystemUI/res/values-ko/strings.xml7
-rw-r--r--packages/SystemUI/res/values-ky/strings.xml7
-rw-r--r--packages/SystemUI/res/values-lo/strings.xml7
-rw-r--r--packages/SystemUI/res/values-lt/strings.xml7
-rw-r--r--packages/SystemUI/res/values-lv/strings.xml29
-rw-r--r--packages/SystemUI/res/values-mk/strings.xml7
-rw-r--r--packages/SystemUI/res/values-ml/strings.xml7
-rw-r--r--packages/SystemUI/res/values-mn/strings.xml7
-rw-r--r--packages/SystemUI/res/values-mr/strings.xml7
-rw-r--r--packages/SystemUI/res/values-ms/strings.xml7
-rw-r--r--packages/SystemUI/res/values-my/strings.xml7
-rw-r--r--packages/SystemUI/res/values-nb/strings.xml7
-rw-r--r--packages/SystemUI/res/values-ne/strings.xml7
-rw-r--r--packages/SystemUI/res/values-nl/strings.xml31
-rw-r--r--packages/SystemUI/res/values-or/strings.xml7
-rw-r--r--packages/SystemUI/res/values-pa/strings.xml7
-rw-r--r--packages/SystemUI/res/values-pl/strings.xml7
-rw-r--r--packages/SystemUI/res/values-pt-rBR/strings.xml7
-rw-r--r--packages/SystemUI/res/values-pt-rPT/strings.xml9
-rw-r--r--packages/SystemUI/res/values-pt/strings.xml7
-rw-r--r--packages/SystemUI/res/values-ro/strings.xml7
-rw-r--r--packages/SystemUI/res/values-ru/strings.xml7
-rw-r--r--packages/SystemUI/res/values-si/strings.xml7
-rw-r--r--packages/SystemUI/res/values-sk/strings.xml7
-rw-r--r--packages/SystemUI/res/values-sl/strings.xml7
-rw-r--r--packages/SystemUI/res/values-sq/strings.xml7
-rw-r--r--packages/SystemUI/res/values-sr/strings.xml7
-rw-r--r--packages/SystemUI/res/values-sv/strings.xml7
-rw-r--r--packages/SystemUI/res/values-sw/strings.xml7
-rw-r--r--packages/SystemUI/res/values-ta/strings.xml7
-rw-r--r--packages/SystemUI/res/values-te/strings.xml7
-rw-r--r--packages/SystemUI/res/values-th/strings.xml7
-rw-r--r--packages/SystemUI/res/values-tl/strings.xml7
-rw-r--r--packages/SystemUI/res/values-tr/strings.xml7
-rw-r--r--packages/SystemUI/res/values-uk/strings.xml7
-rw-r--r--packages/SystemUI/res/values-ur/strings.xml7
-rw-r--r--packages/SystemUI/res/values-uz/strings.xml7
-rw-r--r--packages/SystemUI/res/values-vi/strings.xml7
-rw-r--r--packages/SystemUI/res/values-zh-rCN/strings.xml7
-rw-r--r--packages/SystemUI/res/values-zh-rHK/strings.xml7
-rw-r--r--packages/SystemUI/res/values-zh-rTW/strings.xml7
-rw-r--r--packages/SystemUI/res/values-zu/strings.xml7
-rw-r--r--packages/SystemUI/res/values/config.xml6
-rw-r--r--packages/SystemUI/res/values/strings.xml5
-rw-r--r--packages/SystemUI/res/xml/one_handed_tutorial.xml67
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java116
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java119
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java2
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardSimPukView.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/BatteryMeterView.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/Dependency.java17
-rw-r--r--packages/SystemUI/src/com/android/systemui/SystemUIFactory.java34
-rw-r--r--packages/SystemUI/src/com/android/systemui/accessibility/DisplayIdIndexSupplier.java23
-rw-r--r--packages/SystemUI/src/com/android/systemui/accessibility/MagnificationModeSwitch.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/accessibility/ModeSwitchesController.java22
-rw-r--r--packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java23
-rw-r--r--packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java42
-rw-r--r--packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnifierCallback.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java61
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/SystemUIRootComponent.java17
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt1
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/SeekBarObserver.kt12
-rw-r--r--packages/SystemUI/src/com/android/systemui/onehanded/OneHandedAnimationCallback.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/onehanded/OneHandedAnimationController.java38
-rw-r--r--packages/SystemUI/src/com/android/systemui/onehanded/OneHandedDisplayAreaOrganizer.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/onehanded/OneHandedGestureHandler.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/onehanded/OneHandedManagerImpl.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/onehanded/OneHandedTouchHandler.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/onehanded/OneHandedTutorialHandler.java161
-rw-r--r--packages/SystemUI/src/com/android/systemui/onehanded/OneHandedUI.java23
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/Recents.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java528
-rw-r--r--packages/SystemUI/src/com/android/systemui/stackdivider/DividerController.java516
-rw-r--r--packages/SystemUI/src/com/android/systemui/stackdivider/DividerHandleView.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/stackdivider/DividerImeController.java19
-rw-r--r--packages/SystemUI/src/com/android/systemui/stackdivider/DividerModule.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/stackdivider/DividerState.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java48
-rw-r--r--packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivityController.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreenTaskOrganizer.java30
-rw-r--r--packages/SystemUI/src/com/android/systemui/stackdivider/SyncTransactionQueue.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java106
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/GroupEntry.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListDumper.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListEntry.java27
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifInflaterImpl.java32
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifViewManager.kt204
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java20
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java20
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/SimpleNotificationListContainer.kt43
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/BubbleCoordinator.java28
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java87
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorLogger.kt17
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinder.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/OnDismissCallbackImpl.java83
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/init/NotifPipelineInitializer.java18
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/OnDismissCallbackImpl.java81
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/ShadeListBuilderLogger.kt15
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/Pluggable.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifViewBarn.kt (renamed from packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifViewBarn.kt)22
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifViewManager.kt240
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifViewManagerLogger.kt72
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java38
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java48
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/OnDismissCallback.java35
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/dagger/ExpandableNotificationRowComponent.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationListContainer.java22
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationListItem.java69
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java71
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardLiftController.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenLockIconController.java17
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java20
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java18
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java57
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java46
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java26
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/DeadZone.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/tuner/BatteryPreference.java18
-rw-r--r--packages/SystemUI/src/com/android/systemui/tuner/ClockPreference.java18
-rw-r--r--packages/SystemUI/src/com/android/systemui/tuner/StatusBarSwitch.java28
-rw-r--r--packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java20
-rw-r--r--packages/SystemUI/src/com/android/systemui/tv/TvSystemUIRootComponent.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/wmshell/WindowManagerShellModule.java9
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java162
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java86
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/DependencyTest.java5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/SysuiBaseFragmentTest.java5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/TestableDependency.java14
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationModeSwitchTest.java11
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/accessibility/ModeSwitchesControllerTest.java30
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java22
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationTest.java11
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java16
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java13
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/SeekBarObserverTest.kt6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedAnimationControllerTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedDisplayAreaOrganizerTest.java6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedGestureHandlerTest.java5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedManagerImplTest.java5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedTouchHandlerTest.java5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedTutorialHandlerTest.java80
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedUITest.java45
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java17
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java12
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/EntryUtil.kt (renamed from packages/SystemUI/src/com/android/systemui/statusbar/notification/row/dagger/DismissRunnable.java)26
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/GroupEntryBuilder.java82
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/GroupEntryHelper.java42
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/HighPriorityProviderTest.java31
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryBuilder.java54
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.java28
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorTest.java175
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java85
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java16
-rw-r--r--packages/Tethering/Android.bp1
-rw-r--r--packages/Tethering/AndroidManifest.xml2
-rw-r--r--packages/Tethering/proguard.flags2
-rw-r--r--packages/Tethering/src/android/net/ip/IpServer.java26
-rw-r--r--packages/Tethering/src/android/net/util/TetheringMessageBase.java2
-rw-r--r--packages/Tethering/src/com/android/networkstack/tethering/EntitlementManager.java6
-rw-r--r--packages/Tethering/src/com/android/networkstack/tethering/Tethering.java80
-rw-r--r--packages/Tethering/src/com/android/networkstack/tethering/UpstreamNetworkMonitor.java2
-rw-r--r--packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java54
-rw-r--r--packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java28
-rw-r--r--services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java17
-rw-r--r--services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java2
-rw-r--r--services/autofill/java/com/android/server/autofill/RemoteFillService.java3
-rw-r--r--services/autofill/java/com/android/server/autofill/Session.java8
-rw-r--r--services/backup/java/com/android/server/backup/DataChangedJournal.java41
-rw-r--r--services/backup/java/com/android/server/backup/UserBackupManagerService.java38
-rw-r--r--services/backup/java/com/android/server/backup/fullbackup/PerformAdbBackupTask.java46
-rw-r--r--services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java2
-rw-r--r--services/backup/java/com/android/server/backup/restore/PerformAdbRestoreTask.java39
-rw-r--r--services/backup/java/com/android/server/backup/utils/BackupEligibilityRules.java10
-rw-r--r--services/core/Android.bp1
-rw-r--r--services/core/java/com/android/server/BinderCallsStatsService.java24
-rw-r--r--services/core/java/com/android/server/GestureLauncherService.java43
-rw-r--r--services/core/java/com/android/server/ServiceWatcher.java54
-rw-r--r--services/core/java/com/android/server/TelephonyRegistry.java28
-rw-r--r--services/core/java/com/android/server/am/ActiveServices.java15
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerDebugConfig.java1
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java1728
-rw-r--r--services/core/java/com/android/server/am/BroadcastQueue.java2
-rw-r--r--services/core/java/com/android/server/am/BroadcastRecord.java14
-rw-r--r--services/core/java/com/android/server/am/CachedAppOptimizer.java16
-rw-r--r--services/core/java/com/android/server/am/ContentProviderHelper.java1679
-rw-r--r--services/core/java/com/android/server/am/CoreSettingsObserver.java6
-rw-r--r--services/core/java/com/android/server/am/OWNERS2
-rw-r--r--services/core/java/com/android/server/am/PendingIntentRecord.java15
-rw-r--r--services/core/java/com/android/server/am/ProcessList.java17
-rw-r--r--services/core/java/com/android/server/am/ProcessRecord.java29
-rw-r--r--services/core/java/com/android/server/am/ServiceRecord.java8
-rw-r--r--services/core/java/com/android/server/am/UserController.java27
-rw-r--r--services/core/java/com/android/server/appop/AppOpsService.java73
-rw-r--r--services/core/java/com/android/server/appop/TEST_MAPPING3
-rw-r--r--services/core/java/com/android/server/attention/AttentionManagerService.java12
-rw-r--r--services/core/java/com/android/server/connectivity/PermissionMonitor.java162
-rw-r--r--services/core/java/com/android/server/display/ColorFade.java25
-rw-r--r--services/core/java/com/android/server/display/color/ColorDisplayService.java30
-rw-r--r--services/core/java/com/android/server/display/color/ColorDisplayShellCommand.java119
-rw-r--r--services/core/java/com/android/server/gpu/GpuService.java78
-rw-r--r--services/core/java/com/android/server/hdmi/ActiveSourceAction.java10
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java30
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiControlService.java11
-rw-r--r--services/core/java/com/android/server/location/HardwareActivityRecognitionProxy.java3
-rw-r--r--services/core/java/com/android/server/location/LocationManagerService.java9
-rw-r--r--services/core/java/com/android/server/location/LocationProviderProxy.java27
-rw-r--r--services/core/java/com/android/server/location/geofence/GeofenceProxy.java2
-rw-r--r--services/core/java/com/android/server/media/MediaButtonReceiverHolder.java4
-rw-r--r--services/core/java/com/android/server/media/MediaResourceMonitorService.java3
-rw-r--r--services/core/java/com/android/server/media/MediaSessionService.java55
-rw-r--r--services/core/java/com/android/server/net/NetworkStatsCollection.java46
-rw-r--r--services/core/java/com/android/server/net/NetworkStatsFactory.java4
-rw-r--r--services/core/java/com/android/server/net/NetworkStatsRecorder.java2
-rwxr-xr-xservices/core/java/com/android/server/notification/NotificationManagerService.java55
-rw-r--r--services/core/java/com/android/server/notification/RankingReconsideration.java2
-rw-r--r--services/core/java/com/android/server/om/OverlayReferenceMapper.java16
-rw-r--r--services/core/java/com/android/server/os/TEST_MAPPING10
-rw-r--r--services/core/java/com/android/server/pm/BackgroundDexOptService.java6
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerSession.java300
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java495
-rw-r--r--services/core/java/com/android/server/pm/PackageVerificationState.java8
-rw-r--r--services/core/java/com/android/server/pm/Settings.java12
-rw-r--r--services/core/java/com/android/server/pm/StagingManager.java1
-rw-r--r--services/core/java/com/android/server/pm/UserManagerService.java6
-rw-r--r--services/core/java/com/android/server/pm/UserTypeDetails.java10
-rw-r--r--services/core/java/com/android/server/pm/permission/PermissionManagerService.java518
-rw-r--r--services/core/java/com/android/server/pm/permission/PermissionSettings.java12
-rw-r--r--services/core/java/com/android/server/pm/permission/TEST_MAPPING17
-rw-r--r--services/core/java/com/android/server/power/PowerManagerService.java8
-rw-r--r--services/core/java/com/android/server/power/ShutdownCheckPoints.java50
-rw-r--r--services/core/java/com/android/server/power/ShutdownThread.java6
-rw-r--r--services/core/java/com/android/server/statusbar/StatusBarManagerService.java13
-rw-r--r--services/core/java/com/android/server/storage/StorageUserConnection.java50
-rw-r--r--services/core/java/com/android/server/twilight/TwilightService.java3
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java16
-rw-r--r--services/core/java/com/android/server/wm/ActivityStarter.java14
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java8
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskManagerService.java29
-rw-r--r--services/core/java/com/android/server/wm/AppTransitionController.java4
-rw-r--r--services/core/java/com/android/server/wm/BackgroundActivityStartCallback.java39
-rw-r--r--services/core/java/com/android/server/wm/ConfigurationContainer.java83
-rw-r--r--services/core/java/com/android/server/wm/DisplayArea.java11
-rw-r--r--services/core/java/com/android/server/wm/DisplayAreaPolicy.java17
-rw-r--r--services/core/java/com/android/server/wm/DisplayAreaPolicyBuilder.java103
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java31
-rw-r--r--services/core/java/com/android/server/wm/DisplayPolicy.java29
-rw-r--r--services/core/java/com/android/server/wm/InputConsumerImpl.java1
-rw-r--r--services/core/java/com/android/server/wm/InputMonitor.java32
-rw-r--r--services/core/java/com/android/server/wm/RecentsAnimationController.java8
-rw-r--r--services/core/java/com/android/server/wm/Task.java81
-rw-r--r--services/core/java/com/android/server/wm/TaskDisplayArea.java148
-rw-r--r--services/core/java/com/android/server/wm/WindowAnimator.java1
-rw-r--r--services/core/java/com/android/server/wm/WindowContainer.java33
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java22
-rw-r--r--services/core/java/com/android/server/wm/WindowOrganizerController.java50
-rw-r--r--services/core/java/com/android/server/wm/WindowProcessController.java85
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java16
-rw-r--r--services/core/java/com/android/server/wm/WindowStateAnimator.java251
-rw-r--r--services/core/jni/com_android_server_fingerprint_FingerprintService.cpp2
-rw-r--r--services/core/jni/com_android_server_input_InputManagerService.cpp20
-rw-r--r--services/core/jni/stats/PowerStatsPuller.cpp15
-rw-r--r--services/core/jni/stats/SubsystemSleepStatePuller.cpp56
-rw-r--r--services/java/com/android/server/SystemServer.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/GestureLauncherServiceTest.java19
-rw-r--r--services/tests/servicestests/src/com/android/server/am/BroadcastRecordTest.java3
-rw-r--r--services/tests/servicestests/src/com/android/server/attention/AttentionManagerServiceTest.java6
-rw-r--r--services/tests/servicestests/src/com/android/server/backup/DataChangedJournalTest.java26
-rw-r--r--services/tests/servicestests/src/com/android/server/hdmi/ActiveSourceActionTest.java20
-rw-r--r--services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java118
-rw-r--r--services/tests/servicestests/src/com/android/server/job/JobSetTest.java4
-rw-r--r--services/tests/servicestests/src/com/android/server/om/OverlayReferenceMapperTests.kt6
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java39
-rw-r--r--services/tests/servicestests/src/com/android/server/power/ShutdownCheckPointsTest.java132
-rwxr-xr-xservices/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java24
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/NotificationShellCmdTest.java22
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java14
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java22
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java5
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java74
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ConfigurationContainerTests.java55
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayAreaTest.java40
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java30
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java4
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java5
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java7
-rw-r--r--services/usb/java/com/android/server/usb/UsbAlsaManager.java32
-rw-r--r--services/usb/java/com/android/server/usb/UsbDeviceManager.java28
-rw-r--r--services/usb/java/com/android/server/usb/UsbHostManager.java40
-rw-r--r--services/usb/java/com/android/server/usb/UsbPortManager.java2
-rw-r--r--services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java2
-rw-r--r--telecomm/TEST_MAPPING8
-rwxr-xr-xtelecomm/java/android/telecom/Call.java18
-rw-r--r--telecomm/java/android/telecom/Conference.java10
-rwxr-xr-xtelecomm/java/android/telecom/Connection.java14
-rwxr-xr-xtelecomm/java/android/telecom/ConnectionService.java17
-rwxr-xr-xtelecomm/java/android/telecom/InCallAdapter.java4
-rw-r--r--telecomm/java/android/telecom/TelecomManager.java23
-rw-r--r--telecomm/java/com/android/internal/telecom/ITelecomService.aidl2
-rw-r--r--telephony/common/android/telephony/LocationAccessPolicy.java13
-rw-r--r--telephony/common/com/android/internal/telephony/TelephonyPermissions.java14
-rw-r--r--telephony/common/com/google/android/mms/pdu/PduComposer.java2
-rwxr-xr-xtelephony/common/com/google/android/mms/pdu/PduPersister.java10
-rwxr-xr-xtelephony/java/android/telephony/CarrierConfigManager.java7
-rw-r--r--telephony/java/android/telephony/CellLocation.java17
-rw-r--r--telephony/java/android/telephony/CellSignalStrengthNr.java2
-rw-r--r--telephony/java/android/telephony/MbmsDownloadSession.java2
-rw-r--r--telephony/java/android/telephony/PreciseDataConnectionState.java182
-rw-r--r--telephony/java/android/telephony/SmsManager.java139
-rw-r--r--telephony/java/android/telephony/SubscriptionManager.java7
-rw-r--r--telephony/java/android/telephony/TelephonyFrameworkInitializer.java6
-rw-r--r--telephony/java/android/telephony/VisualVoicemailSmsFilterSettings.java6
-rw-r--r--telephony/java/android/telephony/data/ApnSetting.java8
-rwxr-xr-xtelephony/java/android/telephony/ims/ImsCallSession.java2
-rw-r--r--telephony/java/android/telephony/ims/ImsReasonInfo.java197
-rw-r--r--telephony/java/android/telephony/ims/compat/stub/ImsConfigImplBase.java12
-rw-r--r--telephony/java/android/telephony/ims/stub/ImsCallSessionImplBase.java4
-rw-r--r--telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java4
-rw-r--r--telephony/java/android/telephony/mbms/MbmsTempFileProvider.java2
-rw-r--r--telephony/java/com/android/ims/internal/IImsCallSession.aidl4
-rw-r--r--telephony/java/com/android/ims/internal/IImsConfig.aidl8
-rw-r--r--telephony/java/com/android/internal/telephony/cdma/SmsMessage.java4
-rw-r--r--telephony/java/com/android/internal/telephony/gsm/SmsMessage.java4
-rw-r--r--tests/BlobStoreTestUtils/src/com/android/utils/blob/FakeBlobData.java (renamed from tests/BlobStoreTestUtils/src/com/android/utils/blob/DummyBlobData.java)8
-rw-r--r--tests/FlickerTests/Android.bp1
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt153
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/CommonTransitions.kt446
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/DebugTest.kt190
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/FlickerTestBase.kt156
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/NonRotationTestBase.kt44
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/RotationTestBase.kt79
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/helpers/FlickerAppHelper.kt7
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppHelper.kt19
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt13
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt83
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt84
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt99
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt129
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ime/ImeAssertions.kt102
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt92
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt103
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTestBase.kt64
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt109
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/pip/PipTestBase.kt56
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/pip/PipToAppTest.kt92
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/pip/PipToHomeTest.kt96
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt123
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt161
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/OpenAppToSplitScreenTest.kt104
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/ResizeSplitScreenTest.kt266
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/SplitScreenToLauncherTest.kt135
-rw-r--r--tests/LocalizationTest/Android.bp41
-rw-r--r--tests/LocalizationTest/AndroidManifest.xml (renamed from core/res/res/drawable-car-night/car_dialog_button_background.xml)29
-rw-r--r--tests/LocalizationTest/AndroidTest.xml34
-rw-r--r--tests/LocalizationTest/java/com/android/internal/app/LocalizationTest.kt118
-rw-r--r--tests/net/common/java/android/net/NetworkProviderTest.kt14
-rw-r--r--tests/net/java/com/android/server/ConnectivityServiceTest.java2
-rw-r--r--tests/net/java/com/android/server/NetIdManagerTest.kt2
-rw-r--r--tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java208
-rw-r--r--tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java29
-rw-r--r--tests/utils/StubIME/Android.bp (renamed from tests/utils/DummyIME/Android.bp)2
-rw-r--r--tests/utils/StubIME/AndroidManifest.xml (renamed from tests/utils/DummyIME/AndroidManifest.xml)12
-rw-r--r--tests/utils/StubIME/res/xml/method.xml (renamed from tests/utils/DummyIME/res/xml/method.xml)4
-rw-r--r--tests/utils/StubIME/src/com/android/testing/stubime/ImePreferences.java (renamed from tests/utils/DummyIME/src/com/android/testing/dummyime/ImePreferences.java)4
-rw-r--r--tests/utils/StubIME/src/com/android/testing/stubime/StubIme.java (renamed from tests/utils/DummyIME/src/com/android/testing/dummyime/DummyIme.java)6
-rwxr-xr-xtools/hiddenapi/generate_hiddenapi_lists.py127
-rwxr-xr-xtools/hiddenapi/generate_hiddenapi_lists_test.py39
-rw-r--r--tools/stats_log_api_gen/Android.bp20
-rw-r--r--tools/stats_log_api_gen/Collation.cpp14
-rw-r--r--tools/stats_log_api_gen/Collation.h10
-rw-r--r--tools/stats_log_api_gen/java_writer.cpp28
-rw-r--r--tools/stats_log_api_gen/java_writer.h7
-rw-r--r--tools/stats_log_api_gen/java_writer_q.cpp4
-rw-r--r--tools/stats_log_api_gen/java_writer_q.h7
-rw-r--r--tools/stats_log_api_gen/main.cpp21
-rw-r--r--tools/stats_log_api_gen/native_writer.cpp204
-rw-r--r--tools/stats_log_api_gen/native_writer.h7
-rw-r--r--tools/stats_log_api_gen/test_collation.cpp7
-rw-r--r--tools/stats_log_api_gen/utils.cpp53
-rw-r--r--tools/stats_log_api_gen/utils.h22
-rw-r--r--wifi/java/android/net/wifi/WifiNetworkSuggestion.java3
-rw-r--r--wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java11
-rw-r--r--wifi/tests/src/android/net/wifi/aware/TlvBufferUtilsTest.java30
-rw-r--r--wifi/tests/src/android/net/wifi/aware/WifiAwareAgentNetworkSpecifierTest.java24
-rw-r--r--wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java2
740 files changed, 15517 insertions, 9350 deletions
diff --git a/Android.bp b/Android.bp
index e19fe640d32b..0780f88df7c6 100644
--- a/Android.bp
+++ b/Android.bp
@@ -433,7 +433,7 @@ java_library {
"apex_aidl_interface-java",
"suspend_control_aidl_interface-java",
"framework-protos",
- "game-driver-protos",
+ "updatable-driver-protos",
"android.hidl.base-V1.0-java",
"android.hardware.cas-V1.0-java",
"android.hardware.cas-V1.1-java",
@@ -467,6 +467,7 @@ java_library {
"com.android.sysprop.apex",
"com.android.sysprop.init",
+ "com.android.sysprop.localization",
"PlatformProperties",
],
sdk_version: "core_platform",
diff --git a/apct-tests/perftests/autofill/Android.bp b/apct-tests/perftests/autofill/Android.bp
index 65c28fb4d0a7..9ac8c87d3de0 100644
--- a/apct-tests/perftests/autofill/Android.bp
+++ b/apct-tests/perftests/autofill/Android.bp
@@ -20,6 +20,7 @@ android_test {
"androidx.test.rules",
"androidx.annotation_annotation",
"apct-perftests-utils",
+ "collector-device-lib-platform",
],
platform_apis: true,
test_suites: ["device-tests"],
diff --git a/apct-tests/perftests/autofill/AndroidManifest.xml b/apct-tests/perftests/autofill/AndroidManifest.xml
index 57595a213d20..51f6a76b2782 100644
--- a/apct-tests/perftests/autofill/AndroidManifest.xml
+++ b/apct-tests/perftests/autofill/AndroidManifest.xml
@@ -16,6 +16,11 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.perftests.autofill">
+ <uses-sdk android:targetSdkVersion="28" />
+
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+ <uses-permission android:name="android.permission.REAL_GET_TASKS" />
+
<application>
<uses-library android:name="android.test.runner" />
<activity android:name="android.perftests.utils.PerfTestActivity"
diff --git a/apct-tests/perftests/autofill/src/android/view/autofill/AbstractAutofillPerfTestCase.java b/apct-tests/perftests/autofill/src/android/view/autofill/AbstractAutofillPerfTestCase.java
index 48ce8ab2fce5..8f8fc29ee3c4 100644
--- a/apct-tests/perftests/autofill/src/android/view/autofill/AbstractAutofillPerfTestCase.java
+++ b/apct-tests/perftests/autofill/src/android/view/autofill/AbstractAutofillPerfTestCase.java
@@ -26,7 +26,6 @@ import android.perftests.utils.SettingsStateKeeperRule;
import android.provider.Settings;
import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.LargeTest;
import androidx.test.rule.ActivityTestRule;
import org.junit.After;
@@ -37,7 +36,6 @@ import org.junit.Rule;
/**
* Base class for all autofill tests.
*/
-@LargeTest
public abstract class AbstractAutofillPerfTestCase {
@ClassRule
diff --git a/apct-tests/perftests/autofill/src/android/view/autofill/LoginTest.java b/apct-tests/perftests/autofill/src/android/view/autofill/LoginTest.java
index fb5ea80e6ed1..5f52dc782422 100644
--- a/apct-tests/perftests/autofill/src/android/view/autofill/LoginTest.java
+++ b/apct-tests/perftests/autofill/src/android/view/autofill/LoginTest.java
@@ -24,10 +24,14 @@ import android.perftests.utils.PerfTestActivity;
import android.view.View;
import android.widget.EditText;
+import androidx.test.filters.LargeTest;
+
import com.android.perftests.autofill.R;
+import org.junit.Ignore;
import org.junit.Test;
+@LargeTest
public class LoginTest extends AbstractAutofillPerfTestCase {
private EditText mUsername;
@@ -90,6 +94,8 @@ public class LoginTest extends AbstractAutofillPerfTestCase {
/**
* Now the service returns autofill data, for both username and password.
*/
+ // TODO(b/162216576): fix fail test and re-enable it
+ @Ignore
@Test
public void testFocus_autofillBothFields() throws Throwable {
MyAutofillService.newCannedResponse()
@@ -142,6 +148,8 @@ public class LoginTest extends AbstractAutofillPerfTestCase {
/**
* Now the service returns autofill data, but just for username.
*/
+ // TODO(b/162216576): fix fail test and re-enable it
+ @Ignore
@Test
public void testFocus_autofillUsernameOnly() throws Throwable {
// Must set ignored ids so focus on password does not trigger new requests
@@ -258,6 +266,8 @@ public class LoginTest extends AbstractAutofillPerfTestCase {
});
}
+ // TODO(b/162216576): fix fail test and re-enable it
+ @Ignore
@Test
public void testCallbacks() throws Throwable {
MyAutofillService.newCannedResponse()
diff --git a/apct-tests/perftests/blobstore/src/com/android/perftests/blob/BlobStorePerfTests.java b/apct-tests/perftests/blobstore/src/com/android/perftests/blob/BlobStorePerfTests.java
index 23f025b0a759..5a04ba303b66 100644
--- a/apct-tests/perftests/blobstore/src/com/android/perftests/blob/BlobStorePerfTests.java
+++ b/apct-tests/perftests/blobstore/src/com/android/perftests/blob/BlobStorePerfTests.java
@@ -27,7 +27,7 @@ import android.support.test.uiautomator.UiDevice;
import androidx.test.filters.LargeTest;
import androidx.test.platform.app.InstrumentationRegistry;
-import com.android.utils.blob.DummyBlobData;
+import com.android.utils.blob.FakeBlobData;
import org.junit.After;
import org.junit.Before;
@@ -96,7 +96,7 @@ public class BlobStorePerfTests {
mAtraceUtils.startTrace(ATRACE_CATEGORY_SYSTEM_SERVER);
try {
final List<Long> durations = new ArrayList<>();
- final DummyBlobData blobData = prepareDataBlob(fileSizeInMb);
+ final FakeBlobData blobData = prepareDataBlob(fileSizeInMb);
final TraceMarkParser parser = new TraceMarkParser(
line -> line.name.startsWith(ATRACE_COMPUTE_DIGEST_PREFIX));
while (mState.keepRunning(durations)) {
@@ -120,15 +120,15 @@ public class BlobStorePerfTests {
});
}
- private DummyBlobData prepareDataBlob(int fileSizeInMb) throws Exception {
- final DummyBlobData blobData = new DummyBlobData.Builder(mContext)
+ private FakeBlobData prepareDataBlob(int fileSizeInMb) throws Exception {
+ final FakeBlobData blobData = new FakeBlobData.Builder(mContext)
.setFileSize(fileSizeInMb * 1024 * 1024 /* bytes */)
.build();
blobData.prepare();
return blobData;
}
- private void commitBlob(DummyBlobData blobData) throws Exception {
+ private void commitBlob(FakeBlobData blobData) throws Exception {
final long sessionId = mBlobStoreManager.createSession(blobData.getBlobHandle());
try (BlobStoreManager.Session session = mBlobStoreManager.openSession(sessionId)) {
blobData.writeToSession(session);
diff --git a/apct-tests/perftests/contentcapture/Android.bp b/apct-tests/perftests/contentcapture/Android.bp
new file mode 100644
index 000000000000..66d7348008ab
--- /dev/null
+++ b/apct-tests/perftests/contentcapture/Android.bp
@@ -0,0 +1,28 @@
+// 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.
+
+android_test {
+ name: "ContentCapturePerfTests",
+ srcs: ["src/**/*.java"],
+ resource_dirs: ["res"],
+ static_libs: [
+ "androidx.test.rules",
+ "androidx.annotation_annotation",
+ "apct-perftests-utils",
+ "collector-device-lib-platform",
+ "compatibility-device-util-axt",
+ ],
+ platform_apis: true,
+ test_suites: ["device-tests"],
+}
diff --git a/apct-tests/perftests/contentcapture/AndroidManifest.xml b/apct-tests/perftests/contentcapture/AndroidManifest.xml
new file mode 100644
index 000000000000..ee5577f265fa
--- /dev/null
+++ b/apct-tests/perftests/contentcapture/AndroidManifest.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.perftests.contentcapture">
+
+ <uses-sdk android:targetSdkVersion="28" />
+
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+ <uses-permission android:name="android.permission.REAL_GET_TASKS" />
+
+ <application>
+ <uses-library android:name="android.test.runner" />
+ <activity android:name="android.view.contentcapture.CustomTestActivity"
+ android:exported="true">
+ </activity>
+
+ <service
+ android:name="android.view.contentcapture.MyContentCaptureService"
+ android:label="PERF ContentCaptureService"
+ android:permission="android.permission.BIND_CONTENT_CAPTURE_SERVICE"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.service.contentcapture.ContentCaptureService" />
+ </intent-filter>
+ </service>
+
+ </application>
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.perftests.contentcapture" />
+</manifest>
diff --git a/apct-tests/perftests/contentcapture/AndroidTest.xml b/apct-tests/perftests/contentcapture/AndroidTest.xml
new file mode 100644
index 000000000000..d2386bb1efea
--- /dev/null
+++ b/apct-tests/perftests/contentcapture/AndroidTest.xml
@@ -0,0 +1,27 @@
+<?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.
+-->
+<configuration description="Runs ContentCapturePerfTests metric instrumentation.">
+ <option name="test-suite-tag" value="apct" />
+ <option name="test-suite-tag" value="apct-metric-instrumentation" />
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true" />
+ <option name="test-file-name" value="ContentCapturePerfTests.apk" />
+ </target_preparer>
+
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+ <option name="package" value="com.android.perftests.contentcapture" />
+ </test>
+</configuration>
diff --git a/core/java/android/app/IRequestFinishCallback.aidl b/apct-tests/perftests/contentcapture/res/layout/test_container_activity.xml
index 3270565727d9..ca1a11a25e62 100644
--- a/core/java/android/app/IRequestFinishCallback.aidl
+++ b/apct-tests/perftests/contentcapture/res/layout/test_container_activity.xml
@@ -1,5 +1,6 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
+<?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.
@@ -12,16 +13,14 @@
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
- */
+-->
-package android.app;
-
-/**
- * This callback allows ActivityTaskManager to ask the calling Activity
- * to finish in response to a call to onBackPressedOnTaskRoot.
- *
- * {@hide}
- */
-oneway interface IRequestFinishCallback {
- void requestFinish();
-}
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:id="@+id/root_view"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:focusable="true"
+ android:focusableInTouchMode="true"
+ android:orientation="vertical" >
+</LinearLayout>
diff --git a/apct-tests/perftests/contentcapture/res/layout/test_login_activity.xml b/apct-tests/perftests/contentcapture/res/layout/test_login_activity.xml
new file mode 100644
index 000000000000..9bab32ca2264
--- /dev/null
+++ b/apct-tests/perftests/contentcapture/res/layout/test_login_activity.xml
@@ -0,0 +1,50 @@
+<?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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:id="@+id/root_view"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:focusable="true"
+ android:focusableInTouchMode="true"
+ android:orientation="vertical" >
+
+ <TextView
+ android:id="@+id/username_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Username" />
+
+ <EditText
+ android:id="@+id/username"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
+
+ <TextView
+ android:id="@+id/password_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Password" />
+
+ <EditText
+ android:id="@+id/password"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:inputType="textPassword" />
+
+</LinearLayout>
diff --git a/apct-tests/perftests/contentcapture/src/android/view/contentcapture/AbstractContentCapturePerfTestCase.java b/apct-tests/perftests/contentcapture/src/android/view/contentcapture/AbstractContentCapturePerfTestCase.java
new file mode 100644
index 000000000000..9b853fed81d3
--- /dev/null
+++ b/apct-tests/perftests/contentcapture/src/android/view/contentcapture/AbstractContentCapturePerfTestCase.java
@@ -0,0 +1,267 @@
+/*
+ * 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.view.contentcapture;
+
+import static android.view.contentcapture.CustomTestActivity.INTENT_EXTRA_CUSTOM_VIEWS;
+import static android.view.contentcapture.CustomTestActivity.INTENT_EXTRA_LAYOUT_ID;
+
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
+import static com.android.compatibility.common.util.ShellUtils.runShellCommand;
+
+import android.app.Application;
+import android.content.ContentCaptureOptions;
+import android.content.Context;
+import android.content.Intent;
+import android.os.BatteryManager;
+import android.os.UserHandle;
+import android.perftests.utils.PerfStatusReporter;
+import android.provider.Settings;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+import androidx.test.rule.ActivityTestRule;
+
+import com.android.compatibility.common.util.ActivitiesWatcher;
+import com.android.compatibility.common.util.ActivitiesWatcher.ActivityWatcher;
+import com.android.perftests.contentcapture.R;
+
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Rule;
+import org.junit.rules.TestRule;
+import org.junit.runners.model.Statement;
+
+/**
+ * Base class for all content capture tests.
+ */
+public abstract class AbstractContentCapturePerfTestCase {
+
+ private static final String TAG = AbstractContentCapturePerfTestCase.class.getSimpleName();
+ private static final long GENERIC_TIMEOUT_MS = 10_000;
+
+ private static int sOriginalStayOnWhilePluggedIn;
+ private static Context sContext = getInstrumentation().getTargetContext();
+
+ protected ActivitiesWatcher mActivitiesWatcher;
+
+ private MyContentCaptureService.ServiceWatcher mServiceWatcher;
+
+ @Rule
+ public ActivityTestRule<CustomTestActivity> mActivityRule =
+ new ActivityTestRule<>(CustomTestActivity.class, false, false);
+
+ @Rule
+ public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ @Rule
+ public TestRule mServiceDisablerRule = (base, description) -> {
+ return new Statement() {
+ @Override
+ public void evaluate() throws Throwable {
+ try {
+ base.evaluate();
+ } finally {
+ Log.v(TAG, "@mServiceDisablerRule: safelyDisableService()");
+ safelyDisableService();
+ }
+ }
+ };
+ };
+
+ private void safelyDisableService() {
+ try {
+ resetService();
+ MyContentCaptureService.resetStaticState();
+
+ if (mServiceWatcher != null) {
+ mServiceWatcher.waitOnDestroy();
+ }
+ } catch (Throwable t) {
+ Log.e(TAG, "error disabling service", t);
+ }
+ }
+
+ /**
+ * Sets the content capture service.
+ */
+ private static void setService(@NonNull String service) {
+ final int userId = getCurrentUserId();
+ Log.d(TAG, "Setting service for user " + userId + " to " + service);
+ // TODO(b/123540602): use @TestingAPI to get max duration constant
+ runShellCommand("cmd content_capture set temporary-service %d %s 119000", userId, service);
+ }
+
+ /**
+ * Resets the content capture service.
+ */
+ private static void resetService() {
+ final int userId = getCurrentUserId();
+ Log.d(TAG, "Resetting back user " + userId + " to default service");
+ runShellCommand("cmd content_capture set temporary-service %d", userId);
+ }
+
+ private static int getCurrentUserId() {
+ return UserHandle.myUserId();
+ }
+
+ @BeforeClass
+ public static void setStayAwake() {
+ Log.v(TAG, "@BeforeClass: setStayAwake()");
+ // Some test cases will restart the activity, and stay awake is necessary to ensure that
+ // the test will not screen off during the test.
+ // Keeping the activity screen on is not enough, screen off may occur between the activity
+ // finished and the next start
+ final int stayOnWhilePluggedIn = Settings.Global.getInt(sContext.getContentResolver(),
+ Settings.Global.STAY_ON_WHILE_PLUGGED_IN, 0);
+ sOriginalStayOnWhilePluggedIn = -1;
+ if (stayOnWhilePluggedIn != BatteryManager.BATTERY_PLUGGED_ANY) {
+ sOriginalStayOnWhilePluggedIn = stayOnWhilePluggedIn;
+ // Keep the device awake during testing.
+ setStayOnWhilePluggedIn(BatteryManager.BATTERY_PLUGGED_ANY);
+ }
+ }
+
+ @AfterClass
+ public static void resetStayAwake() {
+ Log.v(TAG, "@AfterClass: resetStayAwake()");
+ if (sOriginalStayOnWhilePluggedIn != -1) {
+ setStayOnWhilePluggedIn(sOriginalStayOnWhilePluggedIn);
+ }
+ }
+
+ private static void setStayOnWhilePluggedIn(int value) {
+ runShellCommand(String.format("settings put global %s %d",
+ Settings.Global.STAY_ON_WHILE_PLUGGED_IN, value));
+ }
+
+ @BeforeClass
+ public static void setAllowSelf() {
+ final ContentCaptureOptions options = new ContentCaptureOptions(null);
+ Log.v(TAG, "@BeforeClass: setAllowSelf(): options=" + options);
+ sContext.getApplicationContext().setContentCaptureOptions(options);
+ }
+
+ @AfterClass
+ public static void unsetAllowSelf() {
+ Log.v(TAG, "@AfterClass: unsetAllowSelf()");
+ clearOptions();
+ }
+
+ protected static void clearOptions() {
+ sContext.getApplicationContext().setContentCaptureOptions(null);
+ }
+
+ @BeforeClass
+ public static void disableDefaultService() {
+ Log.v(TAG, "@BeforeClass: disableDefaultService()");
+ setDefaultServiceEnabled(false);
+ }
+
+ @AfterClass
+ public static void enableDefaultService() {
+ Log.v(TAG, "@AfterClass: enableDefaultService()");
+ setDefaultServiceEnabled(true);
+ }
+
+ /**
+ * Enables / disables the default service.
+ */
+ private static void setDefaultServiceEnabled(boolean enabled) {
+ final int userId = getCurrentUserId();
+ Log.d(TAG, "setDefaultServiceEnabled(user=" + userId + ", enabled= " + enabled + ")");
+ runShellCommand("cmd content_capture set default-service-enabled %d %s", userId,
+ Boolean.toString(enabled));
+ }
+
+ @Before
+ public void prepareDevice() throws Exception {
+ Log.v(TAG, "@Before: prepareDevice()");
+
+ // Unlock screen.
+ runShellCommand("input keyevent KEYCODE_WAKEUP");
+
+ // Dismiss keyguard, in case it's set as "Swipe to unlock".
+ runShellCommand("wm dismiss-keyguard");
+
+ // Collapse notifications.
+ runShellCommand("cmd statusbar collapse");
+ }
+
+ @Before
+ public void registerLifecycleCallback() {
+ Log.v(TAG, "@Before: Registering lifecycle callback");
+ final Application app = (Application) sContext.getApplicationContext();
+ mActivitiesWatcher = new ActivitiesWatcher(GENERIC_TIMEOUT_MS);
+ app.registerActivityLifecycleCallbacks(mActivitiesWatcher);
+ }
+
+ @After
+ public void unregisterLifecycleCallback() {
+ Log.d(TAG, "@After: Unregistering lifecycle callback: " + mActivitiesWatcher);
+ if (mActivitiesWatcher != null) {
+ final Application app = (Application) sContext.getApplicationContext();
+ app.unregisterActivityLifecycleCallbacks(mActivitiesWatcher);
+ }
+ }
+
+ /**
+ * Sets {@link MyContentCaptureService} as the service for the current user and waits until
+ * its created, then add the perf test package into allow list.
+ */
+ public MyContentCaptureService enableService() throws InterruptedException {
+ if (mServiceWatcher != null) {
+ throw new IllegalStateException("There Can Be Only One!");
+ }
+
+ mServiceWatcher = MyContentCaptureService.setServiceWatcher();
+ setService(MyContentCaptureService.SERVICE_NAME);
+ mServiceWatcher.setAllowSelf();
+ return mServiceWatcher.waitOnCreate();
+ }
+
+ @NonNull
+ protected ActivityWatcher startWatcher() {
+ return mActivitiesWatcher.watch(CustomTestActivity.class);
+ }
+
+ /**
+ * Launch test activity with default login layout
+ */
+ protected CustomTestActivity launchActivity() {
+ return launchActivity(R.layout.test_login_activity, 0);
+ }
+
+ /**
+ * Launch test activity with give layout and parameter
+ */
+ protected CustomTestActivity launchActivity(int layoutId, int numViews) {
+ final Intent intent = new Intent(sContext, CustomTestActivity.class);
+ intent.putExtra(INTENT_EXTRA_LAYOUT_ID, layoutId);
+ intent.putExtra(INTENT_EXTRA_CUSTOM_VIEWS, numViews);
+ return mActivityRule.launchActivity(intent);
+ }
+
+ protected void finishActivity() {
+ try {
+ mActivityRule.finishActivity();
+ } catch (IllegalStateException e) {
+ // no op
+ }
+ }
+}
diff --git a/apct-tests/perftests/contentcapture/src/android/view/contentcapture/CustomTestActivity.java b/apct-tests/perftests/contentcapture/src/android/view/contentcapture/CustomTestActivity.java
new file mode 100644
index 000000000000..e509837f441a
--- /dev/null
+++ b/apct-tests/perftests/contentcapture/src/android/view/contentcapture/CustomTestActivity.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.view.contentcapture;
+
+import android.app.Activity;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import com.android.perftests.contentcapture.R;
+
+/**
+ * A simple activity used for testing, e.g. performance of activity switching, or as a base
+ * container of testing view.
+ */
+public class CustomTestActivity extends Activity {
+ public static final String INTENT_EXTRA_LAYOUT_ID = "layout_id";
+ public static final String INTENT_EXTRA_CUSTOM_VIEWS = "custom_view_number";
+ public static final int MAX_VIEWS = 500;
+ private static final int CUSTOM_CONTAINER_LAYOUT_ID = R.layout.test_container_activity;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ if (getIntent().hasExtra(INTENT_EXTRA_LAYOUT_ID)) {
+ final int layoutId = getIntent().getIntExtra(INTENT_EXTRA_LAYOUT_ID,
+ /* defaultValue= */0);
+ setContentView(layoutId);
+ if (layoutId == CUSTOM_CONTAINER_LAYOUT_ID) {
+ createCustomViews(findViewById(R.id.root_view),
+ getIntent().getIntExtra(INTENT_EXTRA_CUSTOM_VIEWS, MAX_VIEWS));
+ }
+ }
+ }
+
+ private void createCustomViews(LinearLayout root, int number) {
+ LinearLayout horizontalLayout = null;
+ for (int i = 0; i < number; i++) {
+ final int j = i % 8;
+ if (horizontalLayout != null && j == 0) {
+ root.addView(horizontalLayout);
+ horizontalLayout = null;
+ }
+ if (horizontalLayout == null) {
+ horizontalLayout = createHorizontalLayout();
+ }
+ horizontalLayout.addView(createItem(null, i));
+ }
+ if (horizontalLayout != null) {
+ root.addView(horizontalLayout);
+ }
+ }
+
+ private LinearLayout createHorizontalLayout() {
+ final LinearLayout layout = new LinearLayout(getApplicationContext());
+ layout.setOrientation(LinearLayout.HORIZONTAL);
+ return layout;
+ }
+
+ private LinearLayout createItem(Drawable drawable, int index) {
+ final LinearLayout group = new LinearLayout(getApplicationContext());
+ group.setOrientation(LinearLayout.VERTICAL);
+ group.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,
+ LinearLayout.LayoutParams.WRAP_CONTENT, /* weight= */ 1.0f));
+
+ final TextView text = new TextView(this);
+ text.setText("i = " + index);
+ group.addView(text);
+
+ return group;
+ }
+}
diff --git a/apct-tests/perftests/contentcapture/src/android/view/contentcapture/LoginTest.java b/apct-tests/perftests/contentcapture/src/android/view/contentcapture/LoginTest.java
new file mode 100644
index 000000000000..725750976d98
--- /dev/null
+++ b/apct-tests/perftests/contentcapture/src/android/view/contentcapture/LoginTest.java
@@ -0,0 +1,158 @@
+/*
+ * 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.view.contentcapture;
+
+import static com.android.compatibility.common.util.ActivitiesWatcher.ActivityLifecycle.CREATED;
+import static com.android.compatibility.common.util.ActivitiesWatcher.ActivityLifecycle.DESTROYED;
+
+import android.perftests.utils.BenchmarkState;
+import android.view.View;
+
+import androidx.test.filters.LargeTest;
+
+import com.android.compatibility.common.util.ActivitiesWatcher.ActivityWatcher;
+import com.android.perftests.contentcapture.R;
+
+import org.junit.Test;
+
+@LargeTest
+public class LoginTest extends AbstractContentCapturePerfTestCase {
+
+ @Test
+ public void testLaunchActivity() throws Throwable {
+ enableService();
+
+ testActivityLaunchTime(R.layout.test_login_activity, 0);
+ }
+
+ @Test
+ public void testLaunchActivity_contain100Views() throws Throwable {
+ enableService();
+
+ testActivityLaunchTime(R.layout.test_container_activity, 100);
+ }
+
+ @Test
+ public void testLaunchActivity_contain300Views() throws Throwable {
+ enableService();
+
+ testActivityLaunchTime(R.layout.test_container_activity, 300);
+ }
+
+ @Test
+ public void testLaunchActivity_contain500Views() throws Throwable {
+ enableService();
+
+ testActivityLaunchTime(R.layout.test_container_activity, 500);
+ }
+
+ @Test
+ public void testLaunchActivity_noService() throws Throwable {
+ testActivityLaunchTime(R.layout.test_login_activity, 0);
+ }
+
+ @Test
+ public void testLaunchActivity_noService_contain100Views() throws Throwable {
+ testActivityLaunchTime(R.layout.test_container_activity, 100);
+ }
+
+ @Test
+ public void testLaunchActivity_noService_contain300Views() throws Throwable {
+ testActivityLaunchTime(R.layout.test_container_activity, 300);
+ }
+
+ @Test
+ public void testLaunchActivity_noService_contain500Views() throws Throwable {
+ testActivityLaunchTime(R.layout.test_container_activity, 500);
+ }
+
+ private void testActivityLaunchTime(int layoutId, int numViews) throws Throwable {
+ final ActivityWatcher watcher = startWatcher();
+
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ launchActivity(layoutId, numViews);
+
+ // Ignore the time to finish the activity
+ state.pauseTiming();
+ watcher.waitFor(CREATED);
+ finishActivity();
+ watcher.waitFor(DESTROYED);
+ state.resumeTiming();
+ }
+ }
+
+ @Test
+ public void testOnVisibilityAggregated_visibleChanged() throws Throwable {
+ enableService();
+ final CustomTestActivity activity = launchActivity();
+ final View root = activity.getWindow().getDecorView();
+ final View username = root.findViewById(R.id.username);
+
+ testOnVisibilityAggregated(username);
+ }
+
+ @Test
+ public void testOnVisibilityAggregated_visibleChanged_noService() throws Throwable {
+ final CustomTestActivity activity = launchActivity();
+ final View root = activity.getWindow().getDecorView();
+ final View username = root.findViewById(R.id.username);
+
+ testOnVisibilityAggregated(username);
+ }
+
+ @Test
+ public void testOnVisibilityAggregated_visibleChanged_noOptions() throws Throwable {
+ enableService();
+ clearOptions();
+ final CustomTestActivity activity = launchActivity();
+ final View root = activity.getWindow().getDecorView();
+ final View username = root.findViewById(R.id.username);
+
+ testOnVisibilityAggregated(username);
+ }
+
+ @Test
+ public void testOnVisibilityAggregated_visibleChanged_notImportant() throws Throwable {
+ enableService();
+ final CustomTestActivity activity = launchActivity();
+ final View root = activity.getWindow().getDecorView();
+ final View username = root.findViewById(R.id.username);
+ username.setImportantForContentCapture(View.IMPORTANT_FOR_CONTENT_CAPTURE_NO);
+
+ testOnVisibilityAggregated(username);
+ }
+
+ private void testOnVisibilityAggregated(View view) throws Throwable {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+
+ while (state.keepRunning()) {
+ // Only count the time of onVisibilityAggregated()
+ state.pauseTiming();
+ mActivityRule.runOnUiThread(() -> {
+ state.resumeTiming();
+ view.onVisibilityAggregated(false);
+ state.pauseTiming();
+ });
+ mActivityRule.runOnUiThread(() -> {
+ state.resumeTiming();
+ view.onVisibilityAggregated(true);
+ state.pauseTiming();
+ });
+ state.resumeTiming();
+ }
+ }
+}
diff --git a/apct-tests/perftests/contentcapture/src/android/view/contentcapture/MyContentCaptureService.java b/apct-tests/perftests/contentcapture/src/android/view/contentcapture/MyContentCaptureService.java
new file mode 100644
index 000000000000..b1dbb28c9501
--- /dev/null
+++ b/apct-tests/perftests/contentcapture/src/android/view/contentcapture/MyContentCaptureService.java
@@ -0,0 +1,181 @@
+/*
+ * 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.view.contentcapture;
+
+import android.content.ComponentName;
+import android.service.contentcapture.ActivityEvent;
+import android.service.contentcapture.ContentCaptureService;
+import android.util.ArraySet;
+import android.util.Log;
+import android.util.Pair;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import java.util.Set;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+public class MyContentCaptureService extends ContentCaptureService {
+
+ private static final String TAG = MyContentCaptureService.class.getSimpleName();
+ private static final String MY_PACKAGE = "com.android.perftests.contentcapture";
+ public static final String SERVICE_NAME = MY_PACKAGE + "/"
+ + MyContentCaptureService.class.getName();
+
+ private static ServiceWatcher sServiceWatcher;
+
+ @NonNull
+ public static ServiceWatcher setServiceWatcher() {
+ if (sServiceWatcher != null) {
+ throw new IllegalStateException("There Can Be Only One!");
+ }
+ sServiceWatcher = new ServiceWatcher();
+ return sServiceWatcher;
+ }
+
+ public static void resetStaticState() {
+ sServiceWatcher = null;
+ }
+
+ public static void clearServiceWatcher() {
+ if (sServiceWatcher != null) {
+ if (sServiceWatcher.mReadyToClear) {
+ sServiceWatcher.mService = null;
+ sServiceWatcher = null;
+ } else {
+ sServiceWatcher.mReadyToClear = true;
+ }
+ }
+ }
+
+ @Override
+ public void onConnected() {
+ Log.i(TAG, "onConnected: sServiceWatcher=" + sServiceWatcher);
+
+ if (sServiceWatcher == null) {
+ Log.e(TAG, "onConnected() without a watcher");
+ return;
+ }
+
+ if (!sServiceWatcher.mReadyToClear && sServiceWatcher.mService != null) {
+ Log.e(TAG, "onConnected(): already created: " + sServiceWatcher);
+ return;
+ }
+
+ sServiceWatcher.mService = this;
+ sServiceWatcher.mCreated.countDown();
+ sServiceWatcher.mReadyToClear = false;
+ }
+
+ @Override
+ public void onDisconnected() {
+ Log.i(TAG, "onDisconnected: sServiceWatcher=" + sServiceWatcher);
+
+ if (sServiceWatcher == null) {
+ Log.e(TAG, "onDisconnected() without a watcher");
+ return;
+ }
+ if (sServiceWatcher.mService == null) {
+ Log.e(TAG, "onDisconnected(): no service on " + sServiceWatcher);
+ return;
+ }
+
+ sServiceWatcher.mDestroyed.countDown();
+ clearServiceWatcher();
+ }
+
+ @Override
+ public void onCreateContentCaptureSession(ContentCaptureContext context,
+ ContentCaptureSessionId sessionId) {
+ Log.i(TAG, "onCreateContentCaptureSession(ctx=" + context + ", session=" + sessionId);
+ }
+
+ @Override
+ public void onDestroyContentCaptureSession(ContentCaptureSessionId sessionId) {
+ Log.i(TAG, "onDestroyContentCaptureSession(session=" + sessionId + ")");
+ }
+
+ @Override
+ public void onContentCaptureEvent(ContentCaptureSessionId sessionId,
+ ContentCaptureEvent event) {
+ Log.i(TAG, "onContentCaptureEventsRequest(session=" + sessionId + "): " + event);
+ }
+
+ @Override
+ public void onActivityEvent(ActivityEvent event) {
+ Log.i(TAG, "onActivityEvent(): " + event);
+ }
+
+ public static final class ServiceWatcher {
+
+ private static final long GENERIC_TIMEOUT_MS = 10_000;
+ private final CountDownLatch mCreated = new CountDownLatch(1);
+ private final CountDownLatch mDestroyed = new CountDownLatch(1);
+ private boolean mReadyToClear = true;
+ private Pair<Set<String>, Set<ComponentName>> mAllowList;
+
+ private MyContentCaptureService mService;
+
+ @NonNull
+ public MyContentCaptureService waitOnCreate() throws InterruptedException {
+ await(mCreated, "not created");
+
+ if (mService == null) {
+ throw new IllegalStateException("not created");
+ }
+
+ if (mAllowList != null) {
+ Log.d(TAG, "Allow after created: " + mAllowList);
+ mService.setContentCaptureWhitelist(mAllowList.first, mAllowList.second);
+ }
+
+ return mService;
+ }
+
+ public void waitOnDestroy() throws InterruptedException {
+ await(mDestroyed, "not destroyed");
+ }
+
+ /**
+ * Allow just this package.
+ */
+ public void setAllowSelf() {
+ final ArraySet<String> pkgs = new ArraySet<>(1);
+ pkgs.add(MY_PACKAGE);
+ mAllowList = new Pair<>(pkgs, null);
+ }
+
+ @Override
+ public String toString() {
+ return "mService: " + mService + " created: " + (mCreated.getCount() == 0)
+ + " destroyed: " + (mDestroyed.getCount() == 0);
+ }
+
+ /**
+ * Awaits for a latch to be counted down.
+ */
+ private static void await(@NonNull CountDownLatch latch, @NonNull String fmt,
+ @Nullable Object... args)
+ throws InterruptedException {
+ final boolean called = latch.await(GENERIC_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+ if (!called) {
+ throw new IllegalStateException(String.format(fmt, args)
+ + " in " + GENERIC_TIMEOUT_MS + "ms");
+ }
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/Android.bp b/apct-tests/perftests/core/Android.bp
index 03ab5b6f2c8c..92dbc263cb34 100644
--- a/apct-tests/perftests/core/Android.bp
+++ b/apct-tests/perftests/core/Android.bp
@@ -17,11 +17,14 @@ android_test {
"apct-perftests-overlay-apps",
"apct-perftests-resources-manager-apps",
"apct-perftests-utils",
+ "collector-device-lib",
"guava",
],
libs: ["android.test.base"],
+ data: [":perfetto_artifacts"],
+
platform_apis: true,
jni_libs: ["libperftestscore_jni"],
diff --git a/apct-tests/perftests/core/AndroidTest.xml b/apct-tests/perftests/core/AndroidTest.xml
index 1b289130124f..4f8ee2927d51 100644
--- a/apct-tests/perftests/core/AndroidTest.xml
+++ b/apct-tests/perftests/core/AndroidTest.xml
@@ -16,13 +16,40 @@
<configuration description="Runs CorePerfTests metric instrumentation.">
<option name="test-suite-tag" value="apct" />
<option name="test-suite-tag" value="apct-metric-instrumentation" />
+
+ <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
+ <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+ <option name="push-file" key="trace_config_detailed.textproto" value="/data/misc/perfetto-traces/trace_config.textproto" />
+ </target_preparer>
+
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
<option name="test-file-name" value="CorePerfTests.apk" />
</target_preparer>
+ <metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
+ <option name="pull-pattern-keys" value="perfetto_file_path" />
+ </metrics_collector>
+
+ <!-- Needed for storing the perfetto files in external storage-->
+ <option name="isolated-storage" value="false" />
+
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="package" value="com.android.perftests.core" />
<option name="hidden-api-checks" value="false"/>
+
+ <option name="device-listeners" value="android.device.collectors.ProcLoadListener,android.device.collectors.PerfettoListener" />
+ <!-- ProcLoadListener related arguments -->
+ <!-- Wait for device last minute threshold to reach 3 with 2 minute timeout before starting the test run -->
+ <option name="instrumentation-arg" key="procload-collector:per_run" value="true" />
+ <option name="instrumentation-arg" key="proc-loadavg-threshold" value="3" />
+ <option name="instrumentation-arg" key="proc-loadavg-timeout" value="120000" />
+ <option name="instrumentation-arg" key="proc-loadavg-interval" value="10000" />
+
+ <!-- PerfettoListener related arguments -->
+ <option name="instrumentation-arg" key="perfetto_config_text_proto" value="true" />
+ <option name="instrumentation-arg" key="perfetto_config_file" value="trace_config.textproto" />
+
+ <option name="instrumentation-arg" key="newRunListenerMode" value="true" />
</test>
</configuration>
diff --git a/apct-tests/perftests/core/src/android/view/CutoutSpecificationBenchmark.java b/apct-tests/perftests/core/src/android/view/CutoutSpecificationBenchmark.java
index abd39f880a26..860c134ce3e2 100644
--- a/apct-tests/perftests/core/src/android/view/CutoutSpecificationBenchmark.java
+++ b/apct-tests/perftests/core/src/android/view/CutoutSpecificationBenchmark.java
@@ -16,24 +16,20 @@
package android.view;
-import android.content.Context;
import android.graphics.Matrix;
import android.graphics.Path;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Region;
import android.text.TextUtils;
-import android.util.DisplayMetrics;
import android.util.Log;
import android.util.PathParser;
import androidx.benchmark.BenchmarkState;
import androidx.benchmark.junit4.BenchmarkRule;
import androidx.test.filters.LargeTest;
-import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -41,6 +37,10 @@ import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
@LargeTest
public class CutoutSpecificationBenchmark {
+ private static final int DISPLAY_WIDTH = 1080;
+ private static final int DISPLAY_HEIGHT = 1920;
+ private static final float DISPLAY_DENSITY = 3.5f;
+
private static final String TAG = "CutoutSpecificationBenchmark";
private static final String BOTTOM_MARKER = "@bottom";
@@ -69,21 +69,6 @@ public class CutoutSpecificationBenchmark {
@Rule
public BenchmarkRule mBenchmarkRule = new BenchmarkRule();
- private Context mContext;
- private DisplayMetrics mDisplayMetrics;
-
- /**
- * Setup the necessary member field used by test methods.
- */
- @Before
- public void setUp() {
- mContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
-
- mDisplayMetrics = new DisplayMetrics();
- mContext.getDisplay().getRealMetrics(mDisplayMetrics);
- }
-
-
private static void toRectAndAddToRegion(Path p, Region inoutRegion, Rect inoutRect) {
final RectF rectF = new RectF();
p.computeBounds(rectF, false /* unused */);
@@ -170,8 +155,8 @@ public class CutoutSpecificationBenchmark {
public void parseByOldMethodForDoubleCutout() {
final BenchmarkState state = mBenchmarkRule.getState();
while (state.keepRunning()) {
- oldMethodParsingSpec(DOUBLE_CUTOUT_SPEC, mDisplayMetrics.widthPixels,
- mDisplayMetrics.heightPixels, mDisplayMetrics.density);
+ oldMethodParsingSpec(DOUBLE_CUTOUT_SPEC, DISPLAY_WIDTH, DISPLAY_HEIGHT,
+ DISPLAY_DENSITY);
}
}
@@ -179,8 +164,7 @@ public class CutoutSpecificationBenchmark {
public void parseByNewMethodForDoubleCutout() {
final BenchmarkState state = mBenchmarkRule.getState();
while (state.keepRunning()) {
- new CutoutSpecification.Parser(mDisplayMetrics.density,
- mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels)
+ new CutoutSpecification.Parser(DISPLAY_DENSITY, DISPLAY_WIDTH, DISPLAY_HEIGHT)
.parse(DOUBLE_CUTOUT_SPEC);
}
}
@@ -211,8 +195,8 @@ public class CutoutSpecificationBenchmark {
final BenchmarkState state = mBenchmarkRule.getState();
while (state.keepRunning()) {
- new CutoutSpecification.Parser(mDisplayMetrics.density,
- mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels).parse(spec);
+ new CutoutSpecification.Parser(DISPLAY_DENSITY, DISPLAY_WIDTH, DISPLAY_HEIGHT)
+ .parse(spec);
}
}
@@ -233,8 +217,8 @@ public class CutoutSpecificationBenchmark {
final BenchmarkState state = mBenchmarkRule.getState();
while (state.keepRunning()) {
- new CutoutSpecification.Parser(mDisplayMetrics.density,
- mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels).parse(spec);
+ new CutoutSpecification.Parser(DISPLAY_DENSITY, DISPLAY_WIDTH, DISPLAY_HEIGHT)
+ .parse(spec);
}
}
}
diff --git a/apct-tests/perftests/windowmanager/Android.bp b/apct-tests/perftests/windowmanager/Android.bp
index 9e95a104af81..9fa99853ace3 100644
--- a/apct-tests/perftests/windowmanager/Android.bp
+++ b/apct-tests/perftests/windowmanager/Android.bp
@@ -19,6 +19,7 @@ android_test {
"androidx.test.rules",
"androidx.annotation_annotation",
"apct-perftests-utils",
+ "collector-device-lib",
"platform-test-annotations",
],
test_suites: ["device-tests"],
diff --git a/apex/jobscheduler/framework/java/com/android/server/DeviceIdleInternal.java b/apex/jobscheduler/framework/java/com/android/server/DeviceIdleInternal.java
index 6475f5706a6d..18643ed91276 100644
--- a/apex/jobscheduler/framework/java/com/android/server/DeviceIdleInternal.java
+++ b/apex/jobscheduler/framework/java/com/android/server/DeviceIdleInternal.java
@@ -37,7 +37,7 @@ public interface DeviceIdleInternal {
String reason);
// duration in milliseconds
- long getNotificationWhitelistDuration();
+ long getNotificationAllowlistDuration();
void setJobsActive(boolean active);
diff --git a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
index f26549c24787..b1bafeea3c98 100644
--- a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
+++ b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
@@ -890,7 +890,8 @@ public class DeviceIdleController extends SystemService
"mms_temp_app_whitelist_duration";
private static final String KEY_SMS_TEMP_APP_WHITELIST_DURATION =
"sms_temp_app_whitelist_duration";
- private static final String KEY_NOTIFICATION_WHITELIST_DURATION =
+ // TODO(b/124466289): update value to match the name
+ private static final String KEY_NOTIFICATION_ALLOWLIST_DURATION =
"notification_whitelist_duration";
/**
* Whether to wait for the user to unlock the device before causing screen-on to
@@ -1124,9 +1125,9 @@ public class DeviceIdleController extends SystemService
* Amount of time we would like to whitelist an app that is handling a
* {@link android.app.PendingIntent} triggered by a {@link android.app.Notification}.
* @see Settings.Global#DEVICE_IDLE_CONSTANTS
- * @see #KEY_NOTIFICATION_WHITELIST_DURATION
+ * @see #KEY_NOTIFICATION_ALLOWLIST_DURATION
*/
- public long NOTIFICATION_WHITELIST_DURATION;
+ public long NOTIFICATION_ALLOWLIST_DURATION;
/**
* Pre idle time factor use to make idle delay longer
@@ -1230,8 +1231,8 @@ public class DeviceIdleController extends SystemService
KEY_MMS_TEMP_APP_WHITELIST_DURATION, 60 * 1000L);
SMS_TEMP_APP_WHITELIST_DURATION = mParser.getDurationMillis(
KEY_SMS_TEMP_APP_WHITELIST_DURATION, 20 * 1000L);
- NOTIFICATION_WHITELIST_DURATION = mParser.getDurationMillis(
- KEY_NOTIFICATION_WHITELIST_DURATION, 30 * 1000L);
+ NOTIFICATION_ALLOWLIST_DURATION = mParser.getDurationMillis(
+ KEY_NOTIFICATION_ALLOWLIST_DURATION, 30 * 1000L);
WAIT_FOR_UNLOCK = mParser.getBoolean(KEY_WAIT_FOR_UNLOCK, true);
PRE_IDLE_FACTOR_LONG = mParser.getFloat(KEY_PRE_IDLE_FACTOR_LONG, 1.67f);
PRE_IDLE_FACTOR_SHORT = mParser.getFloat(KEY_PRE_IDLE_FACTOR_SHORT, 0.33f);
@@ -1343,8 +1344,8 @@ public class DeviceIdleController extends SystemService
TimeUtils.formatDuration(SMS_TEMP_APP_WHITELIST_DURATION, pw);
pw.println();
- pw.print(" "); pw.print(KEY_NOTIFICATION_WHITELIST_DURATION); pw.print("=");
- TimeUtils.formatDuration(NOTIFICATION_WHITELIST_DURATION, pw);
+ pw.print(" "); pw.print(KEY_NOTIFICATION_ALLOWLIST_DURATION); pw.print("=");
+ TimeUtils.formatDuration(NOTIFICATION_ALLOWLIST_DURATION, pw);
pw.println();
pw.print(" "); pw.print(KEY_WAIT_FOR_UNLOCK); pw.print("=");
@@ -1792,8 +1793,8 @@ public class DeviceIdleController extends SystemService
// duration in milliseconds
@Override
- public long getNotificationWhitelistDuration() {
- return mConstants.NOTIFICATION_WHITELIST_DURATION;
+ public long getNotificationAllowlistDuration() {
+ return mConstants.NOTIFICATION_ALLOWLIST_DURATION;
}
@Override
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
index 06c469a5cc82..4db4adc2178f 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
@@ -1193,7 +1193,7 @@ public class JobSchedulerService extends com.android.server.SystemService
private void cancelJobsForNonExistentUsers() {
UserManagerInternal umi = LocalServices.getService(UserManagerInternal.class);
synchronized (mLock) {
- mJobs.removeJobsOfNonUsers(umi.getUserIds());
+ mJobs.removeJobsOfUnlistedUsers(umi.getUserIds());
}
}
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobStore.java b/apex/jobscheduler/service/java/com/android/server/job/JobStore.java
index 7bd51b77a119..eaf8f4d96331 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobStore.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobStore.java
@@ -254,11 +254,11 @@ public final class JobStore {
}
/**
- * Remove the jobs of users not specified in the whitelist.
- * @param whitelist Array of User IDs whose jobs are not to be removed.
+ * Remove the jobs of users not specified in the keepUserIds.
+ * @param keepUserIds Array of User IDs whose jobs should be kept and not removed.
*/
- public void removeJobsOfNonUsers(int[] whitelist) {
- mJobSet.removeJobsOfNonUsers(whitelist);
+ public void removeJobsOfUnlistedUsers(int[] keepUserIds) {
+ mJobSet.removeJobsOfUnlistedUsers(keepUserIds);
}
@VisibleForTesting
@@ -1151,15 +1151,14 @@ public final class JobStore {
}
/**
- * Removes the jobs of all users not specified by the whitelist of user ids.
- * This will remove jobs scheduled *by* non-existent users as well as jobs scheduled *for*
- * non-existent users
+ * Removes the jobs of all users not specified by the keepUserIds of user ids.
+ * This will remove jobs scheduled *by* and *for* any unlisted users.
*/
- public void removeJobsOfNonUsers(final int[] whitelist) {
+ public void removeJobsOfUnlistedUsers(final int[] keepUserIds) {
final Predicate<JobStatus> noSourceUser =
- job -> !ArrayUtils.contains(whitelist, job.getSourceUserId());
+ job -> !ArrayUtils.contains(keepUserIds, job.getSourceUserId());
final Predicate<JobStatus> noCallingUser =
- job -> !ArrayUtils.contains(whitelist, job.getUserId());
+ job -> !ArrayUtils.contains(keepUserIds, job.getUserId());
removeAll(noSourceUser.or(noCallingUser));
}
diff --git a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
index 2f993dad51c7..6bc95bf8bc75 100644
--- a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
+++ b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
@@ -222,12 +222,19 @@ public class AppStandbyController implements AppStandbyInternal {
@GuardedBy("mPackageAccessListeners")
private final ArrayList<AppIdleStateChangeListener> mPackageAccessListeners = new ArrayList<>();
+ /**
+ * Lock specifically for bookkeeping around the carrier-privileged app set.
+ * Do not acquire any other locks while holding this one. Methods that
+ * require this lock to be held are named with a "CPL" suffix.
+ */
+ private final Object mCarrierPrivilegedLock = new Lock();
+
/** Whether we've queried the list of carrier privileged apps. */
- @GuardedBy("mAppIdleLock")
+ @GuardedBy("mCarrierPrivilegedLock")
private boolean mHaveCarrierPrivilegedApps;
/** List of carrier-privileged apps that should be excluded from standby */
- @GuardedBy("mAppIdleLock")
+ @GuardedBy("mCarrierPrivilegedLock")
private List<String> mCarrierPrivilegedApps;
@GuardedBy("mActiveAdminApps")
@@ -1594,9 +1601,9 @@ public class AppStandbyController implements AppStandbyInternal {
}
private boolean isCarrierApp(String packageName) {
- synchronized (mAppIdleLock) {
+ synchronized (mCarrierPrivilegedLock) {
if (!mHaveCarrierPrivilegedApps) {
- fetchCarrierPrivilegedAppsLocked();
+ fetchCarrierPrivilegedAppsCPL();
}
if (mCarrierPrivilegedApps != null) {
return mCarrierPrivilegedApps.contains(packageName);
@@ -1610,14 +1617,14 @@ public class AppStandbyController implements AppStandbyInternal {
if (DEBUG) {
Slog.i(TAG, "Clearing carrier privileged apps list");
}
- synchronized (mAppIdleLock) {
+ synchronized (mCarrierPrivilegedLock) {
mHaveCarrierPrivilegedApps = false;
mCarrierPrivilegedApps = null; // Need to be refetched.
}
}
- @GuardedBy("mAppIdleLock")
- private void fetchCarrierPrivilegedAppsLocked() {
+ @GuardedBy("mCarrierPrivilegedLock")
+ private void fetchCarrierPrivilegedAppsCPL() {
TelephonyManager telephonyManager =
mContext.getSystemService(TelephonyManager.class);
mCarrierPrivilegedApps =
@@ -1858,7 +1865,7 @@ public class AppStandbyController implements AppStandbyInternal {
@Override
public void dumpState(String[] args, PrintWriter pw) {
- synchronized (mAppIdleLock) {
+ synchronized (mCarrierPrivilegedLock) {
pw.println("Carrier privileged apps (have=" + mHaveCarrierPrivilegedApps
+ "): " + mCarrierPrivilegedApps);
}
diff --git a/apex/statsd/aidl/Android.bp b/apex/statsd/aidl/Android.bp
index 04339e67d799..f66cf7c9e23c 100644
--- a/apex/statsd/aidl/Android.bp
+++ b/apex/statsd/aidl/Android.bp
@@ -30,6 +30,7 @@ aidl_interface {
"android/os/StatsDimensionsValueParcel.aidl",
"android/util/StatsEventParcel.aidl",
],
+ host_supported: true,
backend: {
java: {
enabled: false, // framework-statsd and service-statsd use framework-statsd-aidl-sources
diff --git a/apex/statsd/aidl/android/os/IStatsCompanionService.aidl b/apex/statsd/aidl/android/os/IStatsCompanionService.aidl
index 5cdb3249501b..d56a4bd0a8e5 100644
--- a/apex/statsd/aidl/android/os/IStatsCompanionService.aidl
+++ b/apex/statsd/aidl/android/os/IStatsCompanionService.aidl
@@ -27,17 +27,6 @@ interface IStatsCompanionService {
oneway void statsdReady();
/**
- * Register an alarm for anomaly detection to fire at the given timestamp (ms since epoch).
- * If anomaly alarm had already been registered, it will be replaced with the new timestamp.
- * Uses AlarmManager.set API, so if the timestamp is in the past, alarm fires immediately, and
- * alarm is inexact.
- */
- oneway void setAnomalyAlarm(long timestampMs);
-
- /** Cancel any anomaly detection alarm. */
- oneway void cancelAnomalyAlarm();
-
- /**
* Register a repeating alarm for pulling to fire at the given timestamp and every
* intervalMs thereafter (in ms since epoch).
* If polling alarm had already been registered, it will be replaced by new one.
diff --git a/apex/statsd/aidl/android/os/IStatsd.aidl b/apex/statsd/aidl/android/os/IStatsd.aidl
index 0d3f4208a2ab..066412a9f157 100644
--- a/apex/statsd/aidl/android/os/IStatsd.aidl
+++ b/apex/statsd/aidl/android/os/IStatsd.aidl
@@ -42,13 +42,6 @@ interface IStatsd {
void statsCompanionReady();
/**
- * Tells statsd that an anomaly may have occurred, so statsd can check whether this is so and
- * act accordingly.
- * Two-way binder call so that caller's method (and corresponding wakelocks) will linger.
- */
- void informAnomalyAlarmFired();
-
- /**
* Tells statsd that it is time to poll some stats. Statsd will be responsible for determing
* what stats to poll and initiating the polling.
* Two-way binder call so that caller's method (and corresponding wakelocks) will linger.
diff --git a/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java b/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java
index cbc8ed636ff2..b5e72247a4a3 100644
--- a/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java
+++ b/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java
@@ -100,7 +100,6 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
private static IStatsd sStatsd;
private static final Object sStatsdLock = new Object();
- private final OnAlarmListener mAnomalyAlarmListener;
private final OnAlarmListener mPullingAlarmListener;
private final OnAlarmListener mPeriodicAlarmListener;
@@ -124,7 +123,6 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
handlerThread.start();
mHandler = new CompanionHandler(handlerThread.getLooper());
- mAnomalyAlarmListener = new AnomalyAlarmListener(context);
mPullingAlarmListener = new PullingAlarmListener(context);
mPeriodicAlarmListener = new PeriodicAlarmListener(context);
}
@@ -336,41 +334,6 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
}
}
- public static final class AnomalyAlarmListener implements OnAlarmListener {
- private final Context mContext;
-
- AnomalyAlarmListener(Context context) {
- mContext = context;
- }
-
- @Override
- public void onAlarm() {
- if (DEBUG) {
- Log.i(TAG, "StatsCompanionService believes an anomaly has occurred at time "
- + System.currentTimeMillis() + "ms.");
- }
- IStatsd statsd = getStatsdNonblocking();
- if (statsd == null) {
- Log.w(TAG, "Could not access statsd to inform it of anomaly alarm firing");
- return;
- }
-
- // Wakelock needs to be retained while calling statsd.
- Thread thread = new WakelockThread(mContext,
- AnomalyAlarmListener.class.getCanonicalName(), new Runnable() {
- @Override
- public void run() {
- try {
- statsd.informAnomalyAlarmFired();
- } catch (RemoteException e) {
- Log.w(TAG, "Failed to inform statsd of anomaly alarm firing", e);
- }
- }
- });
- thread.start();
- }
- }
-
public final static class PullingAlarmListener implements OnAlarmListener {
private final Context mContext;
@@ -469,34 +432,6 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
}
@Override // Binder call
- public void setAnomalyAlarm(long timestampMs) {
- StatsCompanion.enforceStatsdCallingUid();
- if (DEBUG) Log.d(TAG, "Setting anomaly alarm for " + timestampMs);
- final long callingToken = Binder.clearCallingIdentity();
- try {
- // using ELAPSED_REALTIME, not ELAPSED_REALTIME_WAKEUP, so if device is asleep, will
- // only fire when it awakens.
- // AlarmManager will automatically cancel any previous mAnomalyAlarmListener alarm.
- mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME, timestampMs, TAG + ".anomaly",
- mAnomalyAlarmListener, mHandler);
- } finally {
- Binder.restoreCallingIdentity(callingToken);
- }
- }
-
- @Override // Binder call
- public void cancelAnomalyAlarm() {
- StatsCompanion.enforceStatsdCallingUid();
- if (DEBUG) Log.d(TAG, "Cancelling anomaly alarm");
- final long callingToken = Binder.clearCallingIdentity();
- try {
- mAlarmManager.cancel(mAnomalyAlarmListener);
- } finally {
- Binder.restoreCallingIdentity(callingToken);
- }
- }
-
- @Override // Binder call
public void setAlarmForSubscriberTriggering(long timestampMs) {
StatsCompanion.enforceStatsdCallingUid();
if (DEBUG) {
@@ -666,7 +601,6 @@ public class StatsCompanionService extends IStatsCompanionService.Stub {
// instead of in binder death because statsd can come back and set different alarms, or not
// want to set an alarm when it had been set. This guarantees that when we get a new statsd,
// we cancel any alarms before it is able to set them.
- cancelAnomalyAlarm();
cancelPullingAlarm();
cancelAlarmForSubscriberTriggering();
diff --git a/api/current.txt b/api/current.txt
index 1d2286b333bb..a59c7b85e608 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -5957,6 +5957,7 @@ package android.app {
method public long[] getVibrationPattern();
method public boolean hasUserSetImportance();
method public boolean hasUserSetSound();
+ method public boolean isDemoted();
method public boolean isImportantConversation();
method public void setAllowBubbles(boolean);
method public void setBypassDnd(boolean);
@@ -45454,6 +45455,7 @@ package android.system {
package android.telecom {
public final class Call {
+ method public void addConferenceParticipants(@NonNull java.util.List<android.net.Uri>);
method public void answer(int);
method public void conference(android.telecom.Call);
method public void deflect(android.net.Uri);
@@ -45562,6 +45564,7 @@ package android.telecom {
method public static boolean hasProperty(int, int);
method public boolean hasProperty(int);
method public static String propertiesToString(int);
+ field public static final int CAPABILITY_ADD_PARTICIPANT = 33554432; // 0x2000000
field public static final int CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO = 4194304; // 0x400000
field public static final int CAPABILITY_CAN_PAUSE_VIDEO = 1048576; // 0x100000
field public static final int CAPABILITY_CAN_PULL_CALL = 8388608; // 0x800000
@@ -45591,6 +45594,7 @@ package android.telecom {
field public static final int PROPERTY_GENERIC_CONFERENCE = 2; // 0x2
field public static final int PROPERTY_HAS_CDMA_VOICE_PRIVACY = 128; // 0x80
field public static final int PROPERTY_HIGH_DEF_AUDIO = 16; // 0x10
+ field public static final int PROPERTY_IS_ADHOC_CONFERENCE = 8192; // 0x2000
field public static final int PROPERTY_IS_EXTERNAL_CALL = 64; // 0x40
field public static final int PROPERTY_NETWORK_IDENTIFIED_EMERGENCY_CALL = 2048; // 0x800
field public static final int PROPERTY_RTT = 1024; // 0x400
@@ -45668,6 +45672,7 @@ package android.telecom {
public abstract class Conference extends android.telecom.Conferenceable {
ctor public Conference(android.telecom.PhoneAccountHandle);
method public final boolean addConnection(android.telecom.Connection);
+ method @NonNull public static android.telecom.Conference createFailedConference(@NonNull android.telecom.DisconnectCause, @NonNull android.telecom.PhoneAccountHandle);
method public final void destroy();
method public final android.telecom.CallAudioState getCallAudioState();
method public final java.util.List<android.telecom.Connection> getConferenceableConnections();
@@ -45683,6 +45688,9 @@ package android.telecom {
method public final android.telecom.StatusHints getStatusHints();
method public android.telecom.Connection.VideoProvider getVideoProvider();
method public int getVideoState();
+ method public final boolean isRingbackRequested();
+ method public void onAddConferenceParticipants(@NonNull java.util.List<android.net.Uri>);
+ method public void onAnswer(int);
method public void onCallAudioStateChanged(android.telecom.CallAudioState);
method public void onConnectionAdded(android.telecom.Connection);
method public void onDisconnect();
@@ -45691,6 +45699,7 @@ package android.telecom {
method public void onMerge(android.telecom.Connection);
method public void onMerge();
method public void onPlayDtmfTone(char);
+ method public void onReject();
method public void onSeparate(android.telecom.Connection);
method public void onStopDtmfTone();
method public void onSwap();
@@ -45711,6 +45720,8 @@ package android.telecom {
method public final void setDisconnected(android.telecom.DisconnectCause);
method public final void setExtras(@Nullable android.os.Bundle);
method public final void setOnHold();
+ method public final void setRingbackRequested(boolean);
+ method public final void setRinging();
method public final void setStatusHints(android.telecom.StatusHints);
method public final void setVideoProvider(android.telecom.Connection, android.telecom.Connection.VideoProvider);
method public final void setVideoState(android.telecom.Connection, int);
@@ -45747,6 +45758,7 @@ package android.telecom {
method public final boolean isRingbackRequested();
method public final void notifyConferenceMergeFailed();
method public void onAbort();
+ method public void onAddConferenceParticipants(@NonNull java.util.List<android.net.Uri>);
method public void onAnswer(int);
method public void onAnswer();
method public void onCallAudioStateChanged(android.telecom.CallAudioState);
@@ -45826,6 +45838,7 @@ package android.telecom {
field public static final int AUDIO_CODEC_GSM_HR = 10; // 0xa
field public static final int AUDIO_CODEC_NONE = 0; // 0x0
field public static final int AUDIO_CODEC_QCELP13K = 3; // 0x3
+ field public static final int CAPABILITY_ADD_PARTICIPANT = 67108864; // 0x4000000
field public static final int CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO = 8388608; // 0x800000
field public static final int CAPABILITY_CAN_PAUSE_VIDEO = 1048576; // 0x100000
field public static final int CAPABILITY_CAN_PULL_CALL = 16777216; // 0x1000000
@@ -45869,6 +45882,7 @@ package android.telecom {
field public static final int PROPERTY_ASSISTED_DIALING = 512; // 0x200
field public static final int PROPERTY_HAS_CDMA_VOICE_PRIVACY = 32; // 0x20
field public static final int PROPERTY_HIGH_DEF_AUDIO = 4; // 0x4
+ field public static final int PROPERTY_IS_ADHOC_CONFERENCE = 4096; // 0x1000
field public static final int PROPERTY_IS_EXTERNAL_CALL = 16; // 0x10
field public static final int PROPERTY_IS_RTT = 256; // 0x100
field public static final int PROPERTY_NETWORK_IDENTIFIED_EMERGENCY_CALL = 1024; // 0x400
@@ -45964,9 +45978,13 @@ package android.telecom {
method public void onConference(android.telecom.Connection, android.telecom.Connection);
method public void onConnectionServiceFocusGained();
method public void onConnectionServiceFocusLost();
+ method @Nullable public android.telecom.Conference onCreateIncomingConference(@Nullable android.telecom.PhoneAccountHandle, @Nullable android.telecom.ConnectionRequest);
+ method public void onCreateIncomingConferenceFailed(@Nullable android.telecom.PhoneAccountHandle, @Nullable android.telecom.ConnectionRequest);
method public android.telecom.Connection onCreateIncomingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
method public void onCreateIncomingConnectionFailed(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
method public android.telecom.Connection onCreateIncomingHandoverConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
+ method @Nullable public android.telecom.Conference onCreateOutgoingConference(@Nullable android.telecom.PhoneAccountHandle, @Nullable android.telecom.ConnectionRequest);
+ method public void onCreateOutgoingConferenceFailed(@Nullable android.telecom.PhoneAccountHandle, @Nullable android.telecom.ConnectionRequest);
method public android.telecom.Connection onCreateOutgoingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
method public void onCreateOutgoingConnectionFailed(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
method public android.telecom.Connection onCreateOutgoingHandoverConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
@@ -46277,6 +46295,7 @@ package android.telecom {
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ANSWER_PHONE_CALLS, android.Manifest.permission.MODIFY_PHONE_STATE}) public void acceptRingingCall();
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ANSWER_PHONE_CALLS, android.Manifest.permission.MODIFY_PHONE_STATE}) public void acceptRingingCall(int);
method public void addNewIncomingCall(android.telecom.PhoneAccountHandle, android.os.Bundle);
+ method public void addNewIncomingConference(@NonNull android.telecom.PhoneAccountHandle, @NonNull android.os.Bundle);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void cancelMissedCallsNotification();
method public android.content.Intent createManageBlockedNumbersIntent();
method @Deprecated @RequiresPermission(android.Manifest.permission.ANSWER_PHONE_CALLS) public boolean endCall();
@@ -46304,6 +46323,7 @@ package android.telecom {
method public void registerPhoneAccount(android.telecom.PhoneAccount);
method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public void showInCallScreen(boolean);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void silenceRinger();
+ method @RequiresPermission(android.Manifest.permission.CALL_PHONE) public void startConference(@NonNull java.util.List<android.net.Uri>, @NonNull android.os.Bundle);
method public void unregisterPhoneAccount(android.telecom.PhoneAccountHandle);
field public static final String ACTION_CHANGE_DEFAULT_DIALER = "android.telecom.action.CHANGE_DEFAULT_DIALER";
field public static final String ACTION_CHANGE_PHONE_ACCOUNTS = "android.telecom.action.CHANGE_PHONE_ACCOUNTS";
@@ -46843,6 +46863,8 @@ package android.telephony {
field public static final String KEY_SIM_NETWORK_UNLOCK_ALLOW_DISMISS_BOOL = "sim_network_unlock_allow_dismiss_bool";
field public static final String KEY_SMS_REQUIRES_DESTINATION_NUMBER_CONVERSION_BOOL = "sms_requires_destination_number_conversion_bool";
field public static final String KEY_SUPPORT_3GPP_CALL_FORWARDING_WHILE_ROAMING_BOOL = "support_3gpp_call_forwarding_while_roaming_bool";
+ field public static final String KEY_SUPPORT_ADD_CONFERENCE_PARTICIPANTS_BOOL = "support_add_conference_participants_bool";
+ field public static final String KEY_SUPPORT_ADHOC_CONFERENCE_CALLS_BOOL = "support_adhoc_conference_calls_bool";
field public static final String KEY_SUPPORT_CLIR_NETWORK_DEFAULT_BOOL = "support_clir_network_default_bool";
field public static final String KEY_SUPPORT_CONFERENCE_CALL_BOOL = "support_conference_call_bool";
field public static final String KEY_SUPPORT_EMERGENCY_SMS_OVER_IMS_BOOL = "support_emergency_sms_over_ims_bool";
@@ -47915,12 +47937,13 @@ package android.telephony {
public final class SmsManager {
method public String createAppSpecificSmsToken(android.app.PendingIntent);
method @Nullable public String createAppSpecificSmsTokenWithPackageInfo(@Nullable String, @NonNull android.app.PendingIntent);
+ method @NonNull public android.telephony.SmsManager createForSubscriptionId(int);
method public java.util.ArrayList<java.lang.String> divideMessage(String);
method public void downloadMultimediaMessage(android.content.Context, String, android.net.Uri, android.os.Bundle, android.app.PendingIntent);
method @NonNull public android.os.Bundle getCarrierConfigValues();
- method public static android.telephony.SmsManager getDefault();
+ method @Deprecated public static android.telephony.SmsManager getDefault();
method public static int getDefaultSmsSubscriptionId();
- method public static android.telephony.SmsManager getSmsManagerForSubscriptionId(int);
+ method @Deprecated public static android.telephony.SmsManager getSmsManagerForSubscriptionId(int);
method @RequiresPermission(android.Manifest.permission.SMS_FINANCIAL_TRANSACTIONS) public void getSmsMessagesForFinancialApp(android.os.Bundle, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.SmsManager.FinancialSmsCallback);
method @Nullable @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public String getSmscAddress();
method public int getSubscriptionId();
diff --git a/api/module-lib-current.txt b/api/module-lib-current.txt
index 360e44ff055c..696e02972c23 100644
--- a/api/module-lib-current.txt
+++ b/api/module-lib-current.txt
@@ -5,6 +5,10 @@ package android.app {
field public static final String OPSTR_NO_ISOLATED_STORAGE = "android:no_isolated_storage";
}
+ public class NotificationManager {
+ method public boolean hasEnabledNotificationListener(@NonNull String, @NonNull android.os.UserHandle);
+ }
+
}
package android.content.rollback {
@@ -69,6 +73,15 @@ package android.net {
package android.os {
+ public class Binder implements android.os.IBinder {
+ method public final void markVintfStability();
+ }
+
+ public interface Parcelable {
+ field public static final int PARCELABLE_STABILITY_LOCAL = 0; // 0x0
+ field public static final int PARCELABLE_STABILITY_VINTF = 1; // 0x1
+ }
+
public class StatsFrameworkInitializer {
method public static void registerServiceWrappers();
method public static void setStatsServiceManager(@NonNull android.os.StatsServiceManager);
diff --git a/api/test-current.txt b/api/test-current.txt
index f1a3566f7b45..963ef7c540c7 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -453,6 +453,7 @@ package android.app {
method public void lockFields(int);
method public void setBlockable(boolean);
method public void setDeleted(boolean);
+ method public void setDemoted(boolean);
method public void setFgServiceShown(boolean);
method public void setImportanceLockedByCriticalDeviceFunction(boolean);
method public void setImportanceLockedByOEM(boolean);
@@ -476,6 +477,7 @@ package android.app {
method public boolean isNotificationAssistantAccessGranted(@NonNull android.content.ComponentName);
method public boolean matchesCallFilter(android.os.Bundle);
method public void setNotificationAssistantAccessGranted(@Nullable android.content.ComponentName, boolean);
+ method public void updateNotificationChannel(@NonNull String, int, @NonNull android.app.NotificationChannel);
}
public final class PictureInPictureParams implements android.os.Parcelable {
@@ -551,11 +553,13 @@ package android.app {
method public int getActivityType();
method public android.graphics.Rect getAppBounds();
method public android.graphics.Rect getBounds();
+ method @NonNull public android.graphics.Rect getMaxBounds();
method public int getRotation();
method public int getWindowingMode();
method public void setActivityType(int);
method public void setAppBounds(android.graphics.Rect);
method public void setBounds(android.graphics.Rect);
+ method public void setMaxBounds(@Nullable android.graphics.Rect);
method public void setRotation(int);
method public void setTo(android.app.WindowConfiguration);
method public void setWindowingMode(int);
diff --git a/cmds/statsd/Android.bp b/cmds/statsd/Android.bp
index 124f815f51f0..1579715727ac 100644
--- a/cmds/statsd/Android.bp
+++ b/cmds/statsd/Android.bp
@@ -171,7 +171,8 @@ cc_library_static {
export_generated_headers: ["statslog_statsdtest.h"],
shared_libs: [
"libstatssocket",
- ]
+ "libstatspull",
+ ],
}
cc_library_static {
@@ -185,7 +186,11 @@ cc_library_static {
],
shared_libs: [
"libstatssocket",
- ]
+ "libstatspull",
+ ],
+ export_shared_lib_headers: [
+ "libstatspull",
+ ],
}
// =========
diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp
index 05e9ec3a1769..b7f23a605142 100644
--- a/cmds/statsd/src/StatsLogProcessor.cpp
+++ b/cmds/statsd/src/StatsLogProcessor.cpp
@@ -120,10 +120,9 @@ static void flushProtoToBuffer(ProtoOutputStream& proto, vector<uint8_t>* outDat
}
}
-void StatsLogProcessor::onAnomalyAlarmFired(
+void StatsLogProcessor::processFiredAnomalyAlarmsLocked(
const int64_t& timestampNs,
unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>> alarmSet) {
- std::lock_guard<std::mutex> lock(mMetricsMutex);
for (const auto& itr : mMetricsManagers) {
itr.second->onAnomalyAlarmFired(timestampNs, alarmSet);
}
@@ -429,6 +428,20 @@ void StatsLogProcessor::OnLogEvent(LogEvent* event, int64_t elapsedRealtimeNs) {
return;
}
+ bool fireAlarm = false;
+ {
+ std::lock_guard<std::mutex> anomalyLock(mAnomalyAlarmMutex);
+ if (mNextAnomalyAlarmTime != 0 &&
+ MillisToNano(mNextAnomalyAlarmTime) <= elapsedRealtimeNs) {
+ mNextAnomalyAlarmTime = 0;
+ VLOG("informing anomaly alarm at time %lld", (long long)elapsedRealtimeNs);
+ fireAlarm = true;
+ }
+ }
+ if (fireAlarm) {
+ informAnomalyAlarmFiredLocked(NanoToMillis(elapsedRealtimeNs));
+ }
+
int64_t curTimeSec = getElapsedRealtimeSec();
if (curTimeSec - mLastPullerCacheClearTimeSec > StatsdStats::kPullerCacheClearIntervalSec) {
mPullerManager->ClearPullerCacheIfNecessary(curTimeSec * NS_PER_SEC);
@@ -1090,6 +1103,28 @@ void StatsLogProcessor::noteOnDiskData(const ConfigKey& key) {
mOnDiskDataConfigs.insert(key);
}
+void StatsLogProcessor::setAnomalyAlarm(const int64_t elapsedTimeMillis) {
+ std::lock_guard<std::mutex> lock(mAnomalyAlarmMutex);
+ mNextAnomalyAlarmTime = elapsedTimeMillis;
+}
+
+void StatsLogProcessor::cancelAnomalyAlarm() {
+ std::lock_guard<std::mutex> lock(mAnomalyAlarmMutex);
+ mNextAnomalyAlarmTime = 0;
+}
+
+void StatsLogProcessor::informAnomalyAlarmFiredLocked(const int64_t elapsedTimeMillis) {
+ VLOG("StatsService::informAlarmForSubscriberTriggeringFired was called");
+ std::unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>> alarmSet =
+ mAnomalyAlarmMonitor->popSoonerThan(static_cast<uint32_t>(elapsedTimeMillis / 1000));
+ if (alarmSet.size() > 0) {
+ VLOG("Found periodic alarm fired.");
+ processFiredAnomalyAlarmsLocked(MillisToNano(elapsedTimeMillis), alarmSet);
+ } else {
+ ALOGW("Cannot find an periodic alarm that fired. Perhaps it was recently cancelled.");
+ }
+}
+
} // namespace statsd
} // namespace os
} // namespace android
diff --git a/cmds/statsd/src/StatsLogProcessor.h b/cmds/statsd/src/StatsLogProcessor.h
index c0f54a0995ac..2384ed8f8ca8 100644
--- a/cmds/statsd/src/StatsLogProcessor.h
+++ b/cmds/statsd/src/StatsLogProcessor.h
@@ -66,11 +66,6 @@ public:
const DumpLatency dumpLatency,
ProtoOutputStream* proto);
- /* Tells MetricsManager that the alarms in alarmSet have fired. Modifies anomaly alarmSet. */
- void onAnomalyAlarmFired(
- const int64_t& timestampNs,
- unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>> alarmSet);
-
/* Tells MetricsManager that the alarms in alarmSet have fired. Modifies periodic alarmSet. */
void onPeriodicAlarmFired(
const int64_t& timestampNs,
@@ -146,6 +141,10 @@ public:
// Add a specific config key to the possible configs to dump ASAP.
void noteOnDiskData(const ConfigKey& key);
+ void setAnomalyAlarm(const int64_t timeMillis);
+
+ void cancelAnomalyAlarm();
+
private:
// For testing only.
inline sp<AlarmMonitor> getAnomalyAlarmMonitor() const {
@@ -158,6 +157,11 @@ private:
mutable mutex mMetricsMutex;
+ // Guards mNextAnomalyAlarmTime. A separate mutex is needed because alarms are set/cancelled
+ // in the onLogEvent code path, which is locked by mMetricsMutex.
+ // DO NOT acquire mMetricsMutex while holding mAnomalyAlarmMutex. This can lead to a deadlock.
+ mutable mutex mAnomalyAlarmMutex;
+
std::unordered_map<ConfigKey, sp<MetricsManager>> mMetricsManagers;
std::unordered_map<ConfigKey, int64_t> mLastBroadcastTimes;
@@ -248,6 +252,15 @@ private:
// Reset the specified configs.
void resetConfigsLocked(const int64_t timestampNs, const std::vector<ConfigKey>& configs);
+ // An anomaly alarm should have fired.
+ // Check with anomaly alarm manager to find the alarms and process the result.
+ void informAnomalyAlarmFiredLocked(const int64_t elapsedTimeMillis);
+
+ /* Tells MetricsManager that the alarms in alarmSet have fired. Modifies anomaly alarmSet. */
+ void processFiredAnomalyAlarmsLocked(
+ const int64_t& timestampNs,
+ unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>> alarmSet);
+
// Function used to send a broadcast so that receiver for the config key can call getData
// to retrieve the stored data.
std::function<bool(const ConfigKey& key)> mSendBroadcast;
@@ -274,6 +287,9 @@ private:
//Last time we wrote metadata to disk.
int64_t mLastMetadataWriteNs = 0;
+ // The time for the next anomaly alarm for alerts.
+ int64_t mNextAnomalyAlarmTime = 0;
+
bool mPrintAllLogs = false;
FRIEND_TEST(StatsLogProcessorTest, TestOutOfOrderLogs);
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index d5e331495164..68c2dd56ef13 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -91,17 +91,13 @@ Status checkUid(uid_t expectedUid) {
StatsService::StatsService(const sp<Looper>& handlerLooper, shared_ptr<LogEventQueue> queue)
: mAnomalyAlarmMonitor(new AlarmMonitor(
MIN_DIFF_TO_UPDATE_REGISTERED_ALARM_SECS,
- [](const shared_ptr<IStatsCompanionService>& sc, int64_t timeMillis) {
- if (sc != nullptr) {
- sc->setAnomalyAlarm(timeMillis);
- StatsdStats::getInstance().noteRegisteredAnomalyAlarmChanged();
- }
+ [this](const shared_ptr<IStatsCompanionService>& /*sc*/, int64_t timeMillis) {
+ mProcessor->setAnomalyAlarm(timeMillis);
+ StatsdStats::getInstance().noteRegisteredAnomalyAlarmChanged();
},
- [](const shared_ptr<IStatsCompanionService>& sc) {
- if (sc != nullptr) {
- sc->cancelAnomalyAlarm();
- StatsdStats::getInstance().noteRegisteredAnomalyAlarmChanged();
- }
+ [this](const shared_ptr<IStatsCompanionService>& /*sc*/) {
+ mProcessor->cancelAnomalyAlarm();
+ StatsdStats::getInstance().noteRegisteredAnomalyAlarmChanged();
})),
mPeriodicAlarmMonitor(new AlarmMonitor(
MIN_DIFF_TO_UPDATE_REGISTERED_ALARM_SECS,
@@ -977,22 +973,6 @@ Status StatsService::informOnePackageRemoved(const string& app, int32_t uid) {
return Status::ok();
}
-Status StatsService::informAnomalyAlarmFired() {
- ENFORCE_UID(AID_SYSTEM);
-
- VLOG("StatsService::informAnomalyAlarmFired was called");
- int64_t currentTimeSec = getElapsedRealtimeSec();
- std::unordered_set<sp<const InternalAlarm>, SpHash<InternalAlarm>> alarmSet =
- mAnomalyAlarmMonitor->popSoonerThan(static_cast<uint32_t>(currentTimeSec));
- if (alarmSet.size() > 0) {
- VLOG("Found an anomaly alarm that fired.");
- mProcessor->onAnomalyAlarmFired(currentTimeSec * NS_PER_SEC, alarmSet);
- } else {
- VLOG("Cannot find an anomaly alarm that fired. Perhaps it was recently cancelled.");
- }
- return Status::ok();
-}
-
Status StatsService::informAlarmForSubscriberTriggeringFired() {
ENFORCE_UID(AID_SYSTEM);
diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h
index 324ffbd65e51..479f4e87ec96 100644
--- a/cmds/statsd/src/StatsService.h
+++ b/cmds/statsd/src/StatsService.h
@@ -66,7 +66,6 @@ public:
virtual Status systemRunning();
virtual Status statsCompanionReady();
virtual Status bootCompleted();
- virtual Status informAnomalyAlarmFired();
virtual Status informPollAlarmFired();
virtual Status informAlarmForSubscriberTriggeringFired();
@@ -404,6 +403,10 @@ private:
FRIEND_TEST(PartialBucketE2eTest, TestGaugeMetricOnBootWithoutMinPartialBucket);
FRIEND_TEST(PartialBucketE2eTest, TestGaugeMetricWithoutMinPartialBucket);
FRIEND_TEST(PartialBucketE2eTest, TestGaugeMetricWithMinPartialBucket);
+
+ FRIEND_TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_single_bucket);
+ FRIEND_TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_multiple_buckets);
+ FRIEND_TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_long_refractory_period);
};
} // namespace statsd
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index e70eac88c769..c95f4c07f86c 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -66,7 +66,7 @@ import "frameworks/base/core/proto/android/stats/textclassifier/textclassifier_e
import "frameworks/base/core/proto/android/stats/otaupdate/updateengine_enums.proto";
/**
- * The master atom class. This message defines all of the available
+ * The primary atom class. This message defines all of the available
* raw stats log events from the Android system, also known as "atoms."
*
* This field contains a single oneof with all of the available messages.
diff --git a/cmds/statsd/src/config/ConfigManager.cpp b/cmds/statsd/src/config/ConfigManager.cpp
index bbae3fef7934..13020e06dc5d 100644
--- a/cmds/statsd/src/config/ConfigManager.cpp
+++ b/cmds/statsd/src/config/ConfigManager.cpp
@@ -128,7 +128,7 @@ void ConfigManager::Startup() {
}
void ConfigManager::StartupForTest() {
- // Dummy function to avoid reading configs from disks for tests.
+ // No-op function to avoid reading configs from disks for tests.
}
void ConfigManager::AddListener(const sp<ConfigListener>& listener) {
diff --git a/cmds/statsd/src/config/ConfigManager.h b/cmds/statsd/src/config/ConfigManager.h
index 40146b1b2bec..bef057f96409 100644
--- a/cmds/statsd/src/config/ConfigManager.h
+++ b/cmds/statsd/src/config/ConfigManager.h
@@ -46,7 +46,7 @@ public:
void Startup();
/*
- * Dummy initializer for tests.
+ * No-op initializer for tests.
*/
void StartupForTest();
diff --git a/cmds/statsd/tests/LogEntryMatcher_test.cpp b/cmds/statsd/tests/LogEntryMatcher_test.cpp
index 26423d464027..6264c075426a 100644
--- a/cmds/statsd/tests/LogEntryMatcher_test.cpp
+++ b/cmds/statsd/tests/LogEntryMatcher_test.cpp
@@ -13,9 +13,6 @@
// limitations under the License.
#include <gtest/gtest.h>
-#include <log/log_event_list.h>
-#include <log/log_read.h>
-#include <log/logprint.h>
#include <stdio.h>
#include "annotations.h"
diff --git a/cmds/statsd/tests/e2e/Anomaly_duration_sum_e2e_test.cpp b/cmds/statsd/tests/e2e/Anomaly_duration_sum_e2e_test.cpp
index 95e301002a1b..70e7365ec238 100644
--- a/cmds/statsd/tests/e2e/Anomaly_duration_sum_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/Anomaly_duration_sum_e2e_test.cpp
@@ -12,14 +12,19 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#include <android/binder_ibinder.h>
+#include <android/binder_interface_utils.h>
#include <gtest/gtest.h>
-#include "src/anomaly/DurationAnomalyTracker.h"
+#include <vector>
+
#include "src/StatsLogProcessor.h"
+#include "src/StatsService.h"
+#include "src/anomaly/DurationAnomalyTracker.h"
#include "src/stats_log_util.h"
#include "tests/statsd_test_util.h"
-#include <vector>
+using ::ndk::SharedRefBase;
namespace android {
namespace os {
@@ -29,6 +34,9 @@ namespace statsd {
namespace {
+const int kConfigKey = 789130124;
+const int kCallingUid = 0;
+
StatsdConfig CreateStatsdConfig(int num_buckets,
uint64_t threshold_ns,
DurationMetric::AggregationType aggregationType,
@@ -89,6 +97,13 @@ MetricDimensionKey dimensionKey2(
(int32_t)0x02010101), Value((int32_t)222))}),
DEFAULT_DIMENSION_KEY);
+void sendConfig(shared_ptr<StatsService>& service, const StatsdConfig& config) {
+ string str;
+ config.SerializeToString(&str);
+ std::vector<uint8_t> configAsVec(str.begin(), str.end());
+ service->addConfiguration(kConfigKey, configAsVec, kCallingUid);
+}
+
} // namespace
TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_single_bucket) {
@@ -98,16 +113,18 @@ TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_single_bucket) {
const uint64_t alert_id = config.alert(0).id();
const uint32_t refractory_period_sec = config.alert(0).refractory_period_secs();
- int64_t bucketStartTimeNs = 10 * NS_PER_SEC;
- int64_t bucketSizeNs =
- TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000;
+ shared_ptr<StatsService> service = SharedRefBase::make<StatsService>(nullptr, nullptr);
+ sendConfig(service, config);
- ConfigKey cfgKey;
- auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
+ auto processor = service->mProcessor;
ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
ASSERT_EQ(1u, processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers.size());
+ int64_t bucketStartTimeNs = processor->mTimeBaseNs;
+ int64_t roundedBucketStartTimeNs = bucketStartTimeNs / NS_PER_SEC * NS_PER_SEC;
+ int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1e6;
+
sp<AnomalyTracker> anomalyTracker =
processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers[0];
@@ -158,12 +175,13 @@ TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_single_bucket) {
const int64_t alarmFiredTimestampSec0 = anomalyTracker->getAlarmTimestampSec(dimensionKey1);
EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + NS_PER_SEC + 109) / NS_PER_SEC + 1,
(uint32_t)alarmFiredTimestampSec0);
+ EXPECT_EQ(alarmFiredTimestampSec0,
+ processor->getAnomalyAlarmMonitor()->getRegisteredAlarmTimeSec());
// Anomaly alarm fired.
- auto alarmSet = processor->getAnomalyAlarmMonitor()->popSoonerThan(
- static_cast<uint32_t>(alarmFiredTimestampSec0));
- ASSERT_EQ(1u, alarmSet.size());
- processor->onAnomalyAlarmFired(alarmFiredTimestampSec0 * NS_PER_SEC, alarmSet);
+ auto alarmTriggerEvent = CreateBatterySaverOnEvent(alarmFiredTimestampSec0 * NS_PER_SEC);
+ processor->OnLogEvent(alarmTriggerEvent.get(), alarmFiredTimestampSec0 * NS_PER_SEC);
+
EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
EXPECT_EQ(refractory_period_sec + alarmFiredTimestampSec0,
anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
@@ -179,39 +197,39 @@ TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_single_bucket) {
anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
// Acquire wakelock wl1.
- acquire_event =
- CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs - 5 * NS_PER_SEC - 11,
- attributionUids2, attributionTags2, "wl1");
+ acquire_event = CreateAcquireWakelockEvent(
+ roundedBucketStartTimeNs + bucketSizeNs - 5 * NS_PER_SEC - 11, attributionUids2,
+ attributionTags2, "wl1");
processor->OnLogEvent(acquire_event.get());
const int64_t alarmFiredTimestampSec1 = anomalyTracker->getAlarmTimestampSec(dimensionKey1);
EXPECT_EQ((bucketStartTimeNs + bucketSizeNs - 5 * NS_PER_SEC) / NS_PER_SEC,
(uint64_t)alarmFiredTimestampSec1);
// Release wakelock wl1.
- release_event =
- CreateReleaseWakelockEvent(bucketStartTimeNs + bucketSizeNs - 4 * NS_PER_SEC - 10,
- attributionUids2, attributionTags2, "wl1");
- processor->OnLogEvent(release_event.get());
+ int64_t release_event_time = roundedBucketStartTimeNs + bucketSizeNs - 4 * NS_PER_SEC - 10;
+ release_event = CreateReleaseWakelockEvent(release_event_time, attributionUids2,
+ attributionTags2, "wl1");
+ processor->OnLogEvent(release_event.get(), release_event_time);
EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
- EXPECT_EQ(refractory_period_sec +
- (bucketStartTimeNs + bucketSizeNs - 4 * NS_PER_SEC - 10) / NS_PER_SEC + 1,
+ EXPECT_EQ(refractory_period_sec + (release_event_time) / NS_PER_SEC + 1,
anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
- alarmSet = processor->getAnomalyAlarmMonitor()->popSoonerThan(
+ auto alarmSet = processor->getAnomalyAlarmMonitor()->popSoonerThan(
static_cast<uint32_t>(alarmFiredTimestampSec1));
ASSERT_EQ(0u, alarmSet.size());
// Acquire wakelock wl1 near the end of bucket #0.
- acquire_event = CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs - 2,
+ acquire_event = CreateAcquireWakelockEvent(roundedBucketStartTimeNs + bucketSizeNs - 2,
attributionUids1, attributionTags1, "wl1");
processor->OnLogEvent(acquire_event.get());
EXPECT_EQ((bucketStartTimeNs + bucketSizeNs) / NS_PER_SEC,
anomalyTracker->getAlarmTimestampSec(dimensionKey1));
// Release the event at early bucket #1.
- release_event = CreateReleaseWakelockEvent(bucketStartTimeNs + bucketSizeNs + NS_PER_SEC - 1,
- attributionUids1, attributionTags1, "wl1");
- processor->OnLogEvent(release_event.get());
+ release_event_time = roundedBucketStartTimeNs + bucketSizeNs + NS_PER_SEC - 1;
+ release_event = CreateReleaseWakelockEvent(release_event_time, attributionUids1,
+ attributionTags1, "wl1");
+ processor->OnLogEvent(release_event.get(), release_event_time);
EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
// Anomaly detected when stopping the alarm. The refractory period does not change.
EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + bucketSizeNs + NS_PER_SEC) / NS_PER_SEC,
@@ -236,17 +254,17 @@ TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_single_bucket) {
// Condition turns true.
screen_off_event =
- CreateScreenStateChangedEvent(bucketStartTimeNs + 2 * bucketSizeNs + NS_PER_SEC,
+ CreateScreenStateChangedEvent(roundedBucketStartTimeNs + 2 * bucketSizeNs + NS_PER_SEC,
android::view::DisplayStateEnum::DISPLAY_STATE_OFF);
processor->OnLogEvent(screen_off_event.get());
EXPECT_EQ((bucketStartTimeNs + 2 * bucketSizeNs + NS_PER_SEC + threshold_ns) / NS_PER_SEC,
anomalyTracker->getAlarmTimestampSec(dimensionKey1));
// Condition turns to false.
- screen_on_event =
- CreateScreenStateChangedEvent(bucketStartTimeNs + 2 * bucketSizeNs + 2 * NS_PER_SEC + 1,
- android::view::DisplayStateEnum::DISPLAY_STATE_ON);
- processor->OnLogEvent(screen_on_event.get());
+ int64_t condition_false_time = bucketStartTimeNs + 2 * bucketSizeNs + 2 * NS_PER_SEC + 1;
+ screen_on_event = CreateScreenStateChangedEvent(
+ condition_false_time, android::view::DisplayStateEnum::DISPLAY_STATE_ON);
+ processor->OnLogEvent(screen_on_event.get(), condition_false_time);
// Condition turns to false. Cancelled the alarm.
EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
// Detected one anomaly.
@@ -262,12 +280,11 @@ TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_single_bucket) {
EXPECT_EQ((bucketStartTimeNs + 2 * bucketSizeNs) / NS_PER_SEC + 2 + 2 + 1,
anomalyTracker->getAlarmTimestampSec(dimensionKey1));
- release_event =
- CreateReleaseWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 5 * NS_PER_SEC,
- attributionUids2, attributionTags2, "wl1");
+ release_event_time = roundedBucketStartTimeNs + 2 * bucketSizeNs + 5 * NS_PER_SEC;
+ release_event = CreateReleaseWakelockEvent(release_event_time, attributionUids2,
+ attributionTags2, "wl1");
processor->OnLogEvent(release_event.get());
- EXPECT_EQ(refractory_period_sec +
- (bucketStartTimeNs + 2 * bucketSizeNs + 5 * NS_PER_SEC) / NS_PER_SEC,
+ EXPECT_EQ(refractory_period_sec + (release_event_time) / NS_PER_SEC,
anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
}
@@ -279,16 +296,18 @@ TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_multiple_buckets) {
const uint64_t alert_id = config.alert(0).id();
const uint32_t refractory_period_sec = config.alert(0).refractory_period_secs();
- int64_t bucketStartTimeNs = 10 * NS_PER_SEC;
- int64_t bucketSizeNs =
- TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000;
+ shared_ptr<StatsService> service = SharedRefBase::make<StatsService>(nullptr, nullptr);
+ sendConfig(service, config);
- ConfigKey cfgKey;
- auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
+ auto processor = service->mProcessor;
ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
ASSERT_EQ(1u, processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers.size());
+ int64_t bucketStartTimeNs = processor->mTimeBaseNs;
+ int64_t roundedBucketStartTimeNs = bucketStartTimeNs / NS_PER_SEC * NS_PER_SEC;
+ int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1e6;
+
sp<AnomalyTracker> anomalyTracker =
processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers[0];
@@ -298,96 +317,97 @@ TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_multiple_buckets) {
// Acquire wakelock "wc1" in bucket #0.
auto acquire_event =
- CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs - NS_PER_SEC / 2 - 1,
+ CreateAcquireWakelockEvent(roundedBucketStartTimeNs + bucketSizeNs - NS_PER_SEC / 2 - 1,
attributionUids1, attributionTags1, "wl1");
processor->OnLogEvent(acquire_event.get());
- EXPECT_EQ((bucketStartTimeNs + bucketSizeNs) / NS_PER_SEC + 1,
+ EXPECT_EQ((roundedBucketStartTimeNs + bucketSizeNs) / NS_PER_SEC + 1,
anomalyTracker->getAlarmTimestampSec(dimensionKey1));
EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
// Release wakelock "wc1" in bucket #0.
- auto release_event = CreateReleaseWakelockEvent(bucketStartTimeNs + bucketSizeNs - 1,
- attributionUids1, attributionTags1, "wl1");
- processor->OnLogEvent(release_event.get());
+ int64_t release_event_time = roundedBucketStartTimeNs + bucketSizeNs - 1;
+ auto release_event = CreateReleaseWakelockEvent(release_event_time, attributionUids1,
+ attributionTags1, "wl1");
+ processor->OnLogEvent(release_event.get(), release_event_time);
EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
// Acquire wakelock "wc1" in bucket #1.
- acquire_event = CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs + 1,
- attributionUids2, attributionTags2, "wl1");
+ acquire_event =
+ CreateAcquireWakelockEvent(roundedBucketStartTimeNs + bucketSizeNs + NS_PER_SEC + 1,
+ attributionUids2, attributionTags2, "wl1");
processor->OnLogEvent(acquire_event.get());
- EXPECT_EQ((bucketStartTimeNs + bucketSizeNs) / NS_PER_SEC + 1,
+ EXPECT_EQ((bucketStartTimeNs + bucketSizeNs + NS_PER_SEC) / NS_PER_SEC + 1,
anomalyTracker->getAlarmTimestampSec(dimensionKey1));
EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
- release_event = CreateReleaseWakelockEvent(bucketStartTimeNs + bucketSizeNs + 100,
- attributionUids2, attributionTags2, "wl1");
- processor->OnLogEvent(release_event.get());
+ release_event_time = roundedBucketStartTimeNs + bucketSizeNs + NS_PER_SEC + 100;
+ release_event = CreateReleaseWakelockEvent(release_event_time, attributionUids2,
+ attributionTags2, "wl1");
+ processor->OnLogEvent(release_event.get(), release_event_time);
EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
// Acquire wakelock "wc2" in bucket #2.
- acquire_event = CreateAcquireWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 1,
- attributionUids3, attributionTags3, "wl2");
+ acquire_event =
+ CreateAcquireWakelockEvent(roundedBucketStartTimeNs + 2 * bucketSizeNs + NS_PER_SEC + 1,
+ attributionUids3, attributionTags3, "wl2");
processor->OnLogEvent(acquire_event.get());
- EXPECT_EQ((bucketStartTimeNs + 2 * bucketSizeNs) / NS_PER_SEC + 2,
+ EXPECT_EQ((bucketStartTimeNs + 2 * bucketSizeNs) / NS_PER_SEC + 3,
anomalyTracker->getAlarmTimestampSec(dimensionKey2));
EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2));
// Release wakelock "wc2" in bucket #2.
- release_event =
- CreateReleaseWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 2 * NS_PER_SEC,
- attributionUids3, attributionTags3, "wl2");
- processor->OnLogEvent(release_event.get());
+ release_event_time = roundedBucketStartTimeNs + 2 * bucketSizeNs + 3 * NS_PER_SEC;
+ release_event = CreateReleaseWakelockEvent(release_event_time, attributionUids3,
+ attributionTags3, "wl2");
+ processor->OnLogEvent(release_event.get(), release_event_time);
EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey2));
- EXPECT_EQ(refractory_period_sec +
- (bucketStartTimeNs + 2 * bucketSizeNs + 2 * NS_PER_SEC) / NS_PER_SEC,
+ EXPECT_EQ(refractory_period_sec + (release_event_time) / NS_PER_SEC,
anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2));
// Acquire wakelock "wc1" in bucket #2.
acquire_event =
- CreateAcquireWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 2 * NS_PER_SEC,
+ CreateAcquireWakelockEvent(roundedBucketStartTimeNs + 2 * bucketSizeNs + 3 * NS_PER_SEC,
attributionUids2, attributionTags2, "wl1");
processor->OnLogEvent(acquire_event.get());
- EXPECT_EQ((bucketStartTimeNs + 2 * bucketSizeNs) / NS_PER_SEC + 2 + 1,
+ EXPECT_EQ((roundedBucketStartTimeNs + 2 * bucketSizeNs) / NS_PER_SEC + 3 + 1,
anomalyTracker->getAlarmTimestampSec(dimensionKey1));
EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
// Release wakelock "wc1" in bucket #2.
- release_event =
- CreateReleaseWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 2.5 * NS_PER_SEC,
- attributionUids2, attributionTags2, "wl1");
- processor->OnLogEvent(release_event.get());
+ release_event_time = roundedBucketStartTimeNs + 2 * bucketSizeNs + 3.5 * NS_PER_SEC;
+ release_event = CreateReleaseWakelockEvent(release_event_time, attributionUids2,
+ attributionTags2, "wl1");
+ processor->OnLogEvent(release_event.get(), release_event_time);
EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
- EXPECT_EQ(refractory_period_sec +
- (int64_t)(bucketStartTimeNs + 2 * bucketSizeNs + 2.5 * NS_PER_SEC) /
- NS_PER_SEC +
- 1,
+ EXPECT_EQ(refractory_period_sec + (release_event_time) / NS_PER_SEC + 1,
anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
- acquire_event =
- CreateAcquireWakelockEvent(bucketStartTimeNs + 6 * bucketSizeNs - NS_PER_SEC + 4,
- attributionUids3, attributionTags3, "wl2");
+ acquire_event = CreateAcquireWakelockEvent(roundedBucketStartTimeNs + 6 * bucketSizeNs + 4,
+ attributionUids3, attributionTags3, "wl2");
processor->OnLogEvent(acquire_event.get());
- acquire_event =
- CreateAcquireWakelockEvent(bucketStartTimeNs + 6 * bucketSizeNs - NS_PER_SEC + 5,
- attributionUids1, attributionTags1, "wl1");
+ acquire_event = CreateAcquireWakelockEvent(roundedBucketStartTimeNs + 6 * bucketSizeNs + 5,
+ attributionUids1, attributionTags1, "wl1");
processor->OnLogEvent(acquire_event.get());
- EXPECT_EQ((bucketStartTimeNs + 6 * bucketSizeNs) / NS_PER_SEC + 1,
+ EXPECT_EQ((roundedBucketStartTimeNs + 6 * bucketSizeNs) / NS_PER_SEC + 2,
anomalyTracker->getAlarmTimestampSec(dimensionKey1));
- EXPECT_EQ((bucketStartTimeNs + 6 * bucketSizeNs) / NS_PER_SEC + 1,
+ EXPECT_EQ((roundedBucketStartTimeNs + 6 * bucketSizeNs) / NS_PER_SEC + 2,
anomalyTracker->getAlarmTimestampSec(dimensionKey2));
- release_event = CreateReleaseWakelockEvent(bucketStartTimeNs + 6 * bucketSizeNs + 2,
- attributionUids3, attributionTags3, "wl2");
- processor->OnLogEvent(release_event.get());
- release_event = CreateReleaseWakelockEvent(bucketStartTimeNs + 6 * bucketSizeNs + 6,
- attributionUids1, attributionTags1, "wl1");
- processor->OnLogEvent(release_event.get());
+ release_event_time = roundedBucketStartTimeNs + 6 * bucketSizeNs + NS_PER_SEC + 2;
+ release_event = CreateReleaseWakelockEvent(release_event_time, attributionUids3,
+ attributionTags3, "wl2");
+ processor->OnLogEvent(release_event.get(), release_event_time);
+ release_event = CreateReleaseWakelockEvent(release_event_time + 4, attributionUids1,
+ attributionTags1, "wl1");
+ processor->OnLogEvent(release_event.get(), release_event_time + 4);
EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey2));
// The buckets are not messed up across dimensions. Only one dimension has anomaly triggered.
- EXPECT_EQ(refractory_period_sec + (int64_t)(bucketStartTimeNs + 6 * bucketSizeNs) / NS_PER_SEC +
+ EXPECT_EQ(refractory_period_sec +
+ (int64_t)(roundedBucketStartTimeNs + 6 * bucketSizeNs + NS_PER_SEC) /
+ NS_PER_SEC +
1,
anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
}
@@ -396,20 +416,22 @@ TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_long_refractory_period) {
const int num_buckets = 2;
const uint64_t threshold_ns = 3 * NS_PER_SEC;
auto config = CreateStatsdConfig(num_buckets, threshold_ns, DurationMetric::SUM, false);
- int64_t bucketStartTimeNs = 10 * NS_PER_SEC;
- int64_t bucketSizeNs =
- TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000;
-
const uint64_t alert_id = config.alert(0).id();
+ int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1e6;
const uint32_t refractory_period_sec = 3 * bucketSizeNs / NS_PER_SEC;
config.mutable_alert(0)->set_refractory_period_secs(refractory_period_sec);
- ConfigKey cfgKey;
- auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
+ shared_ptr<StatsService> service = SharedRefBase::make<StatsService>(nullptr, nullptr);
+ sendConfig(service, config);
+
+ auto processor = service->mProcessor;
ASSERT_EQ(processor->mMetricsManagers.size(), 1u);
EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
ASSERT_EQ(1u, processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers.size());
+ int64_t bucketStartTimeNs = processor->mTimeBaseNs;
+ int64_t roundedBucketStartTimeNs = bucketStartTimeNs / NS_PER_SEC * NS_PER_SEC;
+
sp<AnomalyTracker> anomalyTracker =
processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers[0];
@@ -418,81 +440,81 @@ TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_long_refractory_period) {
processor->OnLogEvent(screen_off_event.get());
// Acquire wakelock "wc1" in bucket #0.
- auto acquire_event = CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs - 100,
+ auto acquire_event = CreateAcquireWakelockEvent(roundedBucketStartTimeNs + bucketSizeNs - 100,
attributionUids1, attributionTags1, "wl1");
processor->OnLogEvent(acquire_event.get());
- EXPECT_EQ((bucketStartTimeNs + bucketSizeNs) / NS_PER_SEC + 3,
+ EXPECT_EQ((roundedBucketStartTimeNs + bucketSizeNs) / NS_PER_SEC + 3,
anomalyTracker->getAlarmTimestampSec(dimensionKey1));
EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
// Acquire the wakelock "wc1" again.
acquire_event =
- CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs + 2 * NS_PER_SEC + 1,
+ CreateAcquireWakelockEvent(roundedBucketStartTimeNs + bucketSizeNs + 2 * NS_PER_SEC + 1,
attributionUids1, attributionTags1, "wl1");
processor->OnLogEvent(acquire_event.get());
// The alarm does not change.
- EXPECT_EQ((bucketStartTimeNs + bucketSizeNs) / NS_PER_SEC + 3,
+ EXPECT_EQ((roundedBucketStartTimeNs + bucketSizeNs) / NS_PER_SEC + 3,
anomalyTracker->getAlarmTimestampSec(dimensionKey1));
EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
// Anomaly alarm fired late.
- const int64_t firedAlarmTimestampNs = bucketStartTimeNs + 2 * bucketSizeNs - NS_PER_SEC;
- auto alarmSet = processor->getAnomalyAlarmMonitor()->popSoonerThan(
- static_cast<uint32_t>(firedAlarmTimestampNs / NS_PER_SEC));
- ASSERT_EQ(1u, alarmSet.size());
- processor->onAnomalyAlarmFired(firedAlarmTimestampNs, alarmSet);
+ const int64_t firedAlarmTimestampNs = roundedBucketStartTimeNs + 2 * bucketSizeNs - NS_PER_SEC;
+ auto alarmTriggerEvent = CreateBatterySaverOnEvent(firedAlarmTimestampNs);
+ processor->OnLogEvent(alarmTriggerEvent.get(), firedAlarmTimestampNs);
EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
EXPECT_EQ(refractory_period_sec + firedAlarmTimestampNs / NS_PER_SEC,
anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
- acquire_event = CreateAcquireWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs - 100,
+ acquire_event = CreateAcquireWakelockEvent(roundedBucketStartTimeNs + 2 * bucketSizeNs - 100,
attributionUids1, attributionTags1, "wl1");
processor->OnLogEvent(acquire_event.get());
EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
EXPECT_EQ(refractory_period_sec + firedAlarmTimestampNs / NS_PER_SEC,
anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
- auto release_event = CreateReleaseWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 1,
- attributionUids1, attributionTags1, "wl1");
- processor->OnLogEvent(release_event.get());
+ int64_t release_event_time = bucketStartTimeNs + 2 * bucketSizeNs + 1;
+ auto release_event = CreateReleaseWakelockEvent(release_event_time, attributionUids1,
+ attributionTags1, "wl1");
+ processor->OnLogEvent(release_event.get(), release_event_time);
EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
// Within the refractory period. No anomaly.
EXPECT_EQ(refractory_period_sec + firedAlarmTimestampNs / NS_PER_SEC,
anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
// A new wakelock, but still within refractory period.
- acquire_event =
- CreateAcquireWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 10 * NS_PER_SEC,
- attributionUids1, attributionTags1, "wl1");
+ acquire_event = CreateAcquireWakelockEvent(
+ roundedBucketStartTimeNs + 2 * bucketSizeNs + 10 * NS_PER_SEC, attributionUids1,
+ attributionTags1, "wl1");
processor->OnLogEvent(acquire_event.get());
EXPECT_EQ(refractory_period_sec + firedAlarmTimestampNs / NS_PER_SEC,
anomalyTracker->getAlarmTimestampSec(dimensionKey1));
- release_event = CreateReleaseWakelockEvent(bucketStartTimeNs + 3 * bucketSizeNs - NS_PER_SEC,
- attributionUids1, attributionTags1, "wl1");
+ release_event =
+ CreateReleaseWakelockEvent(roundedBucketStartTimeNs + 3 * bucketSizeNs - NS_PER_SEC,
+ attributionUids1, attributionTags1, "wl1");
// Still in the refractory period. No anomaly.
processor->OnLogEvent(release_event.get());
EXPECT_EQ(refractory_period_sec + firedAlarmTimestampNs / NS_PER_SEC,
anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
- acquire_event =
- CreateAcquireWakelockEvent(bucketStartTimeNs + 5 * bucketSizeNs - 3 * NS_PER_SEC - 5,
- attributionUids1, attributionTags1, "wl1");
+ acquire_event = CreateAcquireWakelockEvent(
+ roundedBucketStartTimeNs + 5 * bucketSizeNs - 2 * NS_PER_SEC - 5, attributionUids1,
+ attributionTags1, "wl1");
processor->OnLogEvent(acquire_event.get());
- EXPECT_EQ((bucketStartTimeNs + 5 * bucketSizeNs) / NS_PER_SEC,
+ EXPECT_EQ((roundedBucketStartTimeNs + 5 * bucketSizeNs) / NS_PER_SEC + 1,
anomalyTracker->getAlarmTimestampSec(dimensionKey1));
- release_event =
- CreateReleaseWakelockEvent(bucketStartTimeNs + 5 * bucketSizeNs - 3 * NS_PER_SEC - 4,
- attributionUids1, attributionTags1, "wl1");
- processor->OnLogEvent(release_event.get());
+ release_event_time = roundedBucketStartTimeNs + 5 * bucketSizeNs - 2 * NS_PER_SEC - 4;
+ release_event = CreateReleaseWakelockEvent(release_event_time, attributionUids1,
+ attributionTags1, "wl1");
+ processor->OnLogEvent(release_event.get(), release_event_time);
EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
- acquire_event =
- CreateAcquireWakelockEvent(bucketStartTimeNs + 5 * bucketSizeNs - 3 * NS_PER_SEC - 3,
- attributionUids1, attributionTags1, "wl1");
+ acquire_event = CreateAcquireWakelockEvent(
+ roundedBucketStartTimeNs + 5 * bucketSizeNs - 2 * NS_PER_SEC - 3, attributionUids1,
+ attributionTags1, "wl1");
processor->OnLogEvent(acquire_event.get());
- EXPECT_EQ((bucketStartTimeNs + 5 * bucketSizeNs) / NS_PER_SEC,
+ EXPECT_EQ((roundedBucketStartTimeNs + 5 * bucketSizeNs) / NS_PER_SEC + 1,
anomalyTracker->getAlarmTimestampSec(dimensionKey1));
}
diff --git a/cmds/telecom/src/com/android/commands/telecom/Telecom.java b/cmds/telecom/src/com/android/commands/telecom/Telecom.java
index fed9c43faa38..5f13a5ce3aae 100644
--- a/cmds/telecom/src/com/android/commands/telecom/Telecom.java
+++ b/cmds/telecom/src/com/android/commands/telecom/Telecom.java
@@ -69,6 +69,7 @@ public final class Telecom extends BaseCommand {
private static final String COMMAND_SET_DEFAULT_DIALER = "set-default-dialer";
private static final String COMMAND_GET_DEFAULT_DIALER = "get-default-dialer";
private static final String COMMAND_STOP_BLOCK_SUPPRESSION = "stop-block-suppression";
+ private static final String COMMAND_CLEANUP_STUCK_CALLS = "cleanup-stuck-calls";
/**
* Change the system dialer package name if a package name was specified,
@@ -119,6 +120,8 @@ public final class Telecom extends BaseCommand {
+ "usage: telecom get-max-phones\n"
+ "usage: telecom stop-block-suppression: Stop suppressing the blocked number"
+ " provider after a call to emergency services.\n"
+ + "usage: telecom cleanup-stuck-calls: Clear any disconnected calls that have"
+ + " gotten wedged in Telecom.\n"
+ "usage: telecom set-emer-phone-account-filter <PACKAGE>\n"
+ "\n"
+ "telecom set-phone-account-enabled: Enables the given phone account, if it has"
@@ -214,6 +217,9 @@ public final class Telecom extends BaseCommand {
case COMMAND_STOP_BLOCK_SUPPRESSION:
runStopBlockSuppression();
break;
+ case COMMAND_CLEANUP_STUCK_CALLS:
+ runCleanupStuckCalls();
+ break;
case COMMAND_SET_DEFAULT_DIALER:
runSetDefaultDialer();
break;
@@ -335,6 +341,10 @@ public final class Telecom extends BaseCommand {
mTelecomService.stopBlockSuppression();
}
+ private void runCleanupStuckCalls() throws RemoteException {
+ mTelecomService.cleanupStuckCalls();
+ }
+
private void runSetDefaultDialer() throws RemoteException {
String packageName = nextArg();
if ("default".equals(packageName)) packageName = null;
diff --git a/cmds/uiautomator/api/current.txt b/cmds/uiautomator/api/current.txt
index 489c2eadfd91..bf87d091934e 100644
--- a/cmds/uiautomator/api/current.txt
+++ b/cmds/uiautomator/api/current.txt
@@ -1,221 +1,222 @@
+// Signature format: 2.0
package com.android.uiautomator.core {
- public final deprecated class Configurator {
- method public long getActionAcknowledgmentTimeout();
- method public static com.android.uiautomator.core.Configurator getInstance();
- method public long getKeyInjectionDelay();
- method public long getScrollAcknowledgmentTimeout();
- method public long getWaitForIdleTimeout();
- method public long getWaitForSelectorTimeout();
- method public com.android.uiautomator.core.Configurator setActionAcknowledgmentTimeout(long);
- method public com.android.uiautomator.core.Configurator setKeyInjectionDelay(long);
- method public com.android.uiautomator.core.Configurator setScrollAcknowledgmentTimeout(long);
- method public com.android.uiautomator.core.Configurator setWaitForIdleTimeout(long);
- method public com.android.uiautomator.core.Configurator setWaitForSelectorTimeout(long);
+ @Deprecated public final class Configurator {
+ method @Deprecated public long getActionAcknowledgmentTimeout();
+ method @Deprecated public static com.android.uiautomator.core.Configurator getInstance();
+ method @Deprecated public long getKeyInjectionDelay();
+ method @Deprecated public long getScrollAcknowledgmentTimeout();
+ method @Deprecated public long getWaitForIdleTimeout();
+ method @Deprecated public long getWaitForSelectorTimeout();
+ method @Deprecated public com.android.uiautomator.core.Configurator setActionAcknowledgmentTimeout(long);
+ method @Deprecated public com.android.uiautomator.core.Configurator setKeyInjectionDelay(long);
+ method @Deprecated public com.android.uiautomator.core.Configurator setScrollAcknowledgmentTimeout(long);
+ method @Deprecated public com.android.uiautomator.core.Configurator setWaitForIdleTimeout(long);
+ method @Deprecated public com.android.uiautomator.core.Configurator setWaitForSelectorTimeout(long);
}
- public deprecated class UiCollection extends com.android.uiautomator.core.UiObject {
- ctor public UiCollection(com.android.uiautomator.core.UiSelector);
- method public com.android.uiautomator.core.UiObject getChildByDescription(com.android.uiautomator.core.UiSelector, java.lang.String) throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public com.android.uiautomator.core.UiObject getChildByInstance(com.android.uiautomator.core.UiSelector, int) throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public com.android.uiautomator.core.UiObject getChildByText(com.android.uiautomator.core.UiSelector, java.lang.String) throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public int getChildCount(com.android.uiautomator.core.UiSelector);
+ @Deprecated public class UiCollection extends com.android.uiautomator.core.UiObject {
+ ctor @Deprecated public UiCollection(com.android.uiautomator.core.UiSelector);
+ method @Deprecated public com.android.uiautomator.core.UiObject getChildByDescription(com.android.uiautomator.core.UiSelector, String) throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public com.android.uiautomator.core.UiObject getChildByInstance(com.android.uiautomator.core.UiSelector, int) throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public com.android.uiautomator.core.UiObject getChildByText(com.android.uiautomator.core.UiSelector, String) throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public int getChildCount(com.android.uiautomator.core.UiSelector);
}
- public deprecated class UiDevice {
- method public void clearLastTraversedText();
- method public boolean click(int, int);
- method public boolean drag(int, int, int, int, int);
- method public void dumpWindowHierarchy(java.lang.String);
- method public void freezeRotation() throws android.os.RemoteException;
- method public deprecated java.lang.String getCurrentActivityName();
- method public java.lang.String getCurrentPackageName();
- method public int getDisplayHeight();
- method public int getDisplayRotation();
- method public android.graphics.Point getDisplaySizeDp();
- method public int getDisplayWidth();
- method public static com.android.uiautomator.core.UiDevice getInstance();
- method public java.lang.String getLastTraversedText();
- method public java.lang.String getProductName();
- method public boolean hasAnyWatcherTriggered();
- method public boolean hasWatcherTriggered(java.lang.String);
- method public boolean isNaturalOrientation();
- method public boolean isScreenOn() throws android.os.RemoteException;
- method public boolean openNotification();
- method public boolean openQuickSettings();
- method public boolean pressBack();
- method public boolean pressDPadCenter();
- method public boolean pressDPadDown();
- method public boolean pressDPadLeft();
- method public boolean pressDPadRight();
- method public boolean pressDPadUp();
- method public boolean pressDelete();
- method public boolean pressEnter();
- method public boolean pressHome();
- method public boolean pressKeyCode(int);
- method public boolean pressKeyCode(int, int);
- method public boolean pressMenu();
- method public boolean pressRecentApps() throws android.os.RemoteException;
- method public boolean pressSearch();
- method public void registerWatcher(java.lang.String, com.android.uiautomator.core.UiWatcher);
- method public void removeWatcher(java.lang.String);
- method public void resetWatcherTriggers();
- method public void runWatchers();
- method public void setCompressedLayoutHeirarchy(boolean);
- method public void setOrientationLeft() throws android.os.RemoteException;
- method public void setOrientationNatural() throws android.os.RemoteException;
- method public void setOrientationRight() throws android.os.RemoteException;
- method public void sleep() throws android.os.RemoteException;
- method public boolean swipe(int, int, int, int, int);
- method public boolean swipe(android.graphics.Point[], int);
- method public boolean takeScreenshot(java.io.File);
- method public boolean takeScreenshot(java.io.File, float, int);
- method public void unfreezeRotation() throws android.os.RemoteException;
- method public void waitForIdle();
- method public void waitForIdle(long);
- method public boolean waitForWindowUpdate(java.lang.String, long);
- method public void wakeUp() throws android.os.RemoteException;
+ @Deprecated public class UiDevice {
+ method @Deprecated public void clearLastTraversedText();
+ method @Deprecated public boolean click(int, int);
+ method @Deprecated public boolean drag(int, int, int, int, int);
+ method @Deprecated public void dumpWindowHierarchy(String);
+ method @Deprecated public void freezeRotation() throws android.os.RemoteException;
+ method @Deprecated public String getCurrentActivityName();
+ method @Deprecated public String getCurrentPackageName();
+ method @Deprecated public int getDisplayHeight();
+ method @Deprecated public int getDisplayRotation();
+ method @Deprecated public android.graphics.Point getDisplaySizeDp();
+ method @Deprecated public int getDisplayWidth();
+ method @Deprecated public static com.android.uiautomator.core.UiDevice getInstance();
+ method @Deprecated public String getLastTraversedText();
+ method @Deprecated public String getProductName();
+ method @Deprecated public boolean hasAnyWatcherTriggered();
+ method @Deprecated public boolean hasWatcherTriggered(String);
+ method @Deprecated public boolean isNaturalOrientation();
+ method @Deprecated public boolean isScreenOn() throws android.os.RemoteException;
+ method @Deprecated public boolean openNotification();
+ method @Deprecated public boolean openQuickSettings();
+ method @Deprecated public boolean pressBack();
+ method @Deprecated public boolean pressDPadCenter();
+ method @Deprecated public boolean pressDPadDown();
+ method @Deprecated public boolean pressDPadLeft();
+ method @Deprecated public boolean pressDPadRight();
+ method @Deprecated public boolean pressDPadUp();
+ method @Deprecated public boolean pressDelete();
+ method @Deprecated public boolean pressEnter();
+ method @Deprecated public boolean pressHome();
+ method @Deprecated public boolean pressKeyCode(int);
+ method @Deprecated public boolean pressKeyCode(int, int);
+ method @Deprecated public boolean pressMenu();
+ method @Deprecated public boolean pressRecentApps() throws android.os.RemoteException;
+ method @Deprecated public boolean pressSearch();
+ method @Deprecated public void registerWatcher(String, com.android.uiautomator.core.UiWatcher);
+ method @Deprecated public void removeWatcher(String);
+ method @Deprecated public void resetWatcherTriggers();
+ method @Deprecated public void runWatchers();
+ method @Deprecated public void setCompressedLayoutHeirarchy(boolean);
+ method @Deprecated public void setOrientationLeft() throws android.os.RemoteException;
+ method @Deprecated public void setOrientationNatural() throws android.os.RemoteException;
+ method @Deprecated public void setOrientationRight() throws android.os.RemoteException;
+ method @Deprecated public void sleep() throws android.os.RemoteException;
+ method @Deprecated public boolean swipe(int, int, int, int, int);
+ method @Deprecated public boolean swipe(android.graphics.Point[], int);
+ method @Deprecated public boolean takeScreenshot(java.io.File);
+ method @Deprecated public boolean takeScreenshot(java.io.File, float, int);
+ method @Deprecated public void unfreezeRotation() throws android.os.RemoteException;
+ method @Deprecated public void waitForIdle();
+ method @Deprecated public void waitForIdle(long);
+ method @Deprecated public boolean waitForWindowUpdate(String, long);
+ method @Deprecated public void wakeUp() throws android.os.RemoteException;
}
- public deprecated class UiObject {
- ctor public UiObject(com.android.uiautomator.core.UiSelector);
- method public void clearTextField() throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public boolean click() throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public boolean clickAndWaitForNewWindow() throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public boolean clickAndWaitForNewWindow(long) throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public boolean clickBottomRight() throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public boolean clickTopLeft() throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public boolean dragTo(com.android.uiautomator.core.UiObject, int) throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public boolean dragTo(int, int, int) throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public boolean exists();
- method protected android.view.accessibility.AccessibilityNodeInfo findAccessibilityNodeInfo(long);
- method public android.graphics.Rect getBounds() throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public com.android.uiautomator.core.UiObject getChild(com.android.uiautomator.core.UiSelector) throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public int getChildCount() throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public java.lang.String getClassName() throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public java.lang.String getContentDescription() throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public com.android.uiautomator.core.UiObject getFromParent(com.android.uiautomator.core.UiSelector) throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public java.lang.String getPackageName() throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public final com.android.uiautomator.core.UiSelector getSelector();
- method public java.lang.String getText() throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public android.graphics.Rect getVisibleBounds() throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public boolean isCheckable() throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public boolean isChecked() throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public boolean isClickable() throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public boolean isEnabled() throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public boolean isFocusable() throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public boolean isFocused() throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public boolean isLongClickable() throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public boolean isScrollable() throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public boolean isSelected() throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public boolean longClick() throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public boolean longClickBottomRight() throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public boolean longClickTopLeft() throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public boolean performMultiPointerGesture(android.view.MotionEvent.PointerCoords...);
- method public boolean performTwoPointerGesture(android.graphics.Point, android.graphics.Point, android.graphics.Point, android.graphics.Point, int);
- method public boolean pinchIn(int, int) throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public boolean pinchOut(int, int) throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public boolean setText(java.lang.String) throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public boolean swipeDown(int) throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public boolean swipeLeft(int) throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public boolean swipeRight(int) throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public boolean swipeUp(int) throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public boolean waitForExists(long);
- method public boolean waitUntilGone(long);
- field protected static final int FINGER_TOUCH_HALF_WIDTH = 20; // 0x14
- field protected static final int SWIPE_MARGIN_LIMIT = 5; // 0x5
- field protected static final deprecated long WAIT_FOR_EVENT_TMEOUT = 3000L; // 0xbb8L
- field protected static final long WAIT_FOR_SELECTOR_POLL = 1000L; // 0x3e8L
- field protected static final deprecated long WAIT_FOR_SELECTOR_TIMEOUT = 10000L; // 0x2710L
- field protected static final long WAIT_FOR_WINDOW_TMEOUT = 5500L; // 0x157cL
+ @Deprecated public class UiObject {
+ ctor @Deprecated public UiObject(com.android.uiautomator.core.UiSelector);
+ method @Deprecated public void clearTextField() throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public boolean click() throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public boolean clickAndWaitForNewWindow() throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public boolean clickAndWaitForNewWindow(long) throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public boolean clickBottomRight() throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public boolean clickTopLeft() throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public boolean dragTo(com.android.uiautomator.core.UiObject, int) throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public boolean dragTo(int, int, int) throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public boolean exists();
+ method @Deprecated protected android.view.accessibility.AccessibilityNodeInfo findAccessibilityNodeInfo(long);
+ method @Deprecated public android.graphics.Rect getBounds() throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public com.android.uiautomator.core.UiObject getChild(com.android.uiautomator.core.UiSelector) throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public int getChildCount() throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public String getClassName() throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public String getContentDescription() throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public com.android.uiautomator.core.UiObject getFromParent(com.android.uiautomator.core.UiSelector) throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public String getPackageName() throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public final com.android.uiautomator.core.UiSelector getSelector();
+ method @Deprecated public String getText() throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public android.graphics.Rect getVisibleBounds() throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public boolean isCheckable() throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public boolean isChecked() throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public boolean isClickable() throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public boolean isEnabled() throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public boolean isFocusable() throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public boolean isFocused() throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public boolean isLongClickable() throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public boolean isScrollable() throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public boolean isSelected() throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public boolean longClick() throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public boolean longClickBottomRight() throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public boolean longClickTopLeft() throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public boolean performMultiPointerGesture(android.view.MotionEvent.PointerCoords[]...);
+ method @Deprecated public boolean performTwoPointerGesture(android.graphics.Point, android.graphics.Point, android.graphics.Point, android.graphics.Point, int);
+ method @Deprecated public boolean pinchIn(int, int) throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public boolean pinchOut(int, int) throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public boolean setText(String) throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public boolean swipeDown(int) throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public boolean swipeLeft(int) throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public boolean swipeRight(int) throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public boolean swipeUp(int) throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public boolean waitForExists(long);
+ method @Deprecated public boolean waitUntilGone(long);
+ field @Deprecated protected static final int FINGER_TOUCH_HALF_WIDTH = 20; // 0x14
+ field @Deprecated protected static final int SWIPE_MARGIN_LIMIT = 5; // 0x5
+ field @Deprecated protected static final long WAIT_FOR_EVENT_TMEOUT = 3000L; // 0xbb8L
+ field @Deprecated protected static final long WAIT_FOR_SELECTOR_POLL = 1000L; // 0x3e8L
+ field @Deprecated protected static final long WAIT_FOR_SELECTOR_TIMEOUT = 10000L; // 0x2710L
+ field @Deprecated protected static final long WAIT_FOR_WINDOW_TMEOUT = 5500L; // 0x157cL
}
- public deprecated class UiObjectNotFoundException extends java.lang.Exception {
- ctor public UiObjectNotFoundException(java.lang.String);
- ctor public UiObjectNotFoundException(java.lang.String, java.lang.Throwable);
- ctor public UiObjectNotFoundException(java.lang.Throwable);
+ @Deprecated public class UiObjectNotFoundException extends java.lang.Exception {
+ ctor @Deprecated public UiObjectNotFoundException(String);
+ ctor @Deprecated public UiObjectNotFoundException(String, Throwable);
+ ctor @Deprecated public UiObjectNotFoundException(Throwable);
}
- public deprecated class UiScrollable extends com.android.uiautomator.core.UiCollection {
- ctor public UiScrollable(com.android.uiautomator.core.UiSelector);
- method protected boolean exists(com.android.uiautomator.core.UiSelector);
- method public boolean flingBackward() throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public boolean flingForward() throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public boolean flingToBeginning(int) throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public boolean flingToEnd(int) throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public com.android.uiautomator.core.UiObject getChildByDescription(com.android.uiautomator.core.UiSelector, java.lang.String, boolean) throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public com.android.uiautomator.core.UiObject getChildByText(com.android.uiautomator.core.UiSelector, java.lang.String, boolean) throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public int getMaxSearchSwipes();
- method public double getSwipeDeadZonePercentage();
- method public boolean scrollBackward() throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public boolean scrollBackward(int) throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public boolean scrollDescriptionIntoView(java.lang.String) throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public boolean scrollForward() throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public boolean scrollForward(int) throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public boolean scrollIntoView(com.android.uiautomator.core.UiObject) throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public boolean scrollIntoView(com.android.uiautomator.core.UiSelector) throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public boolean scrollTextIntoView(java.lang.String) throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public boolean scrollToBeginning(int, int) throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public boolean scrollToBeginning(int) throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public boolean scrollToEnd(int, int) throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public boolean scrollToEnd(int) throws com.android.uiautomator.core.UiObjectNotFoundException;
- method public com.android.uiautomator.core.UiScrollable setAsHorizontalList();
- method public com.android.uiautomator.core.UiScrollable setAsVerticalList();
- method public com.android.uiautomator.core.UiScrollable setMaxSearchSwipes(int);
- method public com.android.uiautomator.core.UiScrollable setSwipeDeadZonePercentage(double);
+ @Deprecated public class UiScrollable extends com.android.uiautomator.core.UiCollection {
+ ctor @Deprecated public UiScrollable(com.android.uiautomator.core.UiSelector);
+ method @Deprecated protected boolean exists(com.android.uiautomator.core.UiSelector);
+ method @Deprecated public boolean flingBackward() throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public boolean flingForward() throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public boolean flingToBeginning(int) throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public boolean flingToEnd(int) throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public com.android.uiautomator.core.UiObject getChildByDescription(com.android.uiautomator.core.UiSelector, String, boolean) throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public com.android.uiautomator.core.UiObject getChildByText(com.android.uiautomator.core.UiSelector, String, boolean) throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public int getMaxSearchSwipes();
+ method @Deprecated public double getSwipeDeadZonePercentage();
+ method @Deprecated public boolean scrollBackward() throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public boolean scrollBackward(int) throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public boolean scrollDescriptionIntoView(String) throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public boolean scrollForward() throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public boolean scrollForward(int) throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public boolean scrollIntoView(com.android.uiautomator.core.UiObject) throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public boolean scrollIntoView(com.android.uiautomator.core.UiSelector) throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public boolean scrollTextIntoView(String) throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public boolean scrollToBeginning(int, int) throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public boolean scrollToBeginning(int) throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public boolean scrollToEnd(int, int) throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public boolean scrollToEnd(int) throws com.android.uiautomator.core.UiObjectNotFoundException;
+ method @Deprecated public com.android.uiautomator.core.UiScrollable setAsHorizontalList();
+ method @Deprecated public com.android.uiautomator.core.UiScrollable setAsVerticalList();
+ method @Deprecated public com.android.uiautomator.core.UiScrollable setMaxSearchSwipes(int);
+ method @Deprecated public com.android.uiautomator.core.UiScrollable setSwipeDeadZonePercentage(double);
}
- public deprecated class UiSelector {
- ctor public UiSelector();
- method public com.android.uiautomator.core.UiSelector checkable(boolean);
- method public com.android.uiautomator.core.UiSelector checked(boolean);
- method public com.android.uiautomator.core.UiSelector childSelector(com.android.uiautomator.core.UiSelector);
- method public com.android.uiautomator.core.UiSelector className(java.lang.String);
- method public <T> com.android.uiautomator.core.UiSelector className(java.lang.Class<T>);
- method public com.android.uiautomator.core.UiSelector classNameMatches(java.lang.String);
- method public com.android.uiautomator.core.UiSelector clickable(boolean);
- method protected com.android.uiautomator.core.UiSelector cloneSelector();
- method public com.android.uiautomator.core.UiSelector description(java.lang.String);
- method public com.android.uiautomator.core.UiSelector descriptionContains(java.lang.String);
- method public com.android.uiautomator.core.UiSelector descriptionMatches(java.lang.String);
- method public com.android.uiautomator.core.UiSelector descriptionStartsWith(java.lang.String);
- method public com.android.uiautomator.core.UiSelector enabled(boolean);
- method public com.android.uiautomator.core.UiSelector focusable(boolean);
- method public com.android.uiautomator.core.UiSelector focused(boolean);
- method public com.android.uiautomator.core.UiSelector fromParent(com.android.uiautomator.core.UiSelector);
- method public com.android.uiautomator.core.UiSelector index(int);
- method public com.android.uiautomator.core.UiSelector instance(int);
- method public com.android.uiautomator.core.UiSelector longClickable(boolean);
- method public com.android.uiautomator.core.UiSelector packageName(java.lang.String);
- method public com.android.uiautomator.core.UiSelector packageNameMatches(java.lang.String);
- method public com.android.uiautomator.core.UiSelector resourceId(java.lang.String);
- method public com.android.uiautomator.core.UiSelector resourceIdMatches(java.lang.String);
- method public com.android.uiautomator.core.UiSelector scrollable(boolean);
- method public com.android.uiautomator.core.UiSelector selected(boolean);
- method public com.android.uiautomator.core.UiSelector text(java.lang.String);
- method public com.android.uiautomator.core.UiSelector textContains(java.lang.String);
- method public com.android.uiautomator.core.UiSelector textMatches(java.lang.String);
- method public com.android.uiautomator.core.UiSelector textStartsWith(java.lang.String);
+ @Deprecated public class UiSelector {
+ ctor @Deprecated public UiSelector();
+ method @Deprecated public com.android.uiautomator.core.UiSelector checkable(boolean);
+ method @Deprecated public com.android.uiautomator.core.UiSelector checked(boolean);
+ method @Deprecated public com.android.uiautomator.core.UiSelector childSelector(com.android.uiautomator.core.UiSelector);
+ method @Deprecated public com.android.uiautomator.core.UiSelector className(String);
+ method @Deprecated public <T> com.android.uiautomator.core.UiSelector className(Class<T>);
+ method @Deprecated public com.android.uiautomator.core.UiSelector classNameMatches(String);
+ method @Deprecated public com.android.uiautomator.core.UiSelector clickable(boolean);
+ method @Deprecated protected com.android.uiautomator.core.UiSelector cloneSelector();
+ method @Deprecated public com.android.uiautomator.core.UiSelector description(String);
+ method @Deprecated public com.android.uiautomator.core.UiSelector descriptionContains(String);
+ method @Deprecated public com.android.uiautomator.core.UiSelector descriptionMatches(String);
+ method @Deprecated public com.android.uiautomator.core.UiSelector descriptionStartsWith(String);
+ method @Deprecated public com.android.uiautomator.core.UiSelector enabled(boolean);
+ method @Deprecated public com.android.uiautomator.core.UiSelector focusable(boolean);
+ method @Deprecated public com.android.uiautomator.core.UiSelector focused(boolean);
+ method @Deprecated public com.android.uiautomator.core.UiSelector fromParent(com.android.uiautomator.core.UiSelector);
+ method @Deprecated public com.android.uiautomator.core.UiSelector index(int);
+ method @Deprecated public com.android.uiautomator.core.UiSelector instance(int);
+ method @Deprecated public com.android.uiautomator.core.UiSelector longClickable(boolean);
+ method @Deprecated public com.android.uiautomator.core.UiSelector packageName(String);
+ method @Deprecated public com.android.uiautomator.core.UiSelector packageNameMatches(String);
+ method @Deprecated public com.android.uiautomator.core.UiSelector resourceId(String);
+ method @Deprecated public com.android.uiautomator.core.UiSelector resourceIdMatches(String);
+ method @Deprecated public com.android.uiautomator.core.UiSelector scrollable(boolean);
+ method @Deprecated public com.android.uiautomator.core.UiSelector selected(boolean);
+ method @Deprecated public com.android.uiautomator.core.UiSelector text(String);
+ method @Deprecated public com.android.uiautomator.core.UiSelector textContains(String);
+ method @Deprecated public com.android.uiautomator.core.UiSelector textMatches(String);
+ method @Deprecated public com.android.uiautomator.core.UiSelector textStartsWith(String);
}
- public abstract deprecated interface UiWatcher {
- method public abstract boolean checkForCondition();
+ @Deprecated public interface UiWatcher {
+ method @Deprecated public boolean checkForCondition();
}
}
package com.android.uiautomator.testrunner {
- public abstract deprecated interface IAutomationSupport {
- method public abstract void sendStatus(int, android.os.Bundle);
+ @Deprecated public interface IAutomationSupport {
+ method @Deprecated public void sendStatus(int, android.os.Bundle);
}
- public deprecated class UiAutomatorTestCase extends junit.framework.TestCase {
- ctor public UiAutomatorTestCase();
- method public com.android.uiautomator.testrunner.IAutomationSupport getAutomationSupport();
- method public android.os.Bundle getParams();
- method public com.android.uiautomator.core.UiDevice getUiDevice();
- method public void sleep(long);
+ @Deprecated public class UiAutomatorTestCase extends junit.framework.TestCase {
+ ctor @Deprecated public UiAutomatorTestCase();
+ method @Deprecated public com.android.uiautomator.testrunner.IAutomationSupport getAutomationSupport();
+ method @Deprecated public android.os.Bundle getParams();
+ method @Deprecated public com.android.uiautomator.core.UiDevice getUiDevice();
+ method @Deprecated public void sleep(long);
}
}
diff --git a/cmds/uiautomator/api/removed.txt b/cmds/uiautomator/api/removed.txt
index e69de29bb2d1..d802177e249b 100644
--- a/cmds/uiautomator/api/removed.txt
+++ b/cmds/uiautomator/api/removed.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/cmds/uiautomator/library/Android.bp b/cmds/uiautomator/library/Android.bp
index c33d31f576a3..04b00cb837b2 100644
--- a/cmds/uiautomator/library/Android.bp
+++ b/cmds/uiautomator/library/Android.bp
@@ -12,8 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-droiddoc {
- name: "uiautomator-stubs-docs",
+droidstubs {
+ name: "uiautomator-stubs",
srcs: [
"core-src/**/*.java",
"testrunner-src/**/*.java",
@@ -24,10 +24,10 @@ droiddoc {
"android.test.base",
"unsupportedappusage",
],
- custom_template: "droiddoc-templates-sdk",
installable: false,
- args: "-stubpackages com.android.uiautomator.core:" +
- "com.android.uiautomator.testrunner",
+ flags: [
+ "-stubpackages com.android.uiautomator.core:com.android.uiautomator.testrunner",
+ ],
check_api: {
current: {
@@ -41,10 +41,26 @@ droiddoc {
},
}
+droiddoc {
+ name: "uiautomator-stubs-docs",
+ srcs: [
+ ":uiautomator-stubs",
+ ],
+ libs: [
+ "android.test.runner",
+ "junit",
+ "android.test.base",
+ "unsupportedappusage",
+ ],
+ installable: false,
+ custom_template: "droiddoc-templates-sdk",
+ create_stubs: false,
+}
+
java_library_static {
name: "android_uiautomator",
srcs: [
- ":uiautomator-stubs-docs",
+ ":uiautomator-stubs",
],
libs: [
"android.test.runner",
@@ -64,7 +80,7 @@ java_library_static {
],
static_libs: [
"junit",
- ]
+ ],
}
java_library_static {
diff --git a/cmds/uiautomator/library/testrunner-src/com/android/uiautomator/core/UiAutomationShellWrapper.java b/cmds/uiautomator/library/testrunner-src/com/android/uiautomator/core/UiAutomationShellWrapper.java
index 71561c3c7023..39248730802f 100644
--- a/cmds/uiautomator/library/testrunner-src/com/android/uiautomator/core/UiAutomationShellWrapper.java
+++ b/cmds/uiautomator/library/testrunner-src/com/android/uiautomator/core/UiAutomationShellWrapper.java
@@ -49,7 +49,7 @@ public class UiAutomationShellWrapper {
}
try {
if (isSet) {
- am.setActivityController(new DummyActivityController(), true);
+ am.setActivityController(new NoOpActivityController(), true);
} else {
am.setActivityController(null, true);
}
@@ -80,9 +80,9 @@ public class UiAutomationShellWrapper {
}
/**
- * Dummy, no interference, activity controller.
+ * No-op, no interference, activity controller.
*/
- private class DummyActivityController extends IActivityController.Stub {
+ private class NoOpActivityController extends IActivityController.Stub {
@Override
public boolean activityStarting(Intent intent, String pkg) throws RemoteException {
/* do nothing and let activity proceed normally */
diff --git a/cmds/uiautomator/library/testrunner-src/com/android/uiautomator/testrunner/UiAutomatorTestCase.java b/cmds/uiautomator/library/testrunner-src/com/android/uiautomator/testrunner/UiAutomatorTestCase.java
index d862e1c2babb..e6fb7aa76e58 100644
--- a/cmds/uiautomator/library/testrunner-src/com/android/uiautomator/testrunner/UiAutomatorTestCase.java
+++ b/cmds/uiautomator/library/testrunner-src/com/android/uiautomator/testrunner/UiAutomatorTestCase.java
@@ -45,7 +45,7 @@ import java.util.List;
public class UiAutomatorTestCase extends TestCase {
private static final String DISABLE_IME = "disable_ime";
- private static final String DUMMY_IME_PACKAGE = "com.android.testing.dummyime";
+ private static final String STUB_IME_PACKAGE = "com.android.testing.stubime";
private static final int NOT_A_SUBTYPE_ID = -1;
private UiDevice mUiDevice;
@@ -58,7 +58,7 @@ public class UiAutomatorTestCase extends TestCase {
super.setUp();
mShouldDisableIme = "true".equals(mParams.getString(DISABLE_IME));
if (mShouldDisableIme) {
- setDummyIme();
+ setStubIme();
}
}
@@ -128,7 +128,7 @@ public class UiAutomatorTestCase extends TestCase {
SystemClock.sleep(ms);
}
- private void setDummyIme() {
+ private void setStubIme() {
Context context = ActivityThread.currentApplication();
if (context == null) {
throw new RuntimeException("ActivityThread.currentApplication() is null.");
@@ -138,13 +138,13 @@ public class UiAutomatorTestCase extends TestCase {
List<InputMethodInfo> infos = im.getInputMethodList();
String id = null;
for (InputMethodInfo info : infos) {
- if (DUMMY_IME_PACKAGE.equals(info.getComponent().getPackageName())) {
+ if (STUB_IME_PACKAGE.equals(info.getComponent().getPackageName())) {
id = info.getId();
}
}
if (id == null) {
throw new RuntimeException(String.format(
- "Required testing fixture missing: IME package (%s)", DUMMY_IME_PACKAGE));
+ "Required testing fixture missing: IME package (%s)", STUB_IME_PACKAGE));
}
if (context.checkSelfPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
!= PackageManager.PERMISSION_GRANTED) {
diff --git a/config/preloaded-classes b/config/preloaded-classes
index 881cfa335700..e43c7d42868c 100644
--- a/config/preloaded-classes
+++ b/config/preloaded-classes
@@ -417,9 +417,6 @@ android.app.INotificationManager
android.app.IProcessObserver$Stub$Proxy
android.app.IProcessObserver$Stub
android.app.IProcessObserver
-android.app.IRequestFinishCallback$Stub$Proxy
-android.app.IRequestFinishCallback$Stub
-android.app.IRequestFinishCallback
android.app.ISearchManager$Stub$Proxy
android.app.ISearchManager$Stub
android.app.ISearchManager
diff --git a/core/java/android/animation/AnimatorSet.java b/core/java/android/animation/AnimatorSet.java
index 35cf39f1b056..a9239b48bb3f 100644
--- a/core/java/android/animation/AnimatorSet.java
+++ b/core/java/android/animation/AnimatorSet.java
@@ -183,7 +183,7 @@ public final class AnimatorSet extends Animator implements AnimationHandler.Anim
// This is to work around a bug in b/34736819. This needs to be removed once app team
// fixes their side.
- private AnimatorListenerAdapter mDummyListener = new AnimatorListenerAdapter() {
+ private AnimatorListenerAdapter mAnimationEndingListener = new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
if (mNodeMap.get(animation) == null) {
@@ -1186,7 +1186,7 @@ public final class AnimatorSet extends Animator implements AnimationHandler.Anim
}
private void startAnimation() {
- addDummyListener();
+ addAnimationEndingListener();
// Register animation callback
addAnimationCallback(0);
@@ -1243,15 +1243,15 @@ public final class AnimatorSet extends Animator implements AnimationHandler.Anim
// This is to work around the issue in b/34736819, as the old behavior in AnimatorSet had
// masked a real bug in play movies. TODO: remove this and below once the root cause is fixed.
- private void addDummyListener() {
+ private void addAnimationEndingListener() {
for (int i = 1; i < mNodes.size(); i++) {
- mNodes.get(i).mAnimation.addListener(mDummyListener);
+ mNodes.get(i).mAnimation.addListener(mAnimationEndingListener);
}
}
- private void removeDummyListener() {
+ private void removeAnimationEndingListener() {
for (int i = 1; i < mNodes.size(); i++) {
- mNodes.get(i).mAnimation.removeListener(mDummyListener);
+ mNodes.get(i).mAnimation.removeListener(mAnimationEndingListener);
}
}
@@ -1301,7 +1301,7 @@ public final class AnimatorSet extends Animator implements AnimationHandler.Anim
tmpListeners.get(i).onAnimationEnd(this, mReversing);
}
}
- removeDummyListener();
+ removeAnimationEndingListener();
mSelfPulse = true;
mReversing = false;
}
@@ -1346,7 +1346,7 @@ public final class AnimatorSet extends Animator implements AnimationHandler.Anim
anim.mNodeMap = new ArrayMap<Animator, Node>();
anim.mNodes = new ArrayList<Node>(nodeCount);
anim.mEvents = new ArrayList<AnimationEvent>();
- anim.mDummyListener = new AnimatorListenerAdapter() {
+ anim.mAnimationEndingListener = new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
if (anim.mNodeMap.get(animation) == null) {
@@ -1369,7 +1369,7 @@ public final class AnimatorSet extends Animator implements AnimationHandler.Anim
final Node node = mNodes.get(n);
Node nodeClone = node.clone();
// Remove the old internal listener from the cloned child
- nodeClone.mAnimation.removeListener(mDummyListener);
+ nodeClone.mAnimation.removeListener(mAnimationEndingListener);
clonesMap.put(node, nodeClone);
anim.mNodes.add(nodeClone);
anim.mNodeMap.put(nodeClone.mAnimation, nodeClone);
@@ -2087,7 +2087,7 @@ public final class AnimatorSet extends Animator implements AnimationHandler.Anim
* animation starts.
*/
public Builder after(long delay) {
- // setup dummy ValueAnimator just to run the clock
+ // setup a ValueAnimator just to run the clock
ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f);
anim.setDuration(delay);
after(anim);
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 107fb26357aa..4a982dd1a411 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -150,7 +150,6 @@ import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
-import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -3798,22 +3797,6 @@ public class Activity extends ContextThemeWrapper
return false;
}
- private static final class RequestFinishCallback extends IRequestFinishCallback.Stub {
- private final WeakReference<Activity> mActivityRef;
-
- RequestFinishCallback(WeakReference<Activity> activityRef) {
- mActivityRef = activityRef;
- }
-
- @Override
- public void requestFinish() {
- Activity activity = mActivityRef.get();
- if (activity != null) {
- activity.mHandler.post(activity::finishAfterTransition);
- }
- }
- }
-
/**
* Called when the activity has detected the user's press of the back
* key. The default implementation simply finishes the current activity,
@@ -3837,9 +3820,8 @@ public class Activity extends ContextThemeWrapper
try {
// Inform activity task manager that the activity received a back press
// while at the root of the task. This call allows ActivityTaskManager
- // to intercept or defer finishing.
- ActivityTaskManager.getService().onBackPressedOnTaskRoot(mToken,
- new RequestFinishCallback(new WeakReference<>(this)));
+ // to intercept or move the task to the back.
+ ActivityTaskManager.getService().onBackPressedOnTaskRoot(mToken);
} catch (RemoteException e) {
finishAfterTransition();
}
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index 9e15c1fca077..f4743895686c 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -52,14 +52,23 @@ public abstract class ActivityManagerInternal {
* if in the same profile group.
* Otherwise, {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL} is required.
*/
- public static final int ALLOW_NON_FULL_IN_PROFILE = 1;
+ public static final int ALLOW_NON_FULL_IN_PROFILE_OR_FULL = 1;
public static final int ALLOW_FULL_ONLY = 2;
/**
* Allows access to a caller with {@link android.Manifest.permission#INTERACT_ACROSS_PROFILES}
* or {@link android.Manifest.permission#INTERACT_ACROSS_USERS} if in the same profile group.
* Otherwise, {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL} is required.
*/
- public static final int ALLOW_ALL_PROFILE_PERMISSIONS_IN_PROFILE = 3;
+ public static final int ALLOW_ACROSS_PROFILES_IN_PROFILE_OR_FULL = 3;
+ /**
+ * Requires {@link android.Manifest.permission#INTERACT_ACROSS_PROFILES},
+ * {@link android.Manifest.permission#INTERACT_ACROSS_USERS}, or
+ * {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL} if in same profile group,
+ * otherwise {@link android.Manifest.permission#INTERACT_ACROSS_USERS} or
+ * {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL}. (so this is an extension
+ * to {@link #ALLOW_NON_FULL})
+ */
+ public static final int ALLOW_ACROSS_PROFILES_IN_PROFILE_OR_NON_FULL = 4;
/**
* Verify that calling app has access to the given provider.
@@ -318,12 +327,14 @@ public abstract class ActivityManagerInternal {
int uid, int realCallingUid, int realCallingPid, Intent intent, String resolvedType,
IIntentReceiver resultTo, int resultCode, String resultData, Bundle resultExtras,
String requiredPermission, Bundle bOptions, boolean serialized, boolean sticky,
- @UserIdInt int userId, boolean allowBackgroundActivityStarts);
+ @UserIdInt int userId, boolean allowBackgroundActivityStarts,
+ @Nullable IBinder backgroundActivityStartsToken);
public abstract ComponentName startServiceInPackage(int uid, Intent service,
String resolvedType, boolean fgRequired, String callingPackage,
@Nullable String callingFeatureId, @UserIdInt int userId,
- boolean allowBackgroundActivityStarts) throws TransactionTooLargeException;
+ boolean allowBackgroundActivityStarts,
+ @Nullable IBinder backgroundActivityStartsToken) throws TransactionTooLargeException;
public abstract void disconnectActivityFromServices(Object connectionHolder);
public abstract void cleanUpServices(@UserIdInt int userId, ComponentName component,
diff --git a/core/java/android/app/IActivityTaskManager.aidl b/core/java/android/app/IActivityTaskManager.aidl
index f428b48bb51f..72a3637d8e07 100644
--- a/core/java/android/app/IActivityTaskManager.aidl
+++ b/core/java/android/app/IActivityTaskManager.aidl
@@ -26,7 +26,6 @@ import android.app.IAppTask;
import android.app.IAssistDataReceiver;
import android.app.IInstrumentationWatcher;
import android.app.IProcessObserver;
-import android.app.IRequestFinishCallback;
import android.app.IServiceConnection;
import android.app.IStopUserCallback;
import android.app.ITaskStackListener;
@@ -458,9 +457,7 @@ interface IActivityTaskManager {
/**
* Reports that an Activity received a back key press when there were no additional activities
- * on the back stack. If the Activity should be finished, the callback will be invoked. A
- * callback is used instead of finishing the activity directly from the server such that the
- * client may perform actions prior to finishing.
+ * on the back stack.
*/
- void onBackPressedOnTaskRoot(in IBinder activityToken, in IRequestFinishCallback callback);
+ void onBackPressedOnTaskRoot(in IBinder activityToken);
}
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index 0deef53c478f..a970322601ec 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -185,6 +185,7 @@ interface INotificationManager
List<ComponentName> getEnabledNotificationListeners(int userId);
ComponentName getAllowedNotificationAssistantForUser(int userId);
ComponentName getAllowedNotificationAssistant();
+ boolean hasEnabledNotificationListener(String packageName, int userId);
@UnsupportedAppUsage
int getZenMode();
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index 1dc54ddbac4b..aa6a08b6d2e4 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -814,12 +814,9 @@ public final class LoadedApk {
makePaths(mActivityThread, isBundledApp, mApplicationInfo, zipPaths, libPaths);
- String libraryPermittedPath = mDataDir;
- if (mActivityThread == null) {
- // In a zygote context where mActivityThread is null we can't access the app data dir
- // and including this in libraryPermittedPath would cause SELinux denials.
- libraryPermittedPath = "";
- }
+ // Including an inaccessible dir in libraryPermittedPath would cause SELinux denials
+ // when the loader attempts to canonicalise the path. so we don't.
+ String libraryPermittedPath = canAccessDataDir() ? mDataDir : "";
if (isBundledApp) {
// For bundled apps, add the base directory of the app (e.g.,
@@ -972,6 +969,33 @@ public final class LoadedApk {
}
}
+ /**
+ * Return whether we can access the package's private data directory in order to be able to
+ * load code from it.
+ */
+ private boolean canAccessDataDir() {
+ // In a zygote context where mActivityThread is null we can't access the app data dir.
+ if (mActivityThread == null) {
+ return false;
+ }
+
+ // A package can access its own data directory (the common case, so short-circuit it).
+ if (Objects.equals(mPackageName, ActivityThread.currentPackageName())) {
+ return true;
+ }
+
+ // Temporarily disable logging of disk reads on the Looper thread as this is necessary -
+ // and the loader will access the directory anyway if we don't check it.
+ StrictMode.ThreadPolicy oldPolicy = allowThreadDiskReads();
+ try {
+ // We are constructing a classloader for a different package. It is likely,
+ // but not certain, that we can't acccess its app data dir - so check.
+ return new File(mDataDir).canExecute();
+ } finally {
+ setThreadPolicy(oldPolicy);
+ }
+ }
+
@UnsupportedAppUsage
public ClassLoader getClassLoader() {
synchronized (this) {
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index f82ab7bcfc08..68e65612971c 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -958,7 +958,7 @@ public class Notification implements Parcelable
*
* @hide
*/
- private IBinder mWhitelistToken;
+ private IBinder mAllowlistToken;
/**
* Must be set by a process to start associating tokens with Notification objects
@@ -966,7 +966,7 @@ public class Notification implements Parcelable
*
* @hide
*/
- static public IBinder processWhitelistToken;
+ static public IBinder processAllowlistToken;
/**
* {@link #extras} key: this is the title of the notification,
@@ -2245,12 +2245,12 @@ public class Notification implements Parcelable
{
int version = parcel.readInt();
- mWhitelistToken = parcel.readStrongBinder();
- if (mWhitelistToken == null) {
- mWhitelistToken = processWhitelistToken;
+ mAllowlistToken = parcel.readStrongBinder();
+ if (mAllowlistToken == null) {
+ mAllowlistToken = processAllowlistToken;
}
// Propagate this token to all pending intents that are unmarshalled from the parcel.
- parcel.setClassCookie(PendingIntent.class, mWhitelistToken);
+ parcel.setClassCookie(PendingIntent.class, mAllowlistToken);
when = parcel.readLong();
creationTime = parcel.readLong();
@@ -2368,7 +2368,7 @@ public class Notification implements Parcelable
* @hide
*/
public void cloneInto(Notification that, boolean heavy) {
- that.mWhitelistToken = this.mWhitelistToken;
+ that.mAllowlistToken = this.mAllowlistToken;
that.when = this.when;
that.creationTime = this.creationTime;
that.mSmallIcon = this.mSmallIcon;
@@ -2678,7 +2678,7 @@ public class Notification implements Parcelable
private void writeToParcelImpl(Parcel parcel, int flags) {
parcel.writeInt(1);
- parcel.writeStrongBinder(mWhitelistToken);
+ parcel.writeStrongBinder(mAllowlistToken);
parcel.writeLong(when);
parcel.writeLong(creationTime);
if (mSmallIcon == null && icon != 0) {
diff --git a/core/java/android/app/NotificationChannel.java b/core/java/android/app/NotificationChannel.java
index cf2f7690bc2c..c827e601ce88 100644
--- a/core/java/android/app/NotificationChannel.java
+++ b/core/java/android/app/NotificationChannel.java
@@ -828,12 +828,15 @@ public final class NotificationChannel implements Parcelable {
/**
* @hide
*/
+ @TestApi
public void setDemoted(boolean demoted) {
mDemoted = demoted;
}
/**
- * @hide
+ * Returns whether the user has decided that this channel does not represent a conversation. The
+ * value will always be false for channels that never claimed to be conversations - that is,
+ * for channels where {@link #getConversationId()} and {@link #getParentChannelId()} are empty.
*/
public boolean isDemoted() {
return mDemoted;
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index eef9c022fda8..8ee995d6e6be 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -20,6 +20,7 @@ import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SdkConstant;
+import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.annotation.TestApi;
@@ -801,8 +802,8 @@ public class NotificationManager {
*
* <p>The name and description should only be changed if the locale changes
* or in response to the user renaming this channel. For example, if a user has a channel
- * named 'John Doe' that represents messages from a 'John Doe', and 'John Doe' changes his name
- * to 'John Smith,' the channel can be renamed to match.
+ * named 'Messages' and the user changes their locale, this channel's name should be updated
+ * with the translation of 'Messages' in the new locale.
*
* <p>The importance of an existing channel will only be changed if the new importance is lower
* than the current value and the user has not altered any settings on this channel.
@@ -957,6 +958,20 @@ public class NotificationManager {
* @hide
*/
@TestApi
+ public void updateNotificationChannel(@NonNull String pkg, int uid,
+ @NonNull NotificationChannel channel) {
+ INotificationManager service = getService();
+ try {
+ service.updateNotificationChannelForPackage(pkg, uid, channel);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * @hide
+ */
+ @TestApi
public ComponentName getEffectsSuppressor() {
INotificationManager service = getService();
try {
@@ -1539,6 +1554,25 @@ public class NotificationManager {
}
}
+ /**
+ * Whether the given user has an enabled
+ * {@link android.service.notification.NotificationListenerService} with the given package name.
+ *
+ * @param packageName the package name of the NotificationListenerService class
+ * @param userHandle the handle of the user that set the listener
+ * @hide
+ */
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ @SuppressLint("UserHandle")
+ public boolean hasEnabledNotificationListener(@NonNull String packageName,
+ @NonNull UserHandle userHandle) {
+ INotificationManager service = getService();
+ try {
+ return service.hasEnabledNotificationListener(packageName, userHandle.getIdentifier());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
private Context mContext;
diff --git a/core/java/android/app/WindowConfiguration.java b/core/java/android/app/WindowConfiguration.java
index ec81ae3bc7c2..79f05a3caa93 100644
--- a/core/java/android/app/WindowConfiguration.java
+++ b/core/java/android/app/WindowConfiguration.java
@@ -310,7 +310,6 @@ public class WindowConfiguration implements Parcelable, Comparable<WindowConfigu
* Sets the maximum bounds to the provided {@link Rect}.
* @param rect the new bounds value.
* @see #getMaxBounds()
- * @hide
*/
public void setMaxBounds(@Nullable Rect rect) {
if (rect == null) {
@@ -364,10 +363,8 @@ public class WindowConfiguration implements Parcelable, Comparable<WindowConfigu
return mBounds;
}
- /**
- * @see #setMaxBounds(Rect)
- * @hide
- */
+ /** @see #setMaxBounds(Rect) */
+ @NonNull
public Rect getMaxBounds() {
return mMaxBounds;
}
diff --git a/core/java/android/app/backup/BackupAgent.java b/core/java/android/app/backup/BackupAgent.java
index 20aa0647d261..a789169ade39 100644
--- a/core/java/android/app/backup/BackupAgent.java
+++ b/core/java/android/app/backup/BackupAgent.java
@@ -919,7 +919,7 @@ public abstract class BackupAgent extends ContextWrapper {
/**
* Only specialized platform agents should overload this entry point to support
- * restores to crazy non-app locations.
+ * restores to non-app locations.
* @hide
*/
protected void onRestoreFile(ParcelFileDescriptor data, long size,
diff --git a/core/java/android/app/usage/UsageStats.java b/core/java/android/app/usage/UsageStats.java
index 4d73a61c972d..f2a054d16ccb 100644
--- a/core/java/android/app/usage/UsageStats.java
+++ b/core/java/android/app/usage/UsageStats.java
@@ -229,7 +229,8 @@ public final class UsageStats implements Parcelable {
}
/**
- * Get the total time this package spent in the foreground, measured in milliseconds.
+ * Get the total time this package spent in the foreground, measured in milliseconds. When in
+ * the foreground, the user is actively interacting with the app.
*/
public long getTotalTimeInForeground() {
return mTotalTimeInForeground;
@@ -237,6 +238,8 @@ public final class UsageStats implements Parcelable {
/**
* Get the total time this package's activity is visible in the UI, measured in milliseconds.
+ * Note: An app may be visible but not considered foreground. Apps in the foreground must be
+ * visible, so visible time includes time in the foreground.
*/
public long getTotalTimeVisible() {
return mTotalTimeVisible;
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index fb9746830d4e..fa3df1da5935 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -1482,7 +1482,7 @@ public final class BluetoothDevice implements Parcelable {
* present in the cache. Clients should use the {@link #getUuids} to get UUIDs
* if service discovery is not to be performed.
*
- * @return False if the sanity check fails, True if the process of initiating an ACL connection
+ * @return False if the check fails, True if the process of initiating an ACL connection
* to the remote device was started.
*/
@RequiresPermission(Manifest.permission.BLUETOOTH)
@@ -1516,7 +1516,7 @@ public final class BluetoothDevice implements Parcelable {
* The object type will match one of the SdpXxxRecord types, depending on the UUID searched
* for.
*
- * @return False if the sanity check fails, True if the process
+ * @return False if the check fails, True if the process
* of initiating an ACL connection to the remote device
* was started.
*/
diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java
index 60ecf64dd0a9..33be50d34777 100644
--- a/core/java/android/content/ContentProvider.java
+++ b/core/java/android/content/ContentProvider.java
@@ -1620,13 +1620,12 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall
* Implementation when a caller has performed an insert on the content
* provider, but that call has been rejected for the operation given
* to {@link #setAppOps(int, int)}. The default implementation simply
- * returns a dummy URI that is the base URI with a 0 path element
- * appended.
+ * returns a URI that is the base URI with a 0 path element appended.
*/
public Uri rejectInsert(Uri uri, ContentValues values) {
// If not allowed, we need to return some reasonable URI. Maybe the
// content provider should be responsible for this, but for now we
- // will just return the base URI with a dummy '0' tagged on to it.
+ // will just return the base URI with a '0' tagged on to it.
// You shouldn't be able to read if you can't write, anyway, so it
// shouldn't matter much what is returned.
return uri.buildUpon().appendPath("0").build();
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index 33f32fb6b9fe..b5eb043d847c 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -726,7 +726,7 @@ public abstract class ContentResolver implements ContentInterface {
/**
* In addition to {@link #SYNC_EXEMPTION_PROMOTE_BUCKET}, we put the sync adapter app in the
- * temp whitelist for 10 minutes, so that even RARE apps can run syncs right away.
+ * temp allowlist for 10 minutes, so that even RARE apps can run syncs right away.
* @hide
*/
public static final int SYNC_EXEMPTION_PROMOTE_BUCKET_WITH_TEMP = 2;
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 6f8923ffaf59..2385712a71d1 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -5174,6 +5174,16 @@ public abstract class Context {
public static final String DREAM_SERVICE = "dream";
/**
+ * Use with {@link #getSystemService(String)} to retrieve a
+ * {@link android.telephony.SmsManager} for accessing Sms functionality.
+ *
+ * @see #getSystemService(String)
+
+ * @hide
+ */
+ public static final String SMS_SERVICE = "sms";
+
+ /**
* Determine whether the given permission is allowed for a particular
* process and user ID running in the system.
*
diff --git a/core/java/android/content/SyncStatusInfo.java b/core/java/android/content/SyncStatusInfo.java
index b72eb040ea92..8d0baa7f53a5 100644
--- a/core/java/android/content/SyncStatusInfo.java
+++ b/core/java/android/content/SyncStatusInfo.java
@@ -273,7 +273,7 @@ public class SyncStatusInfo implements Parcelable {
totalStats.numSyncs - totalStats.numSourceLocal - totalStats.numSourcePoll
- totalStats.numSourceOther
- totalStats.numSourceUser;
- if (totalStats.numSourcePeriodic < 0) { // Sanity check.
+ if (totalStats.numSourcePeriodic < 0) { // Consistency check.
totalStats.numSourcePeriodic = 0;
}
} else {
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 72246ee32186..200604801b97 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -917,7 +917,7 @@ public class PackageParser {
* Automatically detects if the package is a monolithic style (single APK
* file) or cluster style (directory of APKs).
* <p>
- * This performs sanity checking on cluster style packages, such as
+ * This performs checking on cluster style packages, such as
* requiring identical package name and version codes, a single base APK,
* and unique split names.
*
@@ -1038,7 +1038,7 @@ public class PackageParser {
* package is a monolithic style (single APK file) or cluster style
* (directory of APKs).
* <p>
- * This performs sanity checking on cluster style packages, such as
+ * This performs checking on cluster style packages, such as
* requiring identical package name and version codes, a single base APK,
* and unique split names.
* <p>
@@ -1072,7 +1072,7 @@ public class PackageParser {
/**
* Parse all APKs contained in the given directory, treating them as a
- * single package. This also performs sanity checking, such as requiring
+ * single package. This also performs checking, such as requiring
* identical package name and version codes, a single base APK, and unique
* split names.
* <p>
diff --git a/core/java/android/content/pm/dex/DexMetadataHelper.java b/core/java/android/content/pm/dex/DexMetadataHelper.java
index cdb1d221d177..982fce918366 100644
--- a/core/java/android/content/pm/dex/DexMetadataHelper.java
+++ b/core/java/android/content/pm/dex/DexMetadataHelper.java
@@ -147,7 +147,7 @@ public class DexMetadataHelper {
/**
* Validate that the given file is a dex metadata archive.
- * This is just a sanity validation that the file is a zip archive.
+ * This is just a validation that the file is a zip archive.
*
* @throws PackageParserException if the file is not a .dm file.
*/
@@ -173,7 +173,7 @@ public class DexMetadataHelper {
* (for any foo.dm there should be either a 'foo' of a 'foo.apk' file).
* If that's not the case it throws {@code IllegalStateException}.
*
- * This is used to perform a basic sanity check during adb install commands.
+ * This is used to perform a basic check during adb install commands.
* (The installer does not support stand alone .dm files)
*/
public static void validateDexPaths(String[] paths) {
diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java
index 9480d369065d..6407f9b3c1b8 100644
--- a/core/java/android/content/res/Configuration.java
+++ b/core/java/android/content/res/Configuration.java
@@ -1871,7 +1871,7 @@ public final class Configuration implements Parcelable, Comparable<Configuration
*/
public boolean isOtherSeqNewer(Configuration other) {
if (other == null) {
- // Sanity check.
+ // Validation check.
return false;
}
if (other.seq == 0) {
diff --git a/core/java/android/database/sqlite/SQLiteDatabase.java b/core/java/android/database/sqlite/SQLiteDatabase.java
index 7c4692c9e3af..0efd883e8b55 100644
--- a/core/java/android/database/sqlite/SQLiteDatabase.java
+++ b/core/java/android/database/sqlite/SQLiteDatabase.java
@@ -219,7 +219,7 @@ public final class SQLiteDatabase extends SQLiteClosable {
* even a pathological LIKE or GLOB pattern of 50000 bytes relatively quickly.
* The denial of service problem only comes into play when the pattern length gets
* into millions of bytes. Nevertheless, since most useful LIKE or GLOB patterns
- * are at most a few dozen bytes in length, paranoid application developers may
+ * are at most a few dozen bytes in length, cautious application developers may
* want to reduce this parameter to something in the range of a few hundred
* if they know that external users are able to generate arbitrary patterns.
*/
diff --git a/core/java/android/hardware/camera2/CameraDevice.java b/core/java/android/hardware/camera2/CameraDevice.java
index 15625cdeb8f4..decf05396c1f 100644
--- a/core/java/android/hardware/camera2/CameraDevice.java
+++ b/core/java/android/hardware/camera2/CameraDevice.java
@@ -683,6 +683,8 @@ public abstract class CameraDevice implements AutoCloseable {
*<p>BACKWARD_COMPATIBLE devices capable of streaming concurrently with other devices as described by
* {@link android.hardware.camera2.CameraManager#getConcurrentCameraIds} have the
* following guaranteed streams (when streaming concurrently with other devices)</p>
+ * <p> Note: The sizes mentioned for these concurrent streams are the maximum sizes guaranteed
+ * to be supported. Sizes smaller than these, obtained by {@link StreamConfigurationMap#getOutputSizes} for a particular format, are supported as well. </p>
*
* <table>
* <tr><th colspan="5">Concurrent stream guaranteed configurations</th></tr>
@@ -696,7 +698,7 @@ public abstract class CameraDevice implements AutoCloseable {
* </table><br>
* </p>
*
- * <p> Devices which are not backwards-compatible, support a mandatory single stream of size sVGA with image format {@code DEPTH16} during concurrent operation.
+ * <p> Devices which are not backwards-compatible, support a mandatory single stream of size sVGA with image format {@code DEPTH16} during concurrent operation. </p>
*
* <p> For guaranteed concurrent stream configurations:</p>
* <p> sVGA refers to the camera device's maximum resolution for that format from {@link StreamConfigurationMap#getOutputSizes} or
diff --git a/core/java/android/hardware/hdmi/HdmiControlManager.java b/core/java/android/hardware/hdmi/HdmiControlManager.java
index 2579ee687827..da4d8e06ad48 100644
--- a/core/java/android/hardware/hdmi/HdmiControlManager.java
+++ b/core/java/android/hardware/hdmi/HdmiControlManager.java
@@ -24,6 +24,7 @@ import android.annotation.RequiresFeature;
import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
+import android.annotation.StringDef;
import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.annotation.SystemService;
@@ -39,6 +40,8 @@ import android.util.Log;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.ConcurrentUtils;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
@@ -318,6 +321,37 @@ public final class HdmiControlManager {
/** The HdmiControlService will be disabled to standby. */
public static final int CONTROL_STATE_CHANGED_REASON_STANDBY = 3;
+ // -- Which devices the playback device can send a <Standby> message to upon going to sleep.
+ /**
+ * Send <Standby> to TV only.
+ *
+ * @hide
+ */
+ public static final String SEND_STANDBY_ON_SLEEP_TO_TV = "to_tv";
+ /**
+ * Broadcast <Standby> to all devices in the network.
+ *
+ * @hide
+ */
+ public static final String SEND_STANDBY_ON_SLEEP_BROADCAST = "broadcast";
+ /**
+ * Don't send any <Standby> message.
+ *
+ * @hide
+ */
+ public static final String SEND_STANDBY_ON_SLEEP_NONE = "none";
+ /**
+ * @hide
+ */
+ @StringDef({
+ SEND_STANDBY_ON_SLEEP_TO_TV,
+ SEND_STANDBY_ON_SLEEP_BROADCAST,
+ SEND_STANDBY_ON_SLEEP_NONE
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface StandbyBehavior {
+ }
+
// True if we have a logical device of type playback hosted in the system.
private final boolean mHasPlaybackDevice;
// True if we have a logical device of type TV hosted in the system.
diff --git a/core/java/android/hardware/hdmi/IHdmiVendorCommandListener.aidl b/core/java/android/hardware/hdmi/IHdmiVendorCommandListener.aidl
index c708d2030bb0..a16e8787df8a 100644
--- a/core/java/android/hardware/hdmi/IHdmiVendorCommandListener.aidl
+++ b/core/java/android/hardware/hdmi/IHdmiVendorCommandListener.aidl
@@ -22,7 +22,7 @@ package android.hardware.hdmi;
*
* @hide
*/
-interface IHdmiVendorCommandListener {
+oneway interface IHdmiVendorCommandListener {
void onReceived(int logicalAddress, int destAddress, in byte[] operands, boolean hasVendorId);
void onControlStateChanged(boolean enabled, int reason);
}
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index ffb087f6ab24..5d4003afa753 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -608,7 +608,7 @@ public class ConnectivityManager {
public static final int TYPE_BLUETOOTH = 7;
/**
- * Dummy data connection. This should not be used on shipping devices.
+ * Fake data connection. This should not be used on shipping devices.
* @deprecated This is not used any more.
*/
@Deprecated
@@ -1084,9 +1084,9 @@ public class ConnectivityManager {
* to remove an existing always-on VPN configuration.
* @param lockdownEnabled {@code true} to disallow networking when the VPN is not connected or
* {@code false} otherwise.
- * @param lockdownWhitelist The list of packages that are allowed to access network directly
+ * @param lockdownAllowlist The list of packages that are allowed to access network directly
* when VPN is in lockdown mode but is not running. Non-existent packages are ignored so
- * this method must be called when a package that should be whitelisted is installed or
+ * this method must be called when a package that should be allowed is installed or
* uninstalled.
* @return {@code true} if the package is set as always-on VPN controller;
* {@code false} otherwise.
@@ -1094,10 +1094,10 @@ public class ConnectivityManager {
*/
@RequiresPermission(android.Manifest.permission.CONTROL_ALWAYS_ON_VPN)
public boolean setAlwaysOnVpnPackageForUser(int userId, @Nullable String vpnPackage,
- boolean lockdownEnabled, @Nullable List<String> lockdownWhitelist) {
+ boolean lockdownEnabled, @Nullable List<String> lockdownAllowlist) {
try {
return mService.setAlwaysOnVpnPackage(
- userId, vpnPackage, lockdownEnabled, lockdownWhitelist);
+ userId, vpnPackage, lockdownEnabled, lockdownAllowlist);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/net/NetworkAgent.java b/core/java/android/net/NetworkAgent.java
index 482d2d2192b8..327e42bdd2f7 100644
--- a/core/java/android/net/NetworkAgent.java
+++ b/core/java/android/net/NetworkAgent.java
@@ -354,8 +354,7 @@ public abstract class NetworkAgent {
private static NetworkInfo getLegacyNetworkInfo(final NetworkAgentConfig config) {
// The subtype can be changed with (TODO) setLegacySubtype, but it starts
// with the type and an empty description.
- final NetworkInfo ni = new NetworkInfo(config.legacyType, config.legacyType,
- config.legacyTypeName, "");
+ final NetworkInfo ni = new NetworkInfo(config.legacyType, 0, config.legacyTypeName, "");
ni.setIsAvailable(true);
ni.setExtraInfo(config.getLegacyExtraInfo());
return ni;
diff --git a/core/java/android/net/NetworkState.java b/core/java/android/net/NetworkState.java
index e44961528708..713b6888376e 100644
--- a/core/java/android/net/NetworkState.java
+++ b/core/java/android/net/NetworkState.java
@@ -28,7 +28,7 @@ import android.util.Slog;
* @hide
*/
public class NetworkState implements Parcelable {
- private static final boolean SANITY_CHECK_ROAMING = false;
+ private static final boolean VALIDATE_ROAMING_STATE = false;
public static final NetworkState EMPTY = new NetworkState(null, null, null, null, null, null);
@@ -52,7 +52,7 @@ public class NetworkState implements Parcelable {
// This object is an atomic view of a network, so the various components
// should always agree on roaming state.
- if (SANITY_CHECK_ROAMING && networkInfo != null && networkCapabilities != null) {
+ if (VALIDATE_ROAMING_STATE && networkInfo != null && networkCapabilities != null) {
if (networkInfo.isRoaming() == networkCapabilities
.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING)) {
Slog.wtf("NetworkState", "Roaming state disagreement between " + networkInfo
diff --git a/core/java/android/net/NetworkStatsHistory.java b/core/java/android/net/NetworkStatsHistory.java
index 3c1b86b9f196..51f09a0103ff 100644
--- a/core/java/android/net/NetworkStatsHistory.java
+++ b/core/java/android/net/NetworkStatsHistory.java
@@ -26,6 +26,7 @@ import static android.net.NetworkStatsHistory.DataStreamUtils.writeVarLongArray;
import static android.net.NetworkStatsHistory.Entry.UNKNOWN;
import static android.net.NetworkStatsHistory.ParcelUtils.readLongArray;
import static android.net.NetworkStatsHistory.ParcelUtils.writeLongArray;
+import static android.net.NetworkUtils.multiplySafeByRational;
import static android.text.format.DateUtils.SECOND_IN_MILLIS;
import static com.android.internal.util.ArrayUtils.total;
@@ -364,11 +365,12 @@ public class NetworkStatsHistory implements Parcelable {
if (overlap <= 0) continue;
// integer math each time is faster than floating point
- final long fracRxBytes = rxBytes * overlap / duration;
- final long fracRxPackets = rxPackets * overlap / duration;
- final long fracTxBytes = txBytes * overlap / duration;
- final long fracTxPackets = txPackets * overlap / duration;
- final long fracOperations = operations * overlap / duration;
+ final long fracRxBytes = multiplySafeByRational(rxBytes, overlap, duration);
+ final long fracRxPackets = multiplySafeByRational(rxPackets, overlap, duration);
+ final long fracTxBytes = multiplySafeByRational(txBytes, overlap, duration);
+ final long fracTxPackets = multiplySafeByRational(txPackets, overlap, duration);
+ final long fracOperations = multiplySafeByRational(operations, overlap, duration);
+
addLong(activeTime, i, overlap);
addLong(this.rxBytes, i, fracRxBytes); rxBytes -= fracRxBytes;
@@ -568,12 +570,24 @@ public class NetworkStatsHistory implements Parcelable {
if (overlap <= 0) continue;
// integer math each time is faster than floating point
- if (activeTime != null) entry.activeTime += activeTime[i] * overlap / bucketSpan;
- if (rxBytes != null) entry.rxBytes += rxBytes[i] * overlap / bucketSpan;
- if (rxPackets != null) entry.rxPackets += rxPackets[i] * overlap / bucketSpan;
- if (txBytes != null) entry.txBytes += txBytes[i] * overlap / bucketSpan;
- if (txPackets != null) entry.txPackets += txPackets[i] * overlap / bucketSpan;
- if (operations != null) entry.operations += operations[i] * overlap / bucketSpan;
+ if (activeTime != null) {
+ entry.activeTime += multiplySafeByRational(activeTime[i], overlap, bucketSpan);
+ }
+ if (rxBytes != null) {
+ entry.rxBytes += multiplySafeByRational(rxBytes[i], overlap, bucketSpan);
+ }
+ if (rxPackets != null) {
+ entry.rxPackets += multiplySafeByRational(rxPackets[i], overlap, bucketSpan);
+ }
+ if (txBytes != null) {
+ entry.txBytes += multiplySafeByRational(txBytes[i], overlap, bucketSpan);
+ }
+ if (txPackets != null) {
+ entry.txPackets += multiplySafeByRational(txPackets[i], overlap, bucketSpan);
+ }
+ if (operations != null) {
+ entry.operations += multiplySafeByRational(operations[i], overlap, bucketSpan);
+ }
}
return entry;
}
diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java
index 97a7ecc3fb15..1e5b6d5ab5c0 100644
--- a/core/java/android/net/NetworkUtils.java
+++ b/core/java/android/net/NetworkUtils.java
@@ -477,4 +477,35 @@ public class NetworkUtils {
return true;
}
+
+ /**
+ * Safely multiple a value by a rational.
+ * <p>
+ * Internally it uses integer-based math whenever possible, but switches
+ * over to double-based math if values would overflow.
+ * @hide
+ */
+ public static long multiplySafeByRational(long value, long num, long den) {
+ if (den == 0) {
+ throw new ArithmeticException("Invalid Denominator");
+ }
+ long x = value;
+ long y = num;
+
+ // Logic shamelessly borrowed from Math.multiplyExact()
+ long r = x * y;
+ long ax = Math.abs(x);
+ long ay = Math.abs(y);
+ if (((ax | ay) >>> 31 != 0)) {
+ // Some bits greater than 2^31 that might cause overflow
+ // Check the result using the divide operator
+ // and check for the special case of Long.MIN_VALUE * -1
+ if (((y != 0) && (r / y != x)) ||
+ (x == Long.MIN_VALUE && y == -1)) {
+ // Use double math to avoid overflowing
+ return (long) (((double) num / den) * value);
+ }
+ }
+ return r / den;
+ }
}
diff --git a/core/java/android/net/SntpClient.java b/core/java/android/net/SntpClient.java
index 8c6faf6d9970..f6852e681439 100644
--- a/core/java/android/net/SntpClient.java
+++ b/core/java/android/net/SntpClient.java
@@ -25,6 +25,7 @@ import com.android.internal.util.TrafficStatsConstants;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
+import java.net.UnknownHostException;
import java.util.Arrays;
/**
@@ -86,21 +87,26 @@ public class SntpClient {
* Sends an SNTP request to the given host and processes the response.
*
* @param host host name of the server.
- * @param timeout network timeout in milliseconds.
+ * @param timeout network timeout in milliseconds. the timeout doesn't include the DNS lookup
+ * time, and it applies to each individual query to the resolved addresses of
+ * the NTP server.
* @param network network over which to send the request.
* @return true if the transaction was successful.
*/
public boolean requestTime(String host, int timeout, Network network) {
final Network networkForResolv = network.getPrivateDnsBypassingCopy();
- InetAddress address = null;
try {
- address = networkForResolv.getByName(host);
- } catch (Exception e) {
+ final InetAddress[] addresses = networkForResolv.getAllByName(host);
+ for (int i = 0; i < addresses.length; i++) {
+ if (requestTime(addresses[i], NTP_PORT, timeout, networkForResolv)) return true;
+ }
+ } catch (UnknownHostException e) {
+ Log.w(TAG, "Unknown host: " + host);
EventLogTags.writeNtpFailure(host, e.toString());
- if (DBG) Log.d(TAG, "request time failed: " + e);
- return false;
}
- return requestTime(address, NTP_PORT, timeout, networkForResolv);
+
+ if (DBG) Log.d(TAG, "request time failed");
+ return false;
}
public boolean requestTime(InetAddress address, int port, int timeout, Network network) {
@@ -139,10 +145,11 @@ public class SntpClient {
final long originateTime = readTimeStamp(buffer, ORIGINATE_TIME_OFFSET);
final long receiveTime = readTimeStamp(buffer, RECEIVE_TIME_OFFSET);
final long transmitTime = readTimeStamp(buffer, TRANSMIT_TIME_OFFSET);
+ final long referenceTime = readTimeStamp(buffer, REFERENCE_TIME_OFFSET);
- /* do sanity check according to RFC */
+ /* Do validation according to RFC */
// TODO: validate originateTime == requestTime.
- checkValidServerReply(leap, mode, stratum, transmitTime);
+ checkValidServerReply(leap, mode, stratum, transmitTime, referenceTime);
long roundTripTime = responseTicks - requestTicks - (transmitTime - receiveTime);
// receiveTime = originateTime + transit + skew
@@ -218,7 +225,7 @@ public class SntpClient {
}
private static void checkValidServerReply(
- byte leap, byte mode, int stratum, long transmitTime)
+ byte leap, byte mode, int stratum, long transmitTime, long referenceTime)
throws InvalidServerReplyException {
if (leap == NTP_LEAP_NOSYNC) {
throw new InvalidServerReplyException("unsynchronized server");
@@ -232,6 +239,9 @@ public class SntpClient {
if (transmitTime == 0) {
throw new InvalidServerReplyException("zero transmitTime");
}
+ if (referenceTime == 0) {
+ throw new InvalidServerReplyException("zero reference timestamp");
+ }
}
/**
diff --git a/core/java/android/net/VpnService.java b/core/java/android/net/VpnService.java
index 9c2c5b839302..8e90a119fe21 100644
--- a/core/java/android/net/VpnService.java
+++ b/core/java/android/net/VpnService.java
@@ -119,7 +119,7 @@ import java.util.Set;
* <p> The Android system starts a VPN in the background by calling
* {@link android.content.Context#startService startService()}. In Android 8.0
* (API level 26) and higher, the system places VPN apps on the temporary
- * whitelist for a short period so the app can start in the background. The VPN
+ * allowlist for a short period so the app can start in the background. The VPN
* app must promote itself to the foreground after it's launched or the system
* will shut down the app.
*
diff --git a/core/java/android/net/network-policy-restrictions.md b/core/java/android/net/network-policy-restrictions.md
index 63ce1a244643..04c658c39ad3 100644
--- a/core/java/android/net/network-policy-restrictions.md
+++ b/core/java/android/net/network-policy-restrictions.md
@@ -1,11 +1,11 @@
# Data Saver vs Battery Saver
-The tables below show whether an app has network access while on background depending on the status of Data Saver mode, Battery Saver mode, and the app's whitelist on those restricted modes.
+The tables below show whether an app has network access while on background depending on the status of Data Saver mode, Battery Saver mode, and the app's allowlist on those restricted modes.
### How to read the tables
-The 2 topmost rows define the Battery Saver mode and whether the app is whitelisted or not for it.
-The 2 leftmost columns define the Data Saver mode and whether the app is whitelisted, not whitelisted, or blacklisted for it.
+The 2 topmost rows define the Battery Saver mode and whether the app is allowlisted or not for it.
+The 2 leftmost columns define the Data Saver mode and whether the app is allowlisted, not allowlisted, or denylisted for it.
The cells define the network status when the app is on background.
More specifically:
@@ -14,9 +14,9 @@ More specifically:
* **DS OFF**: Data Saver Mode is off
* **BS ON**: Battery Saver Mode is on
* **BS OFF**: Battery Saver Mode is off
-* **WL**: app is whitelisted
-* **!WL**: app is not whitelisted
-* **BL**: app is blacklisted
+* **AL**: app is allowlisted
+* **!AL**: app is not allowlisted
+* **DL**: app is denylisted
* **ok**: network access granted while app on background (NetworkInfo's state/detailed state should be `CONNECTED` / `CONNECTED`)
* **blk**: network access blocked while app on background (NetworkInfo's state/detailed state should be `DISCONNECTED` / `BLOCKED`)
@@ -25,23 +25,23 @@ More specifically:
| | | BS | ON | BS | OFF |
|:-------:|-------|------|-------|------|-------|
-| | | *WL* | *!WL* | *WL* | *!WL* |
-| **DS** | *WL* | ok | blk | ok | ok |
-| **ON** | *!WL* | blk | blk | blk | blk |
-| | *BL* | blk | blk | blk | blk |
-| **DS** | *WL* | blk | blk | ok | ok |
-| **OFF** | *!WL* | blk | blk | ok | ok |
-| | *BL* | blk | blk | blk | blk |
+| | | *AL* | *!AL* | *AL* | *!AL* |
+| **DS** | *AL* | ok | blk | ok | ok |
+| **ON** | *!AL* | blk | blk | blk | blk |
+| | *DL* | blk | blk | blk | blk |
+| **DS** | *AL* | blk | blk | ok | ok |
+| **OFF** | *!AL* | blk | blk | ok | ok |
+| | *DL* | blk | blk | blk | blk |
## On non-metered networks
| | | BS | ON | BS | OFF |
|:-------:|-------|------|-------|------|-------|
-| | | *WL* | *!WL* | *WL* | *!WL* |
-| **DS** | *WL* | ok | blk | ok | ok |
-| **ON** | *!WL* | ok | blk | ok | ok |
-| | *BL* | ok | blk | ok | ok |
-| **DS** | *WL* | ok | blk | ok | ok |
-| **OFF** | *!WL* | ok | blk | ok | ok |
-| | *BL* | ok | blk | ok | ok |
+| | | *AL* | *!AL* | *AL* | *!AL* |
+| **DS** | *AL* | ok | blk | ok | ok |
+| **ON** | *!AL* | ok | blk | ok | ok |
+| | *DL* | ok | blk | ok | ok |
+| **DS** | *AL* | ok | blk | ok | ok |
+| **OFF** | *!AL* | ok | blk | ok | ok |
+| | *DL* | ok | blk | ok | ok |
diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java
index a0207c8497c8..515704ca77f4 100644
--- a/core/java/android/os/Binder.java
+++ b/core/java/android/os/Binder.java
@@ -543,15 +543,17 @@ public class Binder implements IBinder {
/**
* Mark as being built with VINTF-level stability promise. This API should
- * only ever be invoked by the build system. It means that the interface
- * represented by this binder is guaranteed to be kept stable for several
- * years, and the build system also keeps snapshots of these APIs and
- * invokes the AIDL compiler to make sure that these snapshots are
- * backwards compatible. Instead of using this API, use an @VintfStability
- * interface.
+ * only ever be invoked by generated code from the aidl compiler. It means
+ * that the interface represented by this binder is guaranteed to be kept
+ * stable for several years, according to the VINTF compatibility lifecycle,
+ * and the build system also keeps snapshots of these APIs and invokes the
+ * AIDL compiler to make sure that these snapshots are backwards compatible.
+ * Instead of using this API, use the @VintfStability annotation on your
+ * AIDL interface.
*
* @hide
*/
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public final native void markVintfStability();
/**
diff --git a/core/java/android/os/DropBoxManager.java b/core/java/android/os/DropBoxManager.java
index bb8d4fe19aa2..3dce130f5d61 100644
--- a/core/java/android/os/DropBoxManager.java
+++ b/core/java/android/os/DropBoxManager.java
@@ -276,7 +276,7 @@ public class DropBoxManager {
}
/**
- * Create a dummy instance for testing. All methods will fail unless
+ * Create an instance for testing. All methods will fail unless
* overridden with an appropriate mock implementation. To obtain a
* functional instance, use {@link android.content.Context#getSystemService}.
*/
diff --git a/core/java/android/os/FileUtils.java b/core/java/android/os/FileUtils.java
index 87e70431bd12..70c924a46c17 100644
--- a/core/java/android/os/FileUtils.java
+++ b/core/java/android/os/FileUtils.java
@@ -1306,7 +1306,7 @@ public final class FileUtils {
/** {@hide} */
public static int translateModeStringToPosix(String mode) {
- // Sanity check for invalid chars
+ // Quick check for invalid chars
for (int i = 0; i < mode.length(); i++) {
switch (mode.charAt(i)) {
case 'r':
diff --git a/core/java/android/os/GraphicsEnvironment.java b/core/java/android/os/GraphicsEnvironment.java
index df58a6c636f5..1539b6ed4ca7 100644
--- a/core/java/android/os/GraphicsEnvironment.java
+++ b/core/java/android/os/GraphicsEnvironment.java
@@ -78,7 +78,7 @@ public class GraphicsEnvironment {
private static final String ACTION_ANGLE_FOR_ANDROID_TOAST_MESSAGE =
"android.app.action.ANGLE_FOR_ANDROID_TOAST_MESSAGE";
private static final String INTENT_KEY_A4A_TOAST_MESSAGE = "A4A Toast Message";
- private static final String GAME_DRIVER_WHITELIST_ALL = "*";
+ private static final String GAME_DRIVER_ALLOWLIST_ALL = "*";
private static final String GAME_DRIVER_SPHAL_LIBRARIES_FILENAME = "sphal_libraries.txt";
private static final int VULKAN_1_0 = 0x00400000;
private static final int VULKAN_1_1 = 0x00401000;
@@ -142,19 +142,19 @@ public class GraphicsEnvironment {
+ "set to: '" + devOptIn + "'");
}
- // We only want to use ANGLE if the app is whitelisted or the developer has
+ // We only want to use ANGLE if the app is allowlisted or the developer has
// explicitly chosen something other than default driver.
- // The whitelist will be generated by the ANGLE APK at both boot time and
+ // The allowlist will be generated by the ANGLE APK at both boot time and
// ANGLE update time. It will only include apps mentioned in the rules file.
- final boolean whitelisted = checkAngleWhitelist(context, coreSettings, packageName);
+ final boolean allowlisted = checkAngleAllowlist(context, coreSettings, packageName);
final boolean requested = devOptIn.equals(sDriverMap.get(OpenGlDriverChoice.ANGLE));
- final boolean useAngle = (whitelisted || requested);
+ final boolean useAngle = (allowlisted || requested);
if (!useAngle) {
return false;
}
- if (whitelisted) {
- Log.v(TAG, "ANGLE whitelist includes " + packageName);
+ if (allowlisted) {
+ Log.v(TAG, "ANGLE allowlist includes " + packageName);
}
if (requested) {
Log.v(TAG, "ANGLE developer option for " + packageName + ": " + devOptIn);
@@ -564,17 +564,17 @@ public class GraphicsEnvironment {
}
/**
- * Pull ANGLE whitelist from GlobalSettings and compare against current package
+ * Pull ANGLE allowlist from GlobalSettings and compare against current package
*/
- private static boolean checkAngleWhitelist(Context context, Bundle bundle, String packageName) {
+ private static boolean checkAngleAllowlist(Context context, Bundle bundle, String packageName) {
final ContentResolver contentResolver = context.getContentResolver();
- final List<String> angleWhitelist =
+ final List<String> angleAllowlist =
getGlobalSettingsString(contentResolver, bundle,
Settings.Global.GLOBAL_SETTINGS_ANGLE_WHITELIST);
- if (DEBUG) Log.v(TAG, "ANGLE whitelist: " + angleWhitelist);
+ if (DEBUG) Log.v(TAG, "ANGLE allowlist: " + angleAllowlist);
- return angleWhitelist.contains(packageName);
+ return angleAllowlist.contains(packageName);
}
/**
@@ -584,7 +584,7 @@ public class GraphicsEnvironment {
* @param bundle
* @param packageName
* @return true: ANGLE setup successfully
- * false: ANGLE not setup (not on whitelist, ANGLE not present, etc.)
+ * false: ANGLE not setup (not on allowlist, ANGLE not present, etc.)
*/
public boolean setupAngle(Context context, Bundle bundle, PackageManager pm,
String packageName) {
@@ -750,8 +750,8 @@ public class GraphicsEnvironment {
// 2. GAME_DRIVER_OPT_OUT_APPS
// 3. GAME_DRIVER_PRERELEASE_OPT_IN_APPS
// 4. GAME_DRIVER_OPT_IN_APPS
- // 5. GAME_DRIVER_BLACKLIST
- // 6. GAME_DRIVER_WHITELIST
+ // 5. GAME_DRIVER_DENYLIST
+ // 6. GAME_DRIVER_ALLOWLIST
switch (coreSettings.getInt(Settings.Global.GAME_DRIVER_ALL_APPS, 0)) {
case GAME_DRIVER_GLOBAL_OPT_IN_OFF:
if (DEBUG) Log.v(TAG, "Game Driver is turned off on this device.");
@@ -790,21 +790,21 @@ public class GraphicsEnvironment {
final boolean isOptIn =
getGlobalSettingsString(null, coreSettings, Settings.Global.GAME_DRIVER_OPT_IN_APPS)
.contains(appPackageName);
- final List<String> whitelist =
- getGlobalSettingsString(null, coreSettings, Settings.Global.GAME_DRIVER_WHITELIST);
- if (!isOptIn && whitelist.indexOf(GAME_DRIVER_WHITELIST_ALL) != 0
- && !whitelist.contains(appPackageName)) {
- if (DEBUG) Log.v(TAG, "App is not on the whitelist for Game Driver.");
+ final List<String> allowlist =
+ getGlobalSettingsString(null, coreSettings, Settings.Global.GAME_DRIVER_ALLOWLIST);
+ if (!isOptIn && allowlist.indexOf(GAME_DRIVER_ALLOWLIST_ALL) != 0
+ && !allowlist.contains(appPackageName)) {
+ if (DEBUG) Log.v(TAG, "App is not on the allowlist for Game Driver.");
return null;
}
- // If the application is not opted-in, then check whether it's on the blacklist,
- // terminate early if it's on the blacklist and fallback to system driver.
+ // If the application is not opted-in, then check whether it's on the denylist,
+ // terminate early if it's on the denylist and fallback to system driver.
if (!isOptIn
&& getGlobalSettingsString(
- null, coreSettings, Settings.Global.GAME_DRIVER_BLACKLIST)
+ null, coreSettings, Settings.Global.GAME_DRIVER_DENYLIST)
.contains(appPackageName)) {
- if (DEBUG) Log.v(TAG, "App is on the blacklist for Game Driver.");
+ if (DEBUG) Log.v(TAG, "App is on the denylist for Game Driver.");
return null;
}
diff --git a/core/java/android/os/Looper.java b/core/java/android/os/Looper.java
index a7e326378228..b05ea39850f8 100644
--- a/core/java/android/os/Looper.java
+++ b/core/java/android/os/Looper.java
@@ -94,6 +94,11 @@ public final class Looper {
*/
private long mSlowDeliveryThresholdMs;
+ /**
+ * True if a message delivery takes longer than {@link #mSlowDeliveryThresholdMs}.
+ */
+ private boolean mSlowDeliveryDetected;
+
/** Initialize the current thread as a looper.
* This gives you a chance to create handlers that then reference
* this looper, before actually starting the loop. Be sure to call
@@ -148,6 +153,105 @@ public final class Looper {
}
/**
+ * Poll and deliver single message, return true if the outer loop should continue.
+ */
+ private static boolean loopOnce(final Looper me,
+ final long ident, final int thresholdOverride) {
+ Message msg = me.mQueue.next(); // might block
+ if (msg == null) {
+ // No message indicates that the message queue is quitting.
+ return false;
+ }
+
+ // This must be in a local variable, in case a UI event sets the logger
+ final Printer logging = me.mLogging;
+ if (logging != null) {
+ logging.println(">>>>> Dispatching to " + msg.target + " "
+ + msg.callback + ": " + msg.what);
+ }
+ // Make sure the observer won't change while processing a transaction.
+ final Observer observer = sObserver;
+
+ final long traceTag = me.mTraceTag;
+ long slowDispatchThresholdMs = me.mSlowDispatchThresholdMs;
+ long slowDeliveryThresholdMs = me.mSlowDeliveryThresholdMs;
+ if (thresholdOverride > 0) {
+ slowDispatchThresholdMs = thresholdOverride;
+ slowDeliveryThresholdMs = thresholdOverride;
+ }
+ final boolean logSlowDelivery = (slowDeliveryThresholdMs > 0) && (msg.when > 0);
+ final boolean logSlowDispatch = (slowDispatchThresholdMs > 0);
+
+ final boolean needStartTime = logSlowDelivery || logSlowDispatch;
+ final boolean needEndTime = logSlowDispatch;
+
+ if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
+ Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
+ }
+
+ final long dispatchStart = needStartTime ? SystemClock.uptimeMillis() : 0;
+ final long dispatchEnd;
+ Object token = null;
+ if (observer != null) {
+ token = observer.messageDispatchStarting();
+ }
+ long origWorkSource = ThreadLocalWorkSource.setUid(msg.workSourceUid);
+ try {
+ msg.target.dispatchMessage(msg);
+ if (observer != null) {
+ observer.messageDispatched(token, msg);
+ }
+ dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
+ } catch (Exception exception) {
+ if (observer != null) {
+ observer.dispatchingThrewException(token, msg, exception);
+ }
+ throw exception;
+ } finally {
+ ThreadLocalWorkSource.restore(origWorkSource);
+ if (traceTag != 0) {
+ Trace.traceEnd(traceTag);
+ }
+ }
+ if (logSlowDelivery) {
+ if (me.mSlowDeliveryDetected) {
+ if ((dispatchStart - msg.when) <= 10) {
+ Slog.w(TAG, "Drained");
+ me.mSlowDeliveryDetected = false;
+ }
+ } else {
+ if (showSlowLog(slowDeliveryThresholdMs, msg.when, dispatchStart, "delivery",
+ msg)) {
+ // Once we write a slow delivery log, suppress until the queue drains.
+ me.mSlowDeliveryDetected = true;
+ }
+ }
+ }
+ if (logSlowDispatch) {
+ showSlowLog(slowDispatchThresholdMs, dispatchStart, dispatchEnd, "dispatch", msg);
+ }
+
+ if (logging != null) {
+ logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
+ }
+
+ // Make sure that during the course of dispatching the
+ // identity of the thread wasn't corrupted.
+ final long newIdent = Binder.clearCallingIdentity();
+ if (ident != newIdent) {
+ Log.wtf(TAG, "Thread identity changed from 0x"
+ + Long.toHexString(ident) + " to 0x"
+ + Long.toHexString(newIdent) + " while dispatching to "
+ + msg.target.getClass().getName() + " "
+ + msg.callback + " what=" + msg.what);
+ }
+
+ msg.recycleUnchecked();
+
+ return true;
+ }
+
+ /**
* Run the message queue in this thread. Be sure to call
* {@link #quit()} to end the loop.
*/
@@ -162,7 +266,6 @@ public final class Looper {
}
me.mInLoop = true;
- final MessageQueue queue = me.mQueue;
// Make sure the identity of this thread is that of the local process,
// and keep track of what that identity token actually is.
@@ -177,99 +280,12 @@ public final class Looper {
+ Thread.currentThread().getName()
+ ".slow", 0);
- boolean slowDeliveryDetected = false;
+ me.mSlowDeliveryDetected = false;
for (;;) {
- Message msg = queue.next(); // might block
- if (msg == null) {
- // No message indicates that the message queue is quitting.
+ if (!loopOnce(me, ident, thresholdOverride)) {
return;
}
-
- // This must be in a local variable, in case a UI event sets the logger
- final Printer logging = me.mLogging;
- if (logging != null) {
- logging.println(">>>>> Dispatching to " + msg.target + " " +
- msg.callback + ": " + msg.what);
- }
- // Make sure the observer won't change while processing a transaction.
- final Observer observer = sObserver;
-
- final long traceTag = me.mTraceTag;
- long slowDispatchThresholdMs = me.mSlowDispatchThresholdMs;
- long slowDeliveryThresholdMs = me.mSlowDeliveryThresholdMs;
- if (thresholdOverride > 0) {
- slowDispatchThresholdMs = thresholdOverride;
- slowDeliveryThresholdMs = thresholdOverride;
- }
- final boolean logSlowDelivery = (slowDeliveryThresholdMs > 0) && (msg.when > 0);
- final boolean logSlowDispatch = (slowDispatchThresholdMs > 0);
-
- final boolean needStartTime = logSlowDelivery || logSlowDispatch;
- final boolean needEndTime = logSlowDispatch;
-
- if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
- Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
- }
-
- final long dispatchStart = needStartTime ? SystemClock.uptimeMillis() : 0;
- final long dispatchEnd;
- Object token = null;
- if (observer != null) {
- token = observer.messageDispatchStarting();
- }
- long origWorkSource = ThreadLocalWorkSource.setUid(msg.workSourceUid);
- try {
- msg.target.dispatchMessage(msg);
- if (observer != null) {
- observer.messageDispatched(token, msg);
- }
- dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
- } catch (Exception exception) {
- if (observer != null) {
- observer.dispatchingThrewException(token, msg, exception);
- }
- throw exception;
- } finally {
- ThreadLocalWorkSource.restore(origWorkSource);
- if (traceTag != 0) {
- Trace.traceEnd(traceTag);
- }
- }
- if (logSlowDelivery) {
- if (slowDeliveryDetected) {
- if ((dispatchStart - msg.when) <= 10) {
- Slog.w(TAG, "Drained");
- slowDeliveryDetected = false;
- }
- } else {
- if (showSlowLog(slowDeliveryThresholdMs, msg.when, dispatchStart, "delivery",
- msg)) {
- // Once we write a slow delivery log, suppress until the queue drains.
- slowDeliveryDetected = true;
- }
- }
- }
- if (logSlowDispatch) {
- showSlowLog(slowDispatchThresholdMs, dispatchStart, dispatchEnd, "dispatch", msg);
- }
-
- if (logging != null) {
- logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
- }
-
- // Make sure that during the course of dispatching the
- // identity of the thread wasn't corrupted.
- final long newIdent = Binder.clearCallingIdentity();
- if (ident != newIdent) {
- Log.wtf(TAG, "Thread identity changed from 0x"
- + Long.toHexString(ident) + " to 0x"
- + Long.toHexString(newIdent) + " while dispatching to "
- + msg.target.getClass().getName() + " "
- + msg.callback + " what=" + msg.what);
- }
-
- msg.recycleUnchecked();
}
}
diff --git a/core/java/android/os/Parcelable.java b/core/java/android/os/Parcelable.java
index bedbba04255e..3d3759e695e0 100644
--- a/core/java/android/os/Parcelable.java
+++ b/core/java/android/os/Parcelable.java
@@ -17,6 +17,7 @@
package android.os;
import android.annotation.IntDef;
+import android.annotation.SystemApi;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -119,6 +120,7 @@ public interface Parcelable {
* @see ParcelableHolder
* @hide
*/
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public static final int PARCELABLE_STABILITY_LOCAL = 0x0000;
/**
* Something that is meant to be used between system and vendor.
@@ -126,6 +128,7 @@ public interface Parcelable {
* @see ParcelableHolder
* @hide
*/
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public static final int PARCELABLE_STABILITY_VINTF = 0x0001;
/**
diff --git a/core/java/android/os/TEST_MAPPING b/core/java/android/os/TEST_MAPPING
index f4645caee511..39c196d1a06c 100644
--- a/core/java/android/os/TEST_MAPPING
+++ b/core/java/android/os/TEST_MAPPING
@@ -1,6 +1,14 @@
{
"presubmit": [
- // TODO(159590499) add BugreportManagerTestCases
+ {
+ "file_patterns": ["Bugreport[^/]*\\.java"],
+ "name": "BugreportManagerTestCases",
+ "options": [
+ {
+ "exclude-annotation": "androidx.test.filters.LargeTest"
+ }
+ ]
+ },
{
"file_patterns": ["Bugreport[^/]*\\.java"],
"name": "CtsBugreportTestCases",
diff --git a/core/java/android/os/VibrationAttributes.java b/core/java/android/os/VibrationAttributes.java
index f4aa354a8574..8a7cf608cfb8 100644
--- a/core/java/android/os/VibrationAttributes.java
+++ b/core/java/android/os/VibrationAttributes.java
@@ -310,6 +310,7 @@ public final class VibrationAttributes implements Parcelable {
@Nullable VibrationEffect effect) {
mAudioAttributes = audio;
setUsage(audio);
+ setFlags(audio);
applyHapticFeedbackHeuristics(effect);
}
@@ -366,6 +367,12 @@ public final class VibrationAttributes implements Parcelable {
}
}
+ private void setFlags(@NonNull AudioAttributes audio) {
+ if ((audio.getAllFlags() & AudioAttributes.FLAG_BYPASS_INTERRUPTION_POLICY) != 0) {
+ mFlags |= FLAG_BYPASS_INTERRUPTION_POLICY;
+ }
+ }
+
/**
* Combines all of the attributes that have been set and returns a new
* {@link VibrationAttributes} object.
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 346522a504c8..cfe7edd75dd8 100755..100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -9794,6 +9794,21 @@ public final class Settings {
"hdmi_control_auto_device_off_enabled";
/**
+ * Property to decide which devices the playback device can send a <Standby> message to upon
+ * going to sleep. Supported values are:
+ * <ul>
+ * <li>{@link HdmiControlManager#SEND_STANDBY_ON_SLEEP_TO_TV} to TV only.</li>
+ * <li>{@link HdmiControlManager#SEND_STANDBY_ON_SLEEP_BROADCAST} to all devices in the
+ * network.</li>
+ * <li>{@link HdmiControlManager#SEND_STANDBY_ON_SLEEP_NONE} no <Standby> message sent.</li>
+ * </ul>
+ *
+ * @hide
+ */
+ public static final String HDMI_CONTROL_SEND_STANDBY_ON_SLEEP =
+ "hdmi_control_send_standby_on_sleep";
+
+ /**
* Whether or not media is shown automatically when bypassing as a heads up.
* @hide
*/
@@ -10840,17 +10855,6 @@ public final class Settings {
public static final String MODE_RINGER = "mode_ringer";
/**
- * Specifies whether Enhanced Connectivity is enabled or not. This setting allows the
- * Connectivity Thermal Power Manager to actively help the device to save power in 5G
- * scenarios
- * Type: int 1 is enabled, 0 is disabled
- *
- * @hide
- */
- public static final String ENHANCED_CONNECTIVITY_ENABLED =
- "enhanced_connectivity_enable";
-
- /**
* Overlay display devices setting.
* The associated value is a specially formatted string that describes the
* size and density of simulated secondary display devices.
@@ -12377,24 +12381,24 @@ public final class Settings {
public static final String GAME_DRIVER_OPT_OUT_APPS = "game_driver_opt_out_apps";
/**
- * Apps on the blacklist that are forbidden to use Game Driver.
+ * Apps on the denylist that are forbidden to use Game Driver.
* @hide
*/
- public static final String GAME_DRIVER_BLACKLIST = "game_driver_blacklist";
+ public static final String GAME_DRIVER_DENYLIST = "game_driver_denylist";
/**
- * List of blacklists, each blacklist is a blacklist for a specific version of Game Driver.
+ * List of denylists, each denylist is a denylist for a specific version of Game Driver.
* @hide
*/
- public static final String GAME_DRIVER_BLACKLISTS = "game_driver_blacklists";
+ public static final String GAME_DRIVER_DENYLISTS = "game_driver_denylists";
/**
- * Apps on the whitelist that are allowed to use Game Driver.
+ * Apps on the allowlist that are allowed to use Game Driver.
* The string is a list of application package names, seperated by comma.
* i.e. <apk1>,<apk2>,...,<apkN>
* @hide
*/
- public static final String GAME_DRIVER_WHITELIST = "game_driver_whitelist";
+ public static final String GAME_DRIVER_ALLOWLIST = "game_driver_allowlist";
/**
* List of libraries in sphal accessible by Game Driver
diff --git a/core/java/android/security/net/config/NetworkSecurityConfig.java b/core/java/android/security/net/config/NetworkSecurityConfig.java
index 57068fa2eb63..00872fb3b62d 100644
--- a/core/java/android/security/net/config/NetworkSecurityConfig.java
+++ b/core/java/android/security/net/config/NetworkSecurityConfig.java
@@ -216,7 +216,7 @@ public final class NetworkSecurityConfig {
* in {@link Builder#build()}, recursively if needed.
*/
public Builder setParent(Builder parent) {
- // Sanity check to avoid adding loops.
+ // Quick check to avoid adding loops.
Builder current = parent;
while (current != null) {
if (current == this) {
diff --git a/core/java/android/service/notification/NotificationStats.java b/core/java/android/service/notification/NotificationStats.java
index 8be114ca321e..2cd8b8ba42d9 100644
--- a/core/java/android/service/notification/NotificationStats.java
+++ b/core/java/android/service/notification/NotificationStats.java
@@ -73,6 +73,11 @@ public final class NotificationStats implements Parcelable {
* Notification has been dismissed from the notification shade.
*/
public static final int DISMISSAL_SHADE = 3;
+ /**
+ * Notification has been dismissed as a bubble.
+ * @hide
+ */
+ public static final int DISMISSAL_BUBBLE = 3;
/** @hide */
@IntDef(prefix = { "DISMISS_SENTIMENT_" }, value = {
diff --git a/core/java/android/telephony/TelephonyRegistryManager.java b/core/java/android/telephony/TelephonyRegistryManager.java
index 8ab120f78835..0a47032354f5 100644
--- a/core/java/android/telephony/TelephonyRegistryManager.java
+++ b/core/java/android/telephony/TelephonyRegistryManager.java
@@ -107,7 +107,6 @@ public class TelephonyRegistryManager {
IOnSubscriptionsChangedListener callback = new IOnSubscriptionsChangedListener.Stub() {
@Override
public void onSubscriptionsChanged () {
- Log.d(TAG, "onSubscriptionsChangedListener callback received.");
executor.execute(() -> listener.onSubscriptionsChanged());
}
};
diff --git a/core/java/android/text/format/DateIntervalFormat.java b/core/java/android/text/format/DateIntervalFormat.java
index de9ec7ab9ea9..e8236fda42b6 100644
--- a/core/java/android/text/format/DateIntervalFormat.java
+++ b/core/java/android/text/format/DateIntervalFormat.java
@@ -62,7 +62,7 @@ public final class DateIntervalFormat {
/**
* Format a date range. This is our slightly more sensible internal API.
- * A truly sane replacement would take a skeleton instead of int flags.
+ * A truly reasonable replacement would take a skeleton instead of int flags.
*/
@VisibleForTesting(visibility = PACKAGE)
public static String formatDateRange(ULocale icuLocale, android.icu.util.TimeZone icuTimeZone,
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index 0cc469a2d5eb..c4048e5a032d 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -26,6 +26,7 @@ import android.annotation.SuppressLint;
import android.annotation.TestApi;
import android.app.KeyguardManager;
import android.compat.annotation.UnsupportedAppUsage;
+import android.content.Context;
import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
@@ -1157,9 +1158,19 @@ public final class Display {
* </p><p>
* The real size may be smaller than the physical size of the screen when the
* window manager is emulating a smaller display (using adb shell wm size).
- * </p>
+ * </p><p>
+ * In general, {@link #getRealSize(Point)} and {@link WindowManager#getMaximumWindowMetrics()}
+ * report the same bounds except that certain areas of the display may not be available to
+ * windows created in the {@link WindowManager}'s {@link Context}.
+ *
+ * For example, imagine a device which has a multi-task mode that limits windows to half of the
+ * screen. In this case, {@link WindowManager#getMaximumWindowMetrics()} reports the
+ * bounds of the screen half where the window is located, while {@link #getRealSize(Point)}
+ * still reports the bounds of the whole display.
*
* @param outSize Set to the real size of the display.
+ *
+ * @see WindowManager#getMaximumWindowMetrics()
*/
public void getRealSize(Point outSize) {
synchronized (this) {
diff --git a/core/java/android/view/FocusFinder.java b/core/java/android/view/FocusFinder.java
index 713cfb48c95f..064bc6947fc4 100644
--- a/core/java/android/view/FocusFinder.java
+++ b/core/java/android/view/FocusFinder.java
@@ -311,6 +311,9 @@ public class FocusFinder {
}
final int count = focusables.size();
+ if (count < 2) {
+ return null;
+ }
switch (direction) {
case View.FOCUS_FORWARD:
return getNextFocusable(focused, focusables, count);
@@ -373,29 +376,29 @@ public class FocusFinder {
}
private static View getNextFocusable(View focused, ArrayList<View> focusables, int count) {
+ if (count < 2) {
+ return null;
+ }
if (focused != null) {
int position = focusables.lastIndexOf(focused);
if (position >= 0 && position + 1 < count) {
return focusables.get(position + 1);
}
}
- if (!focusables.isEmpty()) {
- return focusables.get(0);
- }
- return null;
+ return focusables.get(0);
}
private static View getPreviousFocusable(View focused, ArrayList<View> focusables, int count) {
+ if (count < 2) {
+ return null;
+ }
if (focused != null) {
int position = focusables.indexOf(focused);
if (position > 0) {
return focusables.get(position - 1);
}
}
- if (!focusables.isEmpty()) {
- return focusables.get(count - 1);
- }
- return null;
+ return focusables.get(count - 1);
}
private static View getNextKeyboardNavigationCluster(
diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java
index ecf97749d349..8cb8e1d12d8a 100644
--- a/core/java/android/view/Surface.java
+++ b/core/java/android/view/Surface.java
@@ -22,6 +22,7 @@ import android.annotation.FloatRange;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.compat.annotation.UnsupportedAppUsage;
+import android.content.pm.ActivityInfo;
import android.content.res.CompatibilityInfo.Translator;
import android.graphics.Canvas;
import android.graphics.ColorSpace;
@@ -1001,7 +1002,10 @@ public class Surface implements Parcelable {
mHardwareRenderer = new HardwareRenderer();
mHardwareRenderer.setContentRoot(mRenderNode);
mHardwareRenderer.setSurface(Surface.this, true);
- mHardwareRenderer.setWideGamut(isWideColorGamut);
+ mHardwareRenderer.setColorMode(
+ isWideColorGamut
+ ? ActivityInfo.COLOR_MODE_WIDE_COLOR_GAMUT
+ : ActivityInfo.COLOR_MODE_DEFAULT);
mHardwareRenderer.setLightSourceAlpha(0.0f, 0.0f);
mHardwareRenderer.setLightSourceGeometry(0.0f, 0.0f, 0.0f, 0.0f);
}
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 6beea8764ed1..eaa7eafc23cc 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -595,6 +595,256 @@ public final class SurfaceControl implements Parcelable {
}
/**
+ * A common arguments class used for various screenshot requests. This contains arguments that
+ * are shared between {@link DisplayCaptureArgs} and {@link LayerCaptureArgs}
+ * @hide
+ */
+ public abstract static class CaptureArgs {
+ private final int mPixelFormat;
+ private final Rect mSourceCrop = new Rect();
+ private final float mFrameScale;
+ private final boolean mCaptureSecureLayers;
+
+ private CaptureArgs(Builder<? extends Builder<?>> builder) {
+ mPixelFormat = builder.mPixelFormat;
+ mSourceCrop.set(builder.mSourceCrop);
+ mFrameScale = builder.mFrameScale;
+ mCaptureSecureLayers = builder.mCaptureSecureLayers;
+ }
+
+ /**
+ * The Builder class used to construct {@link CaptureArgs}
+ *
+ * @param <T> A builder that extends {@link Builder}
+ */
+ public abstract static class Builder<T extends Builder<T>> {
+ private int mPixelFormat = PixelFormat.RGBA_8888;
+ private final Rect mSourceCrop = new Rect();
+ private float mFrameScale = 1;
+ private boolean mCaptureSecureLayers;
+
+ /**
+ * The desired pixel format of the returned buffer.
+ */
+ public T setPixelFormat(int pixelFormat) {
+ mPixelFormat = pixelFormat;
+ return getThis();
+ }
+
+ /**
+ * The portion of the screen to capture into the buffer. Caller may pass in
+ * 'new Rect()' if no cropping is desired.
+ */
+ public T setSourceCrop(Rect sourceCrop) {
+ mSourceCrop.set(sourceCrop);
+ return getThis();
+ }
+
+ /**
+ * The desired scale of the returned buffer. The raw screen will be scaled up/down.
+ */
+ public T setFrameScale(float frameScale) {
+ mFrameScale = frameScale;
+ return getThis();
+ }
+
+ /**
+ * Whether to allow the screenshot of secure layers. Warning: This should only be done
+ * if the content will be placed in a secure SurfaceControl.
+ *
+ * @see ScreenshotHardwareBuffer#containsSecureLayers()
+ */
+ public T setCaptureSecureLayers(boolean captureSecureLayers) {
+ mCaptureSecureLayers = captureSecureLayers;
+ return getThis();
+ }
+
+ /**
+ * Each sub class should return itself to allow the builder to chain properly
+ */
+ public abstract T getThis();
+ }
+ }
+
+ /**
+ * The arguments class used to make display capture requests.
+ *
+ * @see #nativeScreenshot(IBinder, Rect, int, int, boolean, int, boolean)
+ * @hide
+ */
+ public static class DisplayCaptureArgs extends CaptureArgs {
+ private final IBinder mDisplayToken;
+ private final int mWidth;
+ private final int mHeight;
+ private final boolean mUseIdentityTransform;
+ private final int mRotation;
+
+ private DisplayCaptureArgs(Builder builder) {
+ super(builder);
+ mDisplayToken = builder.mDisplayToken;
+ mWidth = builder.mWidth;
+ mHeight = builder.mHeight;
+ mUseIdentityTransform = builder.mUseIdentityTransform;
+ mRotation = builder.mRotation;
+ }
+
+ /**
+ * The Builder class used to construct {@link DisplayCaptureArgs}
+ */
+ public static class Builder extends CaptureArgs.Builder<Builder> {
+ private IBinder mDisplayToken;
+ private int mWidth;
+ private int mHeight;
+ private boolean mUseIdentityTransform;
+ private @Surface.Rotation int mRotation = Surface.ROTATION_0;
+
+ /**
+ * Construct a new {@link LayerCaptureArgs} with the set parameters. The builder
+ * remains valid.
+ */
+ public DisplayCaptureArgs build() {
+ if (mDisplayToken == null) {
+ throw new IllegalStateException(
+ "Can't take screenshot with null display token");
+ }
+ return new DisplayCaptureArgs(this);
+ }
+
+ public Builder(IBinder displayToken) {
+ setDisplayToken(displayToken);
+ }
+
+ /**
+ * The display to take the screenshot of.
+ */
+ public Builder setDisplayToken(IBinder displayToken) {
+ mDisplayToken = displayToken;
+ return this;
+ }
+
+ /**
+ * Set the desired size of the returned buffer. The raw screen will be scaled down to
+ * this size
+ *
+ * @param width The desired width of the returned buffer. Caller may pass in 0 if no
+ * scaling is desired.
+ * @param height The desired height of the returned buffer. Caller may pass in 0 if no
+ * scaling is desired.
+ */
+ public Builder setSize(int width, int height) {
+ mWidth = width;
+ mHeight = height;
+ return this;
+ }
+
+ /**
+ * Replace whatever transformation (rotation, scaling, translation) the surface
+ * layers are currently using with the identity transformation while taking the
+ * screenshot.
+ */
+ public Builder setUseIdentityTransform(boolean useIdentityTransform) {
+ mUseIdentityTransform = useIdentityTransform;
+ return this;
+ }
+
+ /**
+ * Apply a custom clockwise rotation to the screenshot, i.e.
+ * Surface.ROTATION_0,90,180,270. SurfaceFlinger will always take screenshots in its
+ * native portrait orientation by default, so this is useful for returning screenshots
+ * that are independent of device orientation.
+ */
+ public Builder setRotation(@Surface.Rotation int rotation) {
+ mRotation = rotation;
+ return this;
+ }
+
+ @Override
+ public Builder getThis() {
+ return this;
+ }
+ }
+ }
+
+ /**
+ * The arguments class used to make layer capture requests.
+ *
+ * @see #nativeCaptureLayers(IBinder, long, Rect, float, long[], int)
+ * @hide
+ */
+ public static class LayerCaptureArgs extends CaptureArgs {
+ private final long mNativeLayer;
+ private final long[] mNativeExcludeLayers;
+ private final boolean mChildrenOnly;
+
+ private LayerCaptureArgs(Builder builder) {
+ super(builder);
+ mChildrenOnly = builder.mChildrenOnly;
+ mNativeLayer = builder.mLayer.mNativeObject;
+ mNativeExcludeLayers = new long[builder.mExcludeLayers.length];
+ for (int i = 0; i < builder.mExcludeLayers.length; i++) {
+ mNativeExcludeLayers[i] = builder.mExcludeLayers[i].mNativeObject;
+ }
+ }
+
+ /**
+ * The Builder class used to construct {@link LayerCaptureArgs}
+ */
+ public static class Builder extends CaptureArgs.Builder<Builder> {
+ private SurfaceControl mLayer;
+ private SurfaceControl[] mExcludeLayers;
+ private boolean mChildrenOnly = true;
+
+ /**
+ * Construct a new {@link LayerCaptureArgs} with the set parameters. The builder
+ * remains valid.
+ */
+ public LayerCaptureArgs build() {
+ if (mLayer == null) {
+ throw new IllegalStateException(
+ "Can't take screenshot with null layer");
+ }
+ return new LayerCaptureArgs(this);
+ }
+
+ public Builder(SurfaceControl layer) {
+ setLayer(layer);
+ }
+
+ /**
+ * The root layer to capture.
+ */
+ public Builder setLayer(SurfaceControl layer) {
+ mLayer = layer;
+ return this;
+ }
+
+
+ /**
+ * An array of layer handles to exclude.
+ */
+ public Builder setExcludeLayers(@Nullable SurfaceControl[] excludeLayers) {
+ mExcludeLayers = excludeLayers;
+ return this;
+ }
+
+ /**
+ * Whether to include the layer itself in the screenshot or just the children and their
+ * descendants.
+ */
+ public Builder setChildrenOnly(boolean childrenOnly) {
+ mChildrenOnly = childrenOnly;
+ return this;
+ }
+
+ @Override
+ public Builder getThis() {
+ return this;
+ }
+
+ }
+ }
+
+ /**
* Builder class for {@link SurfaceControl} objects.
*
* By default the surface will be hidden, and have "unset" bounds, meaning it can
@@ -1969,37 +2219,6 @@ public final class SurfaceControl implements Parcelable {
}
/**
- * @see SurfaceControl#screenshot(IBinder, Surface, Rect, int, int, boolean, int)
- * @hide
- */
- public static void screenshot(IBinder display, Surface consumer) {
- screenshot(display, consumer, new Rect(), 0, 0, false, 0);
- }
-
- /**
- * Copy the current screen contents into the provided {@link Surface}
- *
- * @param consumer The {@link Surface} to take the screenshot into.
- * @see SurfaceControl#screenshotToBuffer(IBinder, Rect, int, int, boolean, int)
- * @hide
- */
- public static void screenshot(IBinder display, Surface consumer, Rect sourceCrop, int width,
- int height, boolean useIdentityTransform, int rotation) {
- if (consumer == null) {
- throw new IllegalArgumentException("consumer must not be null");
- }
-
- final ScreenshotHardwareBuffer buffer = screenshotToBuffer(display, sourceCrop, width,
- height, useIdentityTransform, rotation);
- try {
- consumer.attachAndQueueBufferWithColorSpace(buffer.getHardwareBuffer(),
- buffer.getColorSpace());
- } catch (RuntimeException e) {
- Log.w(TAG, "Failed to take screenshot - " + e.getMessage());
- }
- }
-
- /**
* @see SurfaceControl#screenshot(Rect, int, int, boolean, int)}
* @hide
*/
@@ -2014,8 +2233,7 @@ public final class SurfaceControl implements Parcelable {
* a software Bitmap using {@link Bitmap#copy(Bitmap.Config, boolean)}
*
* CAVEAT: Versions of screenshot that return a {@link Bitmap} can be extremely slow; avoid use
- * unless absolutely necessary; prefer the versions that use a {@link Surface} such as
- * {@link SurfaceControl#screenshot(IBinder, Surface)} or {@link HardwareBuffer} such as
+ * unless absolutely necessary; prefer the versions that use a {@link HardwareBuffer} such as
* {@link SurfaceControl#screenshotToBuffer(IBinder, Rect, int, int, boolean, int)}.
*
* @see SurfaceControl#screenshotToBuffer(IBinder, Rect, int, int, boolean, int)}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index e951156ec4cc..ef4bc918db6a 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -952,8 +952,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
/**
* Prior to P, {@code #startDragAndDrop} accepts a builder which produces an empty drag shadow.
- * Currently zero size SurfaceControl cannot be created thus we create a dummy 1x1 surface
- * instead.
+ * Currently zero size SurfaceControl cannot be created thus we create a 1x1 surface instead.
*/
private static boolean sAcceptZeroSizeDragShadow;
@@ -30023,7 +30022,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
/**
* Dump all private flags in readable format, useful for documentation and
- * sanity checking.
+ * consistency checking.
*/
private static void dumpFlags() {
final HashMap<String, String> found = Maps.newHashMap();
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index fe6f33da6d2a..2a2d1e6c4c77 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -1329,13 +1329,9 @@ public final class ViewRootImpl implements ViewParent,
final boolean hasSurfaceInsets = insets.left != 0 || insets.right != 0
|| insets.top != 0 || insets.bottom != 0;
final boolean translucent = attrs.format != PixelFormat.OPAQUE || hasSurfaceInsets;
- final boolean wideGamut =
- mContext.getResources().getConfiguration().isScreenWideColorGamut()
- && attrs.getColorMode() == ActivityInfo.COLOR_MODE_WIDE_COLOR_GAMUT;
-
mAttachInfo.mThreadedRenderer = ThreadedRenderer.create(mContext, translucent,
attrs.getTitle().toString());
- mAttachInfo.mThreadedRenderer.setWideGamut(wideGamut);
+ updateColorModeIfNeeded(attrs.getColorMode());
updateForceDarkMode();
if (mAttachInfo.mThreadedRenderer != null) {
mAttachInfo.mHardwareAccelerated =
@@ -2648,7 +2644,7 @@ public final class ViewRootImpl implements ViewParent,
& WindowManagerGlobal.RELAYOUT_RES_SURFACE_RESIZED) != 0;
final boolean alwaysConsumeSystemBarsChanged =
mPendingAlwaysConsumeSystemBars != mAttachInfo.mAlwaysConsumeSystemBars;
- final boolean colorModeChanged = hasColorModeChanged(lp.getColorMode());
+ updateColorModeIfNeeded(lp.getColorMode());
surfaceCreated = !hadSurface && mSurface.isValid();
surfaceDestroyed = hadSurface && !mSurface.isValid();
surfaceReplaced = (surfaceGenerationId != mSurface.getGenerationId())
@@ -2677,10 +2673,6 @@ public final class ViewRootImpl implements ViewParent,
// hierarchy is measured below.
dispatchApplyInsets = true;
}
- if (colorModeChanged && mAttachInfo.mThreadedRenderer != null) {
- mAttachInfo.mThreadedRenderer.setWideGamut(
- lp.getColorMode() == ActivityInfo.COLOR_MODE_WIDE_COLOR_GAMUT);
- }
if (surfaceCreated) {
// If we are creating a new surface, then we need to
@@ -2725,7 +2717,7 @@ public final class ViewRootImpl implements ViewParent,
mAttachInfo.mThreadedRenderer.destroy();
}
} else if ((surfaceReplaced
- || surfaceSizeChanged || windowRelayoutWasForced || colorModeChanged)
+ || surfaceSizeChanged || windowRelayoutWasForced)
&& mSurfaceHolder == null
&& mAttachInfo.mThreadedRenderer != null
&& mSurface.isValid()) {
@@ -4032,7 +4024,7 @@ public final class ViewRootImpl implements ViewParent,
yOffset -= surfaceInsets.top;
// Offset dirty rect for surface insets.
- dirty.offset(surfaceInsets.left, surfaceInsets.right);
+ dirty.offset(surfaceInsets.left, surfaceInsets.top);
}
boolean accessibilityFocusDirty = false;
@@ -4557,18 +4549,16 @@ public final class ViewRootImpl implements ViewParent,
}
}
- private boolean hasColorModeChanged(int colorMode) {
+ private void updateColorModeIfNeeded(int colorMode) {
if (mAttachInfo.mThreadedRenderer == null) {
- return false;
- }
- final boolean isWideGamut = colorMode == ActivityInfo.COLOR_MODE_WIDE_COLOR_GAMUT;
- if (mAttachInfo.mThreadedRenderer.isWideGamut() == isWideGamut) {
- return false;
+ return;
}
- if (isWideGamut && !mContext.getResources().getConfiguration().isScreenWideColorGamut()) {
- return false;
+ // TODO: Centralize this sanitization? Why do we let setting bad modes?
+ // Alternatively, can we just let HWUI figure it out? Do we need to care here?
+ if (!mContext.getResources().getConfiguration().isScreenWideColorGamut()) {
+ colorMode = ActivityInfo.COLOR_MODE_DEFAULT;
}
- return true;
+ mAttachInfo.mThreadedRenderer.setColorMode(colorMode);
}
@Override
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 1d54d9251abb..cf4315fc7c00 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -72,6 +72,7 @@ import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.graphics.PixelFormat;
+import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.Region;
import android.os.IBinder;
@@ -473,9 +474,18 @@ public interface WindowManager extends ViewManager {
*
* Note that this might still be smaller than the size of the physical display if certain areas
* of the display are not available to windows created in this {@link Context}.
+ * <p>
+ * For example, given that there's a device which have a multi-task mode to limit activities
+ * to a half screen. In this case, {@link #getMaximumWindowMetrics()} reports the bounds of
+ * the half screen which the activity is located, while {@link Display#getRealSize(Point)} still
+ * reports the bounds of the whole physical display.
*
- * @see #getMaximumWindowMetrics()
+ * Despite this, {@link #getMaximumWindowMetrics()} and {@link Display#getRealSize(Point)}
+ * reports the same bounds in general.
+ *
+ * @see #getCurrentWindowMetrics()
* @see WindowMetrics
+ * @see Display#getRealSize(Point)
*/
default @NonNull WindowMetrics getMaximumWindowMetrics() {
throw new UnsupportedOperationException();
diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java
index 2fe7c021bb21..b4561c5795b9 100644
--- a/core/java/android/view/WindowManagerImpl.java
+++ b/core/java/android/view/WindowManagerImpl.java
@@ -29,7 +29,6 @@ import android.app.ResourcesManager;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.graphics.Insets;
-import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.Region;
import android.os.Bundle;
@@ -233,17 +232,16 @@ public final class WindowManagerImpl implements WindowManager {
@Override
public WindowMetrics getMaximumWindowMetrics() {
- final Rect maxBounds = getMaximumBounds();
+ final Context context = mParentWindow != null ? mParentWindow.getContext() : mContext;
+ final Rect maxBounds = getMaximumBounds(context);
+
return new WindowMetrics(maxBounds, computeWindowInsets(maxBounds));
}
- private Rect getMaximumBounds() {
- // TODO(b/128338354): Current maximum bound is display size, but it should be displayArea
- // bound after displayArea feature is finished.
- final Display display = mContext.getDisplayNoVerify();
- final Point displaySize = new Point();
- display.getRealSize(displaySize);
- return new Rect(0, 0, displaySize.x, displaySize.y);
+ private static Rect getMaximumBounds(Context context) {
+ synchronized (ResourcesManager.getInstance()) {
+ return context.getResources().getConfiguration().windowConfiguration.getMaxBounds();
+ }
}
// TODO(b/150095967): Set window type to LayoutParams
diff --git a/core/java/android/view/accessibility/IWindowMagnificationConnectionCallback.aidl b/core/java/android/view/accessibility/IWindowMagnificationConnectionCallback.aidl
index 2d05591a8131..2343bf3e8d19 100644
--- a/core/java/android/view/accessibility/IWindowMagnificationConnectionCallback.aidl
+++ b/core/java/android/view/accessibility/IWindowMagnificationConnectionCallback.aidl
@@ -19,7 +19,7 @@ package android.view.accessibility;
import android.graphics.Rect;
/**
- * interface to notify the change of the window magnifier bounds and request to change
+ * interface to notify the changes of the window magnification and request to change
* the magnification mode.
*
* @hide
@@ -27,12 +27,13 @@ import android.graphics.Rect;
oneway interface IWindowMagnificationConnectionCallback {
/**
- * Called when the bounds of the window magnifier is changed.
+ * Called when the bounds of the mirrow window is changed.
*
* @param displayId The logical display id.
* @param bounds The window magnifier bounds in screen coordinates.
*/
void onWindowMagnifierBoundsChanged(int displayId, in Rect bounds);
+
/**
* Changes the magnification mode on specified display. It is invoked by System UI when the
* switch button is toggled.
@@ -41,4 +42,12 @@ import android.graphics.Rect;
* @param magnificationMode new magnification mode.
*/
void onChangeMagnificationMode(int displayId, int magnificationMode);
+
+ /**
+ * Called when the magnified bounds is changed.
+ *
+ * @param displayId The logical display id.
+ * @param sourceBounds The magnified bounds in screen coordinates.
+ */
+ void onSourceBoundsChanged(int displayId, in Rect sourceBounds);
}
diff --git a/core/java/android/view/inputmethod/InlineSuggestionsRequest.java b/core/java/android/view/inputmethod/InlineSuggestionsRequest.java
index cce109074d82..6300320f5eb5 100644
--- a/core/java/android/view/inputmethod/InlineSuggestionsRequest.java
+++ b/core/java/android/view/inputmethod/InlineSuggestionsRequest.java
@@ -47,6 +47,9 @@ public final class InlineSuggestionsRequest implements Parcelable {
/**
* Max number of suggestions expected from the response. It must be a positive value.
* Defaults to {@code SUGGESTION_COUNT_UNLIMITED} if not set.
+ *
+ * <p>In practice, it is recommended that the max suggestion count does not exceed <b>5</b>
+ * for performance reasons.</p>
*/
private final int mMaxSuggestionCount;
@@ -67,6 +70,9 @@ public final class InlineSuggestionsRequest implements Parcelable {
/**
* The IME provided locales for the request. If non-empty, the inline suggestions should
* return languages from the supported locales. If not provided, it'll default to system locale.
+ *
+ * <p>Note for Autofill Providers: It is <b>recommended</b> for the returned inline suggestions
+ * to have one locale to guarantee consistent UI rendering.</p>
*/
private @NonNull LocaleList mSupportedLocales;
@@ -227,6 +233,9 @@ public final class InlineSuggestionsRequest implements Parcelable {
/**
* Max number of suggestions expected from the response. It must be a positive value.
* Defaults to {@code SUGGESTION_COUNT_UNLIMITED} if not set.
+ *
+ * <p>In practice, it is recommended that the max suggestion count does not exceed <b>5</b>
+ * for performance reasons.</p>
*/
@DataClass.Generated.Member
public int getMaxSuggestionCount() {
@@ -256,6 +265,9 @@ public final class InlineSuggestionsRequest implements Parcelable {
/**
* The IME provided locales for the request. If non-empty, the inline suggestions should
* return languages from the supported locales. If not provided, it'll default to system locale.
+ *
+ * <p>Note for Autofill Providers: It is <b>recommended</b> for the returned inline suggestions
+ * to have one locale to guarantee consistent UI rendering.</p>
*/
@DataClass.Generated.Member
public @NonNull LocaleList getSupportedLocales() {
@@ -458,6 +470,9 @@ public final class InlineSuggestionsRequest implements Parcelable {
/**
* Max number of suggestions expected from the response. It must be a positive value.
* Defaults to {@code SUGGESTION_COUNT_UNLIMITED} if not set.
+ *
+ * <p>In practice, it is recommended that the max suggestion count does not exceed <b>5</b>
+ * for performance reasons.</p>
*/
@DataClass.Generated.Member
public @NonNull Builder setMaxSuggestionCount(int value) {
@@ -508,6 +523,9 @@ public final class InlineSuggestionsRequest implements Parcelable {
/**
* The IME provided locales for the request. If non-empty, the inline suggestions should
* return languages from the supported locales. If not provided, it'll default to system locale.
+ *
+ * <p>Note for Autofill Providers: It is <b>recommended</b> for the returned inline suggestions
+ * to have one locale to guarantee consistent UI rendering.</p>
*/
@DataClass.Generated.Member
public @NonNull Builder setSupportedLocales(@NonNull LocaleList value) {
@@ -604,7 +622,7 @@ public final class InlineSuggestionsRequest implements Parcelable {
}
@DataClass.Generated(
- time = 1588109685838L,
+ time = 1595457701315L,
codegenVersion = "1.0.15",
sourceFile = "frameworks/base/core/java/android/view/inputmethod/InlineSuggestionsRequest.java",
inputSignatures = "public static final int SUGGESTION_COUNT_UNLIMITED\nprivate final int mMaxSuggestionCount\nprivate final @android.annotation.NonNull java.util.List<android.widget.inline.InlinePresentationSpec> mInlinePresentationSpecs\nprivate @android.annotation.NonNull java.lang.String mHostPackageName\nprivate @android.annotation.NonNull android.os.LocaleList mSupportedLocales\nprivate @android.annotation.NonNull android.os.Bundle mExtras\nprivate @android.annotation.Nullable android.os.IBinder mHostInputToken\nprivate int mHostDisplayId\npublic void setHostInputToken(android.os.IBinder)\nprivate boolean extrasEquals(android.os.Bundle)\nprivate void parcelHostInputToken(android.os.Parcel,int)\nprivate @android.annotation.Nullable android.os.IBinder unparcelHostInputToken(android.os.Parcel)\npublic void setHostDisplayId(int)\nprivate void onConstructed()\npublic void filterContentTypes()\nprivate static int defaultMaxSuggestionCount()\nprivate static java.lang.String defaultHostPackageName()\nprivate static android.os.LocaleList defaultSupportedLocales()\nprivate static @android.annotation.Nullable android.os.IBinder defaultHostInputToken()\nprivate static @android.annotation.Nullable int defaultHostDisplayId()\nprivate static @android.annotation.NonNull android.os.Bundle defaultExtras()\nclass InlineSuggestionsRequest extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genToString=true, genBuilder=true)\nabstract android.view.inputmethod.InlineSuggestionsRequest.Builder setInlinePresentationSpecs(java.util.List<android.widget.inline.InlinePresentationSpec>)\nabstract android.view.inputmethod.InlineSuggestionsRequest.Builder setHostPackageName(java.lang.String)\nabstract android.view.inputmethod.InlineSuggestionsRequest.Builder setHostInputToken(android.os.IBinder)\nabstract android.view.inputmethod.InlineSuggestionsRequest.Builder setHostDisplayId(int)\nclass BaseBuilder extends java.lang.Object implements []")
diff --git a/core/java/android/view/inputmethod/InlineSuggestionsResponse.java b/core/java/android/view/inputmethod/InlineSuggestionsResponse.java
index be833df61ec4..b393c67d7876 100644
--- a/core/java/android/view/inputmethod/InlineSuggestionsResponse.java
+++ b/core/java/android/view/inputmethod/InlineSuggestionsResponse.java
@@ -32,7 +32,18 @@ import java.util.List;
*/
@DataClass(genEqualsHashCode = true, genToString = true, genHiddenConstructor = true)
public final class InlineSuggestionsResponse implements Parcelable {
- private final @NonNull List<InlineSuggestion> mInlineSuggestions;
+ /**
+ * List of {@link InlineSuggestion}s returned as a part of this response.
+ *
+ * <p>When the host app requests to inflate this <b>ordered</b> list of inline suggestions by
+ * calling {@link InlineSuggestion#inflate}, it is the host's responsibility to track the
+ * order of the inflated {@link android.view.View}s. These views are to be added in
+ * order to the view hierarchy, because the inflation calls will return asynchronously.</p>
+ *
+ * <p>The inflation ordering does not apply to the pinned icon.</p>
+ */
+ @NonNull
+ private final List<InlineSuggestion> mInlineSuggestions;
/**
* Creates a new {@link InlineSuggestionsResponse}, for testing purpose.
@@ -48,7 +59,7 @@ public final class InlineSuggestionsResponse implements Parcelable {
- // Code below generated by codegen v1.0.14.
+ // Code below generated by codegen v1.0.15.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
@@ -64,6 +75,15 @@ public final class InlineSuggestionsResponse implements Parcelable {
/**
* Creates a new InlineSuggestionsResponse.
*
+ * @param inlineSuggestions
+ * List of {@link InlineSuggestion}s returned as a part of this response.
+ *
+ * <p>When the host app requests to inflate this <b>ordered</b> list of inline suggestions by
+ * calling {@link InlineSuggestion#inflate}, it is the host's responsibility to track the
+ * order of the inflated {@link android.view.View}s. These views are to be added in
+ * order to the view hierarchy, because the inflation calls will return asynchronously.</p>
+ *
+ * <p>The inflation ordering does not apply to the pinned icon.</p>
* @hide
*/
@DataClass.Generated.Member
@@ -76,6 +96,16 @@ public final class InlineSuggestionsResponse implements Parcelable {
// onConstructed(); // You can define this method to get a callback
}
+ /**
+ * List of {@link InlineSuggestion}s returned as a part of this response.
+ *
+ * <p>When the host app requests to inflate this <b>ordered</b> list of inline suggestions by
+ * calling {@link InlineSuggestion#inflate}, it is the host's responsibility to track the
+ * order of the inflated {@link android.view.View}s. These views are to be added in
+ * order to the view hierarchy, because the inflation calls will return asynchronously.</p>
+ *
+ * <p>The inflation ordering does not apply to the pinned icon.</p>
+ */
@DataClass.Generated.Member
public @NonNull List<InlineSuggestion> getInlineSuggestions() {
return mInlineSuggestions;
@@ -164,8 +194,8 @@ public final class InlineSuggestionsResponse implements Parcelable {
};
@DataClass.Generated(
- time = 1578972149519L,
- codegenVersion = "1.0.14",
+ time = 1595891876037L,
+ codegenVersion = "1.0.15",
sourceFile = "frameworks/base/core/java/android/view/inputmethod/InlineSuggestionsResponse.java",
inputSignatures = "private final @android.annotation.NonNull java.util.List<android.view.inputmethod.InlineSuggestion> mInlineSuggestions\npublic static @android.annotation.TestApi @android.annotation.NonNull android.view.inputmethod.InlineSuggestionsResponse newInlineSuggestionsResponse(java.util.List<android.view.inputmethod.InlineSuggestion>)\nclass InlineSuggestionsResponse extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genToString=true, genHiddenConstructor=true)")
@Deprecated
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 16e87f8bca9a..97e0689ce64f 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -1514,7 +1514,8 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
if (mOnScrollListener != null) {
mOnScrollListener.onScroll(this, mFirstPosition, getChildCount(), mItemCount);
}
- onScrollChanged(0, 0, 0, 0); // dummy values, View's implementation does not use these.
+ // placeholder values, View's implementation does not use these.
+ onScrollChanged(0, 0, 0, 0);
}
/**
diff --git a/core/java/android/widget/Gallery.java b/core/java/android/widget/Gallery.java
index 8c0061d6e750..d969a8894181 100644
--- a/core/java/android/widget/Gallery.java
+++ b/core/java/android/widget/Gallery.java
@@ -431,7 +431,8 @@ public class Gallery extends AbsSpinner implements GestureDetector.OnGestureList
mSelectedCenterOffset = childLeft + childCenter - galleryCenter;
}
- onScrollChanged(0, 0, 0, 0); // dummy values, View's implementation does not use these.
+ // placeholder values, View's implementation does not use these.
+ onScrollChanged(0, 0, 0, 0);
invalidate();
}
diff --git a/core/java/android/widget/RemoteViewsAdapter.java b/core/java/android/widget/RemoteViewsAdapter.java
index e58f08a79965..b4379ec75205 100644
--- a/core/java/android/widget/RemoteViewsAdapter.java
+++ b/core/java/android/widget/RemoteViewsAdapter.java
@@ -505,7 +505,7 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback
public void reset() {
count = 0;
- // by default there is at least one dummy view type
+ // by default there is at least one placeholder view type
viewTypeCount = 1;
hasStableIds = true;
loadingTemplate = null;
@@ -948,7 +948,7 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback
private void updateTemporaryMetaData(IRemoteViewsFactory factory) {
try {
// get the properties/first view (so that we can use it to
- // measure our dummy views)
+ // measure our placeholder views)
boolean hasStableIds = factory.hasStableIds();
int viewTypeCount = factory.getViewTypeCount();
int count = factory.getCount();
diff --git a/core/java/android/widget/SearchView.java b/core/java/android/widget/SearchView.java
index 6ef570cdc784..2eadb56c0f36 100755
--- a/core/java/android/widget/SearchView.java
+++ b/core/java/android/widget/SearchView.java
@@ -1789,7 +1789,7 @@ public class SearchView extends LinearLayout implements CollapsibleActionView {
return createIntent(action, dataUri, extraData, query, actionKey, actionMsg);
} catch (RuntimeException e ) {
int rowNum;
- try { // be really paranoid now
+ try { // be really defensive now
rowNum = c.getPosition();
} catch (RuntimeException e2 ) {
rowNum = -1;
diff --git a/core/java/android/widget/TEST_MAPPING b/core/java/android/widget/TEST_MAPPING
index f089f48368a0..df3024eda4b6 100644
--- a/core/java/android/widget/TEST_MAPPING
+++ b/core/java/android/widget/TEST_MAPPING
@@ -17,6 +17,45 @@
}
],
"file_patterns": ["Toast\\.java"]
+ },
+ {
+ "name": "CtsAutoFillServiceTestCases",
+ "options": [
+ {
+ "include-filter": "android.autofillservice.cts.LoginActivityTest"
+ },
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ },
+ {
+ "exclude-annotation": "android.platform.test.annotations.AppModeFull"
+ }
+ ]
+ },
+ {
+ "name": "CtsAutoFillServiceTestCases",
+ "options": [
+ {
+ "include-filter": "android.autofillservice.cts.AutofillValueTest"
+ },
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ }
+ ]
+ },
+ {
+ "name": "CtsAutoFillServiceTestCases",
+ "options": [
+ {
+ "include-filter": "android.autofillservice.cts.CheckoutActivityTest"
+ },
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ },
+ {
+ "exclude-annotation": "android.platform.test.annotations.AppModeFull"
+ }
+ ]
}
]
}
diff --git a/core/java/android/widget/inline/InlineContentView.java b/core/java/android/widget/inline/InlineContentView.java
index 9712311aab7c..699a7735bbee 100644
--- a/core/java/android/widget/inline/InlineContentView.java
+++ b/core/java/android/widget/inline/InlineContentView.java
@@ -59,7 +59,7 @@ import java.util.function.Consumer;
*/
public class InlineContentView extends ViewGroup {
- private static final String TAG = "InlineContentView";
+ private static final String TAG = "InlineContentView_test2";
private static final boolean DEBUG = false;
diff --git a/core/java/android/widget/inline/TEST_MAPPING b/core/java/android/widget/inline/TEST_MAPPING
new file mode 100644
index 000000000000..0baad5c31af9
--- /dev/null
+++ b/core/java/android/widget/inline/TEST_MAPPING
@@ -0,0 +1,15 @@
+{
+ "presubmit": [
+ {
+ "name": "CtsAutoFillServiceTestCases",
+ "options": [
+ {
+ "include-filter": "android.autofillservice.cts.inline"
+ },
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ }
+ ]
+ }
+ ]
+}
diff --git a/core/java/com/android/internal/app/LocalePicker.java b/core/java/com/android/internal/app/LocalePicker.java
index 6fdb182e5a62..105e05a4a6c3 100644
--- a/core/java/com/android/internal/app/LocalePicker.java
+++ b/core/java/com/android/internal/app/LocalePicker.java
@@ -16,6 +16,8 @@
package com.android.internal.app;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ActivityThread;
import android.app.IActivityManager;
@@ -29,6 +31,7 @@ import android.os.Bundle;
import android.os.LocaleList;
import android.os.RemoteException;
import android.provider.Settings;
+import android.sysprop.LocalizationProperties;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
@@ -44,6 +47,9 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
+import java.util.function.Predicate;
+import java.util.regex.Pattern;
+import java.util.regex.PatternSyntaxException;
public class LocalePicker extends ListFragment {
private static final String TAG = "LocalePicker";
@@ -93,7 +99,38 @@ public class LocalePicker extends ListFragment {
}
public static String[] getSupportedLocales(Context context) {
- return context.getResources().getStringArray(R.array.supported_locales);
+ String[] allLocales = context.getResources().getStringArray(R.array.supported_locales);
+
+ Predicate<String> localeFilter = getLocaleFilter();
+ if (localeFilter == null) {
+ return allLocales;
+ }
+
+ List<String> result = new ArrayList<>(allLocales.length);
+ for (String locale : allLocales) {
+ if (localeFilter.test(locale)) {
+ result.add(locale);
+ }
+ }
+
+ int localeCount = result.size();
+ return (localeCount == allLocales.length) ? allLocales
+ : result.toArray(new String[localeCount]);
+ }
+
+ @Nullable
+ private static Predicate<String> getLocaleFilter() {
+ try {
+ return LocalizationProperties.locale_filter()
+ .map(filter -> Pattern.compile(filter).asPredicate())
+ .orElse(null);
+ } catch (SecurityException e) {
+ Log.e(TAG, "Failed to read locale filter.", e);
+ } catch (PatternSyntaxException e) {
+ Log.e(TAG, "Bad locale filter format (\"" + e.getPattern() + "\"), skipping.");
+ }
+
+ return null;
}
public static List<LocaleInfo> getAllAssetLocales(Context context, boolean isInDeveloperMode) {
@@ -266,6 +303,11 @@ public class LocalePicker extends ListFragment {
*/
@UnsupportedAppUsage
public static void updateLocales(LocaleList locales) {
+ if (locales != null) {
+ locales = removeExcludedLocales(locales);
+ }
+ // Note: the empty list case is covered by Configuration.setLocales().
+
try {
final IActivityManager am = ActivityManager.getService();
final Configuration config = am.getConfiguration();
@@ -282,6 +324,26 @@ public class LocalePicker extends ListFragment {
}
}
+ @NonNull
+ private static LocaleList removeExcludedLocales(@NonNull LocaleList locales) {
+ Predicate<String> localeFilter = getLocaleFilter();
+ if (localeFilter == null) {
+ return locales;
+ }
+
+ int localeCount = locales.size();
+ ArrayList<Locale> filteredLocales = new ArrayList<>(localeCount);
+ for (int i = 0; i < localeCount; ++i) {
+ Locale locale = locales.get(i);
+ if (localeFilter.test(locale.toString())) {
+ filteredLocales.add(locale);
+ }
+ }
+
+ return (localeCount == filteredLocales.size()) ? locales
+ : new LocaleList(filteredLocales.toArray(new Locale[0]));
+ }
+
/**
* Get the locale list.
*
diff --git a/core/java/com/android/internal/infra/AbstractRemoteService.java b/core/java/com/android/internal/infra/AbstractRemoteService.java
index 7195b45a4055..b2852eaeef2a 100644
--- a/core/java/com/android/internal/infra/AbstractRemoteService.java
+++ b/core/java/com/android/internal/infra/AbstractRemoteService.java
@@ -437,7 +437,7 @@ public abstract class AbstractRemoteService<S extends AbstractRemoteService<S, I
mBinding = true;
final int flags = Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE
- | mBindingFlags;
+ | Context.BIND_INCLUDE_CAPABILITIES | mBindingFlags;
final boolean willBind = mContext.bindServiceAsUser(mIntent, mServiceConnection, flags,
mHandler, new UserHandle(mUserId));
diff --git a/core/java/com/android/internal/policy/GestureNavigationSettingsObserver.java b/core/java/com/android/internal/policy/GestureNavigationSettingsObserver.java
index 0e703fa686e0..205c5fd735ea 100644
--- a/core/java/com/android/internal/policy/GestureNavigationSettingsObserver.java
+++ b/core/java/com/android/internal/policy/GestureNavigationSettingsObserver.java
@@ -103,8 +103,11 @@ public class GestureNavigationSettingsObserver extends ContentObserver {
final DisplayMetrics dm = userRes.getDisplayMetrics();
final float defaultInset = userRes.getDimension(
com.android.internal.R.dimen.config_backGestureInset) / dm.density;
- final float backGestureInset = DeviceConfig.getFloat(DeviceConfig.NAMESPACE_SYSTEMUI,
- BACK_GESTURE_EDGE_WIDTH, defaultInset);
+ // Only apply the back gesture config if there is an existing inset
+ final float backGestureInset = defaultInset > 0
+ ? DeviceConfig.getFloat(DeviceConfig.NAMESPACE_SYSTEMUI,
+ BACK_GESTURE_EDGE_WIDTH, defaultInset)
+ : defaultInset;
final float inset = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, backGestureInset,
dm);
final float scale = Settings.Secure.getFloatForUser(
diff --git a/core/jni/android_hardware_input_InputApplicationHandle.cpp b/core/jni/android_hardware_input_InputApplicationHandle.cpp
index 350f35828418..ff73c74e125e 100644
--- a/core/jni/android_hardware_input_InputApplicationHandle.cpp
+++ b/core/jni/android_hardware_input_InputApplicationHandle.cpp
@@ -61,8 +61,8 @@ bool NativeInputApplicationHandle::updateInfo() {
mInfo.name = getStringField(env, obj, gInputApplicationHandleClassInfo.name, "<null>");
- mInfo.dispatchingTimeout = decltype(mInfo.dispatchingTimeout)(
- env->GetLongField(obj, gInputApplicationHandleClassInfo.dispatchingTimeoutNanos));
+ mInfo.dispatchingTimeoutNanos =
+ env->GetLongField(obj, gInputApplicationHandleClassInfo.dispatchingTimeoutNanos);
jobject tokenObj = env->GetObjectField(obj,
gInputApplicationHandleClassInfo.token);
@@ -77,32 +77,28 @@ bool NativeInputApplicationHandle::updateInfo() {
return mInfo.token.get() != nullptr;
}
-
// --- Global functions ---
-sp<InputApplicationHandle> android_view_InputApplicationHandle_getHandle(
+std::shared_ptr<InputApplicationHandle> android_view_InputApplicationHandle_getHandle(
JNIEnv* env, jobject inputApplicationHandleObj) {
if (!inputApplicationHandleObj) {
return NULL;
}
AutoMutex _l(gHandleMutex);
-
jlong ptr = env->GetLongField(inputApplicationHandleObj, gInputApplicationHandleClassInfo.ptr);
- NativeInputApplicationHandle* handle;
+ std::shared_ptr<NativeInputApplicationHandle>* handle;
if (ptr) {
- handle = reinterpret_cast<NativeInputApplicationHandle*>(ptr);
+ handle = reinterpret_cast<std::shared_ptr<NativeInputApplicationHandle>*>(ptr);
} else {
jweak objWeak = env->NewWeakGlobalRef(inputApplicationHandleObj);
- handle = new NativeInputApplicationHandle(objWeak);
- handle->incStrong((void*)android_view_InputApplicationHandle_getHandle);
+ handle = new std::shared_ptr(std::make_shared<NativeInputApplicationHandle>(objWeak));
env->SetLongField(inputApplicationHandleObj, gInputApplicationHandleClassInfo.ptr,
reinterpret_cast<jlong>(handle));
}
- return handle;
+ return *handle;
}
-
// --- JNI ---
static void android_view_InputApplicationHandle_nativeDispose(JNIEnv* env, jobject obj) {
@@ -112,8 +108,9 @@ static void android_view_InputApplicationHandle_nativeDispose(JNIEnv* env, jobje
if (ptr) {
env->SetLongField(obj, gInputApplicationHandleClassInfo.ptr, 0);
- NativeInputApplicationHandle* handle = reinterpret_cast<NativeInputApplicationHandle*>(ptr);
- handle->decStrong((void*)android_view_InputApplicationHandle_getHandle);
+ std::shared_ptr<NativeInputApplicationHandle>* handle =
+ reinterpret_cast<std::shared_ptr<NativeInputApplicationHandle>*>(ptr);
+ delete handle;
}
}
diff --git a/core/jni/android_hardware_input_InputApplicationHandle.h b/core/jni/android_hardware_input_InputApplicationHandle.h
index 52ab3e614ba1..ec99d6da5b8e 100644
--- a/core/jni/android_hardware_input_InputApplicationHandle.h
+++ b/core/jni/android_hardware_input_InputApplicationHandle.h
@@ -39,8 +39,7 @@ private:
jweak mObjWeak;
};
-
-extern sp<InputApplicationHandle> android_view_InputApplicationHandle_getHandle(
+extern std::shared_ptr<InputApplicationHandle> android_view_InputApplicationHandle_getHandle(
JNIEnv* env, jobject inputApplicationHandleObj);
} // namespace android
diff --git a/core/jni/android_hardware_input_InputWindowHandle.cpp b/core/jni/android_hardware_input_InputWindowHandle.cpp
index bdb4544f4aae..796c5c4cc521 100644
--- a/core/jni/android_hardware_input_InputWindowHandle.cpp
+++ b/core/jni/android_hardware_input_InputWindowHandle.cpp
@@ -168,8 +168,8 @@ bool NativeInputWindowHandle::updateInfo() {
jobject inputApplicationHandleObj = env->GetObjectField(obj,
gInputWindowHandleClassInfo.inputApplicationHandle);
if (inputApplicationHandleObj) {
- sp<InputApplicationHandle> inputApplicationHandle =
- android_view_InputApplicationHandle_getHandle(env, inputApplicationHandleObj);
+ std::shared_ptr<InputApplicationHandle> inputApplicationHandle =
+ android_view_InputApplicationHandle_getHandle(env, inputApplicationHandleObj);
if (inputApplicationHandle != nullptr) {
inputApplicationHandle->updateInfo();
mInfo.applicationInfo = *(inputApplicationHandle->getInfo());
diff --git a/core/jni/android_view_InputEventSender.cpp b/core/jni/android_view_InputEventSender.cpp
index 3ca43ce915cf..ac680f6e2611 100644
--- a/core/jni/android_view_InputEventSender.cpp
+++ b/core/jni/android_view_InputEventSender.cpp
@@ -144,9 +144,8 @@ status_t NativeInputEventSender::sendMotionEvent(uint32_t seq, const MotionEvent
event->getAction(), event->getActionButton(),
event->getFlags(), event->getEdgeFlags(),
event->getMetaState(), event->getButtonState(),
- event->getClassification(), event->getXScale(),
- event->getYScale(), event->getXOffset(),
- event->getYOffset(), event->getXPrecision(),
+ event->getClassification(),
+ event->getTransform(), event->getXPrecision(),
event->getYPrecision(),
event->getRawXCursorPosition(),
event->getRawYCursorPosition(),
diff --git a/core/jni/android_view_MotionEvent.cpp b/core/jni/android_view_MotionEvent.cpp
index 15a91107cbb1..2e396f247979 100644
--- a/core/jni/android_view_MotionEvent.cpp
+++ b/core/jni/android_view_MotionEvent.cpp
@@ -369,13 +369,14 @@ static jlong android_view_MotionEvent_nativeInitialize(
env->DeleteLocalRef(pointerCoordsObj);
}
+ ui::Transform transform;
+ transform.set(xOffset, yOffset);
event->initialize(InputEvent::nextId(), deviceId, source, displayId, INVALID_HMAC, action, 0,
flags, edgeFlags, metaState, buttonState,
- static_cast<MotionClassification>(classification), 1 /*xScale*/, 1 /*yScale*/,
- xOffset, yOffset, xPrecision, yPrecision,
- AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION,
- downTimeNanos, eventTimeNanos, pointerCount, pointerProperties,
- rawPointerCoords);
+ static_cast<MotionClassification>(classification), transform, xPrecision,
+ yPrecision, AMOTION_EVENT_INVALID_CURSOR_POSITION,
+ AMOTION_EVENT_INVALID_CURSOR_POSITION, downTimeNanos, eventTimeNanos,
+ pointerCount, pointerProperties, rawPointerCoords);
return reinterpret_cast<jlong>(event.release());
}
@@ -569,9 +570,9 @@ static void android_view_MotionEvent_nativeTransform(JNIEnv* env, jclass clazz,
jlong nativePtr, jobject matrixObj) {
MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
- float m[9];
- AMatrix_getContents(env, matrixObj, m);
- event->transform(m);
+ std::array<float, 9> matrix;
+ AMatrix_getContents(env, matrixObj, matrix.data());
+ event->transform(matrix);
}
// ----------------- @CriticalNative ------------------------------
diff --git a/core/proto/android/app/settings_enums.proto b/core/proto/android/app/settings_enums.proto
index 097af763038c..5b22e3126eaf 100644
--- a/core/proto/android/app/settings_enums.proto
+++ b/core/proto/android/app/settings_enums.proto
@@ -2693,4 +2693,9 @@ enum PageId {
// CATEGORY: SETTINGS
// OS: R QPR
SETTINGS_SWIPE_BOTTOM_TO_NOTIFICATION = 1846;
+
+ // OPEN: Settings > System > Gestures > Emergency SOS Gesture
+ // CATEGORY: SETTINGS
+ // OS: S
+ EMERGENCY_SOS_GESTURE_SETTINGS = 1847;
}
diff --git a/core/proto/android/providers/settings/global.proto b/core/proto/android/providers/settings/global.proto
index ac143ac1a147..fe540bb18f42 100644
--- a/core/proto/android/providers/settings/global.proto
+++ b/core/proto/android/providers/settings/global.proto
@@ -445,14 +445,14 @@ message GlobalSettingsProto {
// i.e. <pkg1>,<pkg2>,...,<pkgN>
optional SettingProto game_driver_opt_out_apps = 10;
// Game Driver - List of Apps that are forbidden to use Game Driver
- optional SettingProto game_driver_blacklist = 11;
+ optional SettingProto game_driver_denylist = 11;
// Game Driver - List of Apps that are allowed to use Game Driver
- optional SettingProto game_driver_whitelist = 12;
+ optional SettingProto game_driver_allowlist = 12;
// ANGLE - List of Apps that can check ANGLE rules
optional SettingProto angle_whitelist = 13;
- // Game Driver - List of blacklists, each blacklist is a blacklist for
+ // Game Driver - List of denylists, each denylist is a denylist for
// a specific Game Driver version
- optional SettingProto game_driver_blacklists = 14;
+ optional SettingProto game_driver_denylists = 14;
// ANGLE - Show a dialog box when ANGLE is selected for the currently running PKG
optional SettingProto show_angle_in_use_dialog = 15;
// Game Driver - List of libraries in sphal accessible by Game Driver
diff --git a/core/proto/android/server/windowmanagerservice.proto b/core/proto/android/server/windowmanagerservice.proto
index c21663811756..ff0ba8dd5ad4 100644
--- a/core/proto/android/server/windowmanagerservice.proto
+++ b/core/proto/android/server/windowmanagerservice.proto
@@ -204,6 +204,7 @@ message DisplayAreaProto {
optional WindowContainerProto window_container = 1;
optional string name = 2 [ (.android.privacy).dest = DEST_EXPLICIT ];
repeated DisplayAreaChildProto children = 3 [deprecated=true];
+ optional bool is_task_display_area = 4;
}
/* represents a generic child of a DisplayArea */
@@ -275,7 +276,7 @@ message TaskProto {
optional bool adjusted_for_ime = 23;
optional float adjust_ime_amount = 24;
optional float adjust_divider_amount = 25;
- optional bool animating_bounds = 26;
+ optional bool animating_bounds = 26 [deprecated = true];
optional float minimize_amount = 27;
optional bool created_by_organizer = 28;
}
diff --git a/core/res/res/drawable-car/car_dialog_button_background.xml b/core/res/res/drawable-car/car_dialog_button_background.xml
index a7d40bcd759a..72e5af308c01 100644
--- a/core/res/res/drawable-car/car_dialog_button_background.xml
+++ b/core/res/res/drawable-car/car_dialog_button_background.xml
@@ -16,11 +16,18 @@
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_focused="true">
- <ripple android:color="#4b9eff">
- <item android:id="@android:id/mask">
- <color android:color="@*android:color/car_white_1000"/>
+ <layer-list>
+ <item>
+ <shape android:shape="rectangle">
+ <solid android:color="#3D94CBFF"/>
+ </shape>
</item>
- </ripple>
+ <item>
+ <shape android:shape="rectangle">
+ <stroke android:width="8dp" android:color="#94CBFF"/>
+ </shape>
+ </item>
+ </layer-list>
</item>
<item>
<ripple android:color="?android:attr/colorControlHighlight">
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 03c682fd74af..f5facea7fc26 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Druk kieslys om oop te sluit of maak noodoproep."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Druk kieslys om oop te maak."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Teken patroon om te ontsluit"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Noodoproep"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"Keer terug na oproep"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Reg!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Probeer weer"</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index f80da896d8fa..b1183689c5ee 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"ለመክፈት ምናሌ ተጫንወይም የአደጋ ጊዜ ጥሪ አድርግ።"</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"ለመክፈት ምናሌ ተጫን"</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"ለመክፈት ስርዓተ ጥለት ሳል"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"የአደጋ ጊዜ ጥሪ"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"ወደ ጥሪ ተመለስ"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"ትክክል!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"እንደገና ሞክር"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 41e3e26afc2c..26dac618ee7e 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -844,8 +844,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"اضغط على \"القائمة\" لإلغاء التأمين أو إجراء اتصال بالطوارئ."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"اضغط على \"القائمة\" لإلغاء التأمين."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"رسم نقش لإلغاء التأمين"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"مكالمة طوارئ"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"العودة إلى الاتصال"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"صحيح!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"أعد المحاولة"</string>
diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml
index c6c8bb502ba8..d0ed635e69a8 100644
--- a/core/res/res/values-as/strings.xml
+++ b/core/res/res/values-as/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"আনলক কৰিবলৈ বা জৰুৰীকালীন কল কৰিবলৈ মেনু টিপক।"</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"আনলক কৰিবলৈ মেনু টিপক।"</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"আনলক কৰিবলৈ আর্হি আঁকক"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"জৰুৰীকালীন কল"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"কললৈ উভতি যাওক"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"শুদ্ধ!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"আকৌ চেষ্টা কৰক"</string>
diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml
index f0ff88365173..c721bbf8c829 100644
--- a/core/res/res/values-az/strings.xml
+++ b/core/res/res/values-az/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Təcili zəng kilidini açmaq və ya yerləşdirmək üçün Menyu düyməsinə basın."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Kilidi açmaq üçün Menyu düyməsinə basın."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Kilidi açmaq üçün model çəkin"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Təcili zəng"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"Zəngə qayıt"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Düzdür!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Bir də cəhd edin"</string>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index 8319da7ca7ee..93ddbe521ac5 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -835,8 +835,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Pritisnite „Meni“ da biste otključali telefon ili uputite hitan poziv."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Pritisnite „Meni“ za otključavanje."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Unesite šablon za otključavanje"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Hitni poziv"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"Nazad na poziv"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Tačno!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Probajte ponovo"</string>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index 3540516fd9f3..cff1218bd81b 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -568,7 +568,7 @@
<string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"Аўтэнтыфікацыя па адбітках пальцаў скасавана карыстальнікам."</string>
<string name="fingerprint_error_lockout" msgid="7853461265604738671">"Занадта шмат спроб. Паспрабуйце яшчэ раз пазней."</string>
<string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Занадта шмат спроб. Сканер адбіткаў пальцаў выключаны."</string>
- <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Паспрабуйце яшчэ раз."</string>
+ <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Паўтарыце спробу."</string>
<string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Адбіткі пальцаў не зарэгістраваны."</string>
<string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"На гэтай прыладзе няма сканера адбіткаў пальцаў."</string>
<string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Датчык часова выключаны."</string>
@@ -838,11 +838,10 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Націсніце \"Меню\", каб разблакаваць, або зрабіце экстраны выклік."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Націсніце \"Меню\", каб разблакаваць."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Намалюйце камбінацыю разблакоўкі, каб разблакаваць"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Экстранны выклік"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"Вярнуцца да выкліку"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Правільна!"</string>
- <string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Паспрабуйце яшчэ раз"</string>
+ <string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Паўтарыце спробу"</string>
<string name="lockscreen_password_wrong" msgid="8605355913868947490">"Паўтарыце спробу"</string>
<string name="lockscreen_storage_locked" msgid="634993789186443380">"Разблакіраваць для ўсіх функцый і даных"</string>
<string name="faceunlock_multiple_failures" msgid="681991538434031708">"Перавышана максімальная колькасць спроб разблакоўкі праз Фэйскантроль"</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 6643bcfa822c..e49ae26a93ac 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Натиснете „Меню“, за да отключите или да извършите спешно обаждане."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Натиснете „Меню“, за да отключите."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Нарисувайте фигура, за да отключите"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Спешно обаждане"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"Назад към обаждането"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Правилно!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Опитайте отново"</string>
diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml
index cbec4ac51d09..ffc9ecf02b18 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"আনলক করতে বা জরুরি কল করতে মেনু টিপুন৷"</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"আনলক করতে মেনু টিপুন৷"</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"আনলক করতে প্যাটার্ন আঁকুন"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"জরুরি কল"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"কলে ফিরুন"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"সঠিক!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"আবার চেষ্টা করুন"</string>
diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml
index 87b02f553037..0e176b53f236 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -835,8 +835,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Pritisnite dugme Meni kako biste otključali uređaj ili obavili hitni poziv."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Pritisnite dugme Meni za otključavanje uređaja."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Nacrtajte uzorak za otključavanje"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Hitni poziv"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"Povratak na poziv"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Ispravno!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Pokušajte ponovo"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 5fadc92d2970..2e4169e15c3b 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -543,7 +543,7 @@
<string name="biometric_error_user_canceled" msgid="6732303949695293730">"S\'ha cancel·lat l\'autenticació"</string>
<string name="biometric_not_recognized" msgid="5106687642694635888">"No s\'ha reconegut"</string>
<string name="biometric_error_canceled" msgid="8266582404844179778">"S\'ha cancel·lat l\'autenticació"</string>
- <string name="biometric_error_device_not_secured" msgid="3129845065043995924">"No s\'ha establert cap PIN, patró o contrasenya"</string>
+ <string name="biometric_error_device_not_secured" msgid="3129845065043995924">"No s\'ha definit cap PIN, patró o contrasenya"</string>
<string name="biometric_error_generic" msgid="6784371929985434439">"Error en l\'autenticació"</string>
<string name="fingerprint_acquired_partial" msgid="8532380671091299342">"S\'ha detectat una empremta digital parcial. Torna-ho a provar."</string>
<string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"No s\'ha pogut processar l\'empremta digital. Torna-ho a provar."</string>
@@ -832,7 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Premeu Menú per desbloquejar-lo o per fer una trucada d\'emergència."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Premeu Menú per desbloquejar."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Dibuixeu el patró de desbloqueig"</string>
- <string name="lockscreen_emergency_call" msgid="7500692654885445299">"Emergència"</string>
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Trucada d\'emergència"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"Torna a la trucada"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Correcte!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Torna-ho a provar"</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index c69ca37d0f1c..34e6efb2bf78 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -838,8 +838,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Chcete-li odemknout telefon nebo provést tísňové volání, stiskněte Menu."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Telefon odemknete stisknutím tlačítka Menu."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Odblokujte pomocí gesta"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Tísňové volání"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"Zavolat zpět"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Správně!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Zkusit znovu"</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index fb100773dfa6..117fecb0ffd0 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Tryk på Menu for at låse op eller foretage et nødopkald."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Tryk på Menu for at låse op."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Tegn oplåsningsmønster"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Nødopkald"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"Tilbage til opkald"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Rigtigt!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Prøv igen"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 4adcf0ae48ec..faa78df458e0 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Drücke die Menütaste, um das Telefon zu entsperren oder einen Notruf zu tätigen."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Zum Entsperren die Menütaste drücken"</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Muster zum Entsperren zeichnen"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Notruf"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"Zurück zum Anruf"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Korrekt!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Erneut versuchen"</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 23895f4fbf57..2e1b56ad9ff9 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Πατήστε \"Menu\" για ξεκλείδωμα ή για κλήση έκτακτης ανάγκης."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Πατήστε \"Μενού\" για ξεκλείδωμα."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Σχεδιασμός μοτίβου για ξεκλείδωμα"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Κλήση έκτακτης ανάγκης"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"Επιστροφή στην κλήση"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Σωστό!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Προσπαθήστε ξανά"</string>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index 0484ccd8abaa..dcfbf5a49748 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Press Menu to unlock or place emergency call."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Press Menu to unlock."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Draw pattern to unlock"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Emergency call"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"Return to call"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Correct!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Try again"</string>
diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml
index 9981c1212123..65f2426b6e08 100644
--- a/core/res/res/values-en-rCA/strings.xml
+++ b/core/res/res/values-en-rCA/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Press Menu to unlock or place emergency call."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Press Menu to unlock."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Draw pattern to unlock"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Emergency call"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"Return to call"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Correct!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Try again"</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 02cdf69a2cd8..d38e2fe844ad 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Press Menu to unlock or place emergency call."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Press Menu to unlock."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Draw pattern to unlock"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Emergency call"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"Return to call"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Correct!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Try again"</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index 3b18aca951f7..30a9bf88619d 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Press Menu to unlock or place emergency call."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Press Menu to unlock."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Draw pattern to unlock"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Emergency call"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"Return to call"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Correct!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Try again"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 7e8a89aa5a94..27ff3f0d4531 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Presiona el Menú para desbloquear o realizar una llamada de emergencia."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Presionar Menú para desbloquear."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Dibujar el patrón de desbloqueo"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Llamada de emergencia"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"Regresar a llamada"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Correcto"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Vuelve a intentarlo."</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 02aafa75945a..67350cb04fe1 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Pulsa la tecla de menú para desbloquear el teléfono o realizar una llamada de emergencia."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Pulsa la tecla de menú para desbloquear la pantalla."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Dibujar patrón de desbloqueo"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Llamada de emergencia"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"Volver a llamada"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Correcto"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Vuelve a intentarlo"</string>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index 813629417a8e..3929ed4d50da 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Vajutage avamiseks või hädaabikõne tegemiseks menüünuppu"</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Vajutage avamiseks menüüklahvi."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Avamiseks joonistage muster"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Hädaabikõne"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"Kõne juurde tagasi"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Õige."</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Proovige uuesti"</string>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index 1b88f2708782..ecce980c613f 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -350,11 +350,11 @@
<string name="permlab_receiveMms" msgid="4000650116674380275">"jaso testu-mezuak (MMSak)"</string>
<string name="permdesc_receiveMms" msgid="958102423732219710">"MMS mezuak jasotzeko eta prozesatzeko baimena ematen die aplikazioei. Horrela, aplikazioak gailura bidalitako mezuak kontrola eta ezaba ditzake zuri erakutsi gabe."</string>
<string name="permlab_bindCellBroadcastService" msgid="586746677002040651">"desbideratu sare mugikor bidezko igorpen-mezuak"</string>
- <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Sare mugikor bidezko igorpen-modulura lotzeko baimena ematen dio aplikazioari, sare mugikor bidezko igorpen-mezuak jaso ahala desbideratu ahal izateko. Sare mugikor bidezko igorpen-alertak kokapen batzuetan entregatzen dira larrialdi-egoeren berri emateko. Sare mugikor bidezko larrialdi-igorpenak jasotzean, aplikazio maltzurrek gailuaren errendimenduari edota funtzionamenduari eragin diezaiokete."</string>
+ <string name="permdesc_bindCellBroadcastService" msgid="6540910200973641606">"Sare mugikor bidezko igorpen-modulura lotzeko baimena ematen dio aplikazioari, sare mugikor bidezko igorpen-mezuak jaso ahala desbideratu ahal izateko. Sare mugikor bidezko igorpen-alertak kokapen batzuetan entregatzen dira larrialdi-egoeren berri emateko. Sare mugikor bidezko larrialdi-igorpenak jasotzean, aplikazio gaiztoek gailuaren errendimenduari edota funtzionamenduari eragin diezaiokete."</string>
<string name="permlab_readCellBroadcasts" msgid="5869884450872137693">"irakurri sare mugikor bidezko igorpen-mezuak"</string>
<string name="permdesc_readCellBroadcasts" msgid="672513437331980168">"Gailuak jasotako sare mugikor bidezko igorpenen mezuak irakurtzeko baimena ematen die aplikazioei. Sare mugikor bidezko igorpen-alertak kokapen batzuetan ematen dira larrialdi-egoeren berri emateko. Aplikazio gaiztoek gailuaren errendimendua edo funtzionamendua oztopa dezakete larrialdi-igorpen horietako bat jasotzen denean."</string>
<string name="permlab_subscribedFeedsRead" msgid="217624769238425461">"irakurri harpidetutako jarioak"</string>
- <string name="permdesc_subscribedFeedsRead" msgid="6911349196661811865">"Unean sinkronizatutako jarioei buruzko xehetasunak lortzeko baimena ematen die aplikazioei."</string>
+ <string name="permdesc_subscribedFeedsRead" msgid="6911349196661811865">"Une horretan sinkronizatutako jarioei buruzko xehetasunak lortzeko baimena ematen die aplikazioei."</string>
<string name="permlab_sendSms" msgid="7757368721742014252">"bidali eta ikusi SMS mezuak"</string>
<string name="permdesc_sendSms" msgid="6757089798435130769">"SMS mezuak bidaltzeko baimena ematen die aplikazioei. Horrela, ustekabeko gastuak eragin daitezke. Aplikazio gaiztoek erabil dezakete zuk berretsi gabeko mezuak bidalita gastuak eragiteko."</string>
<string name="permlab_readSms" msgid="5164176626258800297">"irakurri testu-mezuak (SMSak edo MMSak)"</string>
@@ -364,7 +364,7 @@
<string name="permlab_receiveWapPush" msgid="4223747702856929056">"jaso testu-mezuak (WAP bidezkoak)"</string>
<string name="permdesc_receiveWapPush" msgid="1638677888301778457">"WAP mezuak jasotzeko eta prozesatzeko baimena ematen die aplikazioei. Horrela, aplikazioak, besteak beste, gailura bidalitako mezuak kontrola eta ezaba ditzake zuri erakutsi gabe."</string>
<string name="permlab_getTasks" msgid="7460048811831750262">"eskuratu abian diren aplikazioak"</string>
- <string name="permdesc_getTasks" msgid="7388138607018233726">"Unean edo duela gutxi exekutatutako zereginei buruzko informazioa lortzeko baimena ematen die aplikazioei. Horrela, aplikazioak gailuan erabiltzen ari diren aplikazioei buruzko informazioa ezagut dezake."</string>
+ <string name="permdesc_getTasks" msgid="7388138607018233726">"Une honetan edo duela gutxi exekutatutako zereginei buruzko informazioa lortzeko baimena ematen die aplikazioei. Horrela, aplikazioak gailuan erabiltzen ari diren aplikazioei buruzko informazioa ezagut dezake."</string>
<string name="permlab_manageProfileAndDeviceOwners" msgid="639849495253987493">"kudeatu profilen eta gailuen jabeak"</string>
<string name="permdesc_manageProfileAndDeviceOwners" msgid="7304240671781989283">"Profilaren eta gailuaren jabeak zehazteko baimena ematen die aplikazioei."</string>
<string name="permlab_reorderTasks" msgid="7598562301992923804">"ordenatu abian diren aplikazioak"</string>
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Desblokeatzeko edo larrialdi-deia egiteko, sakatu Menua."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Desblokeatzeko, sakatu Menua."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Desblokeatzeko, marraztu eredua"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Larrialdi-deia"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"Itzuli deira"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Eredua zuzena da!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Saiatu berriro"</string>
@@ -882,7 +881,7 @@
<string name="lockscreen_glogin_password_hint" msgid="3031027901286812848">"Pasahitza"</string>
<string name="lockscreen_glogin_submit_button" msgid="3590556636347843733">"Hasi saioa"</string>
<string name="lockscreen_glogin_invalid_input" msgid="4369219936865697679">"Erabiltzaile-izen edo pasahitz baliogabea."</string>
- <string name="lockscreen_glogin_account_recovery_hint" msgid="1683405808525090649">"Erabiltzaile-izena edo pasahitza ahaztu zaizu?\nZoaz "<b>"google.com/accounts/recovery"</b>" helbidera."</string>
+ <string name="lockscreen_glogin_account_recovery_hint" msgid="1683405808525090649">"Erabiltzaile-izena edo pasahitza ahaztu zaizu?\nJoan "<b>"google.com/accounts/recovery"</b>" helbidera."</string>
<string name="lockscreen_glogin_checking_password" msgid="2607271802803381645">"Egiaztatzen…"</string>
<string name="lockscreen_unlock_label" msgid="4648257878373307582">"Desblokeatu"</string>
<string name="lockscreen_sound_on_label" msgid="1660281470535492430">"Soinua aktibatuta"</string>
@@ -1604,7 +1603,7 @@
<string name="kg_login_password_hint" msgid="3330530727273164402">"Pasahitza"</string>
<string name="kg_login_submit_button" msgid="893611277617096870">"Hasi saioa"</string>
<string name="kg_login_invalid_input" msgid="8292367491901220210">"Erabiltzaile-izen edo pasahitz baliogabea."</string>
- <string name="kg_login_account_recovery_hint" msgid="4892466171043541248">"Erabiltzaile-izena edo pasahitza ahaztu zaizu?\nZoaz "<b>"google.com/accounts/recovery"</b>" helbidera."</string>
+ <string name="kg_login_account_recovery_hint" msgid="4892466171043541248">"Erabiltzaile-izena edo pasahitza ahaztu zaizu?\nJoan "<b>"google.com/accounts/recovery"</b>" helbidera."</string>
<string name="kg_login_checking_password" msgid="4676010303243317253">"Kontua egiaztatzen…"</string>
<string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="23741434207544038">"PINa oker idatzi duzu <xliff:g id="NUMBER_0">%1$d</xliff:g> aldiz. \n\nSaiatu berriro <xliff:g id="NUMBER_1">%2$d</xliff:g> segundo barru."</string>
<string name="kg_too_many_failed_password_attempts_dialog_message" msgid="3328686432962224215">"Pasahitza oker idatzi duzu <xliff:g id="NUMBER_0">%1$d</xliff:g> aldiz. \n\nSaiatu berriro <xliff:g id="NUMBER_1">%2$d</xliff:g> segundo barru."</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 506a7ee79dcb..1ee4be59733b 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -829,11 +829,10 @@
<string name="emergency_call_dialog_number_for_display" msgid="2978165477085612673">"شماره اضطراری"</string>
<string name="lockscreen_carrier_default" msgid="6192313772955399160">"بدون سرویس"</string>
<string name="lockscreen_screen_locked" msgid="7364905540516041817">"صفحه قفل شد."</string>
- <string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"برای بازگشایی قفل یا انجام تماس اضطراری روی منو فشار دهید."</string>
+ <string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"برای بازکردن قفل یا انجام تماس اضطراری روی «منو» فشار دهید."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"برای بازگشایی قفل روی منو فشار دهید."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"الگو را بکشید تا قفل آن باز شود"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"تماس اضطراری"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"بازگشت به تماس"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"صحیح است!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"دوباره امتحان کنید"</string>
@@ -1927,7 +1926,7 @@
<string name="time_picker_header_text" msgid="9073802285051516688">"تنظیم زمان"</string>
<string name="time_picker_input_error" msgid="8386271930742451034">"زمان معتبری وارد کنید"</string>
<string name="time_picker_prompt_label" msgid="303588544656363889">"زمان را تایپ کنید"</string>
- <string name="time_picker_text_input_mode_description" msgid="4761160667516611576">"برای وارد کردن زمان، به حالت وارد کردن نوشتار تغییر وضعیت دهید."</string>
+ <string name="time_picker_text_input_mode_description" msgid="4761160667516611576">"برای وارد کردن زمان، به حالت ورودی نوشتاری تغییر وضعیت دهید."</string>
<string name="time_picker_radial_mode_description" msgid="1222342577115016953">"برای وارد کردن زمان، به حالت ساعت تغییر وضعیت دهید."</string>
<string name="autofill_picker_accessibility_title" msgid="4425806874792196599">"گزینه‌های تکمیل خودکار"</string>
<string name="autofill_save_accessibility_title" msgid="1523225776218450005">"ذخیره کردن برای تکمیل خودکار"</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 01db781a6ccd..1eff983e803f 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Poista lukitus tai soita hätäpuhelu painamalla Valikko-painiketta."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Poista lukitus painamalla Valikko-painiketta."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Poista lukitus piirtämällä kuvio"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Hätäpuhelu"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"Palaa puheluun"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Oikein!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Yritä uudelleen"</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index f5adc779e082..c6f347b1833b 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Appuyez sur \"Menu\" pour débloquer le téléphone ou appeler un numéro d\'urgence."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Appuyez sur \"Menu\" pour déverrouiller l\'appareil."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Dessinez un schéma pour déverrouiller le téléphone"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Appel d\'urgence"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"Retour à l\'appel"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"C\'est exact!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Réessayer"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 8880dc63428f..6307c354317b 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Appuyez sur \"Menu\" pour déverrouiller le téléphone ou appeler un numéro d\'urgence"</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Appuyez sur \"Menu\" pour déverrouiller le téléphone."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Dessinez un schéma pour déverrouiller le téléphone"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Appel d\'urgence"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"Retour à l\'appel"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Combinaison correcte !"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Veuillez réessayer."</string>
@@ -1938,7 +1937,7 @@
<item quantity="other"><xliff:g id="COUNT">%1$s</xliff:g> suggestions de saisie automatique</item>
</plurals>
<string name="autofill_save_title" msgid="7719802414283739775">"Enregistrer dans "<b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>" ?"</string>
- <string name="autofill_save_title_with_type" msgid="3002460014579799605">"Enregistrer <xliff:g id="TYPE">%1$s</xliff:g> dans "<b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>" ?"</string>
+ <string name="autofill_save_title_with_type" msgid="3002460014579799605">"Enregistrer la <xliff:g id="TYPE">%1$s</xliff:g> dans "<b>"<xliff:g id="LABEL">%2$s</xliff:g>"</b>" ?"</string>
<string name="autofill_save_title_with_2types" msgid="3783270967447869241">"Enregistrer <xliff:g id="TYPE_0">%1$s</xliff:g> et <xliff:g id="TYPE_1">%2$s</xliff:g> dans "<b>"<xliff:g id="LABEL">%3$s</xliff:g>"</b>" ?"</string>
<string name="autofill_save_title_with_3types" msgid="6598228952100102578">"Enregistrer <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> et <xliff:g id="TYPE_2">%3$s</xliff:g> dans "<b>"<xliff:g id="LABEL">%4$s</xliff:g>"</b>" ?"</string>
<string name="autofill_update_title" msgid="3630695947047069136">"Mettre à jour cet élément dans "<b>"<xliff:g id="LABEL">%1$s</xliff:g>"</b>" ?"</string>
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index dffca1c2abcd..b3a4542614ac 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Preme Menú para desbloquear ou realizar unha chamada de emerxencia."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Preme Menú para desbloquear."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Crea o padrón de desbloqueo"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Chamada de emerxencia"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"Volver á chamada"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Correcto!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Téntao de novo"</string>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index 784e85f9a174..ca35a681f636 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"અનલૉક કરવા માટે અથવા કટોકટીનો કૉલ કરવા માટે મેનૂ દબાવો."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"અનલૉક કરવા માટે મેનૂ દબાવો."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"અનલૉક કરવા માટે પૅટર્ન દોરો."</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"ઇમર્જન્સી કૉલ"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"કૉલ પર પાછા ફરો"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"સાચું!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"ફરી પ્રયાસ કરો"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 82a106295acb..7b0bd238d7f7 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"लॉक खोलने के लिए मेन्यू दबाएं या आपातलकालीन कॉल करें."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"लॉक खोलने के लिए मेन्यू दबाएं."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"अनलॉक करने के लिए आकार आरेखित करें"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"आपातकालीन कॉल"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"कॉल पर वापस लौटें"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"सही!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"फिर से कोशिश करें"</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index f1bcd398c65f..eb41c9f8f6f8 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -835,8 +835,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Pritisnite Izbornik za otključavanje ili pozivanje hitnih službi."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Pritisnite Izbornik za otključavanje."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Iscrtajte uzorak za otključavanje"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Hitni poziv"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"Uzvrati poziv"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Ispravno!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Pokušajte ponovo"</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 3106371a2a33..0004ff1a3f13 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"A feloldáshoz vagy segélyhívás kezdeményezéséhez nyomja meg a Menü gombot."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"A feloldáshoz nyomja meg a Menü gombot."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Rajzolja le a mintát a feloldáshoz"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Segélyhívás"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"Hívás folytatása"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Helyes!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Próbálja újra"</string>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index 85afc27bb14c..b115025fd63d 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Ապակողպելու կամ շտապ կանչ անելու համար սեղմեք «Ընտրացանկ»"</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Ապակողպելու համար սեղմեք Ցանկը:"</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Հավաքեք սխեման` ապակողպելու համար"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Շտապ կանչ"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"Վերադառնալ զանգին"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Ճիշտ է:"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Կրկին փորձեք"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 8ec1f50eaceb..688996d87dba 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Tekan Menu untuk membuka atau melakukan panggilan darurat."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Tekan Menu untuk membuka."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Buat pola untuk membuka"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Panggilan darurat"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"Kembali ke panggilan"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Perbaiki!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Coba lagi"</string>
diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml
index 1b0c2fe24521..899fa52fbb9f 100644
--- a/core/res/res/values-is/strings.xml
+++ b/core/res/res/values-is/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Ýttu á valmyndartakkann til að taka úr lás eða hringja neyðarsímtal."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Ýttu á valmyndartakkann til að taka úr lás."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Teiknaðu mynstur til að taka úr lás"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Neyðarsímtal"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"Aftur í símtal"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Rétt!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Reyndu aftur"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index d2bf62d94a40..400c44a4ef9c 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Premi Menu per sbloccare o effettuare chiamate di emergenza."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Premi Menu per sbloccare."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Traccia la sequenza di sblocco"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Chiamata di emergenza"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"Torna a chiamata"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Corretta."</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Riprova"</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 4d6d8155a981..2c4274532a02 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -838,7 +838,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"לחץ על \'תפריט\' כדי לבטל את הנעילה או כדי לבצע שיחת חירום."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"לחץ על \'תפריט\' כדי לבטל את הנעילה."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"שרטט קו לביטול נעילת המסך"</string>
- <string name="lockscreen_emergency_call" msgid="7500692654885445299">"חירום"</string>
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"שיחת חירום"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"חזרה לשיחה"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"נכון!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"כדאי לנסות שוב"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index f9674bd0db11..fdb505b696dc 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"MENUキーでロック解除(または緊急通報)"</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"MENUキーでロック解除"</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"パターンを入力"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"緊急通報"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"通話に戻る"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"一致しました"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"もう一度お試しください"</string>
diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml
index 3d1e9c799a4d..3d0d88b9e823 100644
--- a/core/res/res/values-ka/strings.xml
+++ b/core/res/res/values-ka/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"განბლოკვისთვის ან გადაუდებელი ზარისთვის დააჭირეთ მენიუს."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"განბლოკვისთვის დააჭირეთ მენიუს."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"განსაბლოკად დახატეთ ნიმუში"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"გადაუდებელი ზარი"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"ზარზე დაბრუნება"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"სწორია!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"კიდევ სცადეთ"</string>
diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml
index 38a50abfe6e7..6d063b647c41 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Бекітпесін ашу үшін немесе төтенше қоңырауды табу үшін Мәзір тармағын басыңыз."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Ашу үшін Мәзір пернесін басыңыз."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Бекітпесін ашу үшін кескінді сызыңыз"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Құтқару қызметіне қоңырау шалу"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"Қоңырауға оралу"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Дұрыс!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Қайталап көріңіз"</string>
diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml
index 4e646c5d2a07..b9378def3491 100644
--- a/core/res/res/values-km/strings.xml
+++ b/core/res/res/values-km/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"ចុច​ម៉ឺនុយ ដើម្បី​ដោះ​សោ​ ឬ​ហៅ​ពេល​អាសន្ន។"</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"ចុច​ម៉ឺនុយ ដើម្បី​ដោះ​សោ។"</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"គូរ​លំនាំ ដើម្បី​ដោះ​សោ"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"ហៅទៅលេខសង្គ្រោះបន្ទាន់"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"ត្រឡប់​ទៅ​ការ​ហៅ"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"ត្រឹមត្រូវ!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"ព្យាយាម​ម្ដង​ទៀត"</string>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index 8d742156ca2c..cbb9ca2606f2 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"ಅನ್‌ಲಾಕ್ ಮಾಡಲು ಮೆನು ಒತ್ತಿರಿ ಇಲ್ಲವೇ ತುರ್ತು ಕರೆಯನ್ನು ಮಾಡಿ."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"ಅನ್‌ಲಾಕ್ ಮಾಡಲು ಮೆನು ಒತ್ತಿರಿ."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"ಅನ್‌ಲಾಕ್ ಮಾಡಲು ಪ್ಯಾಟರ್ನ್ ಚಿತ್ರಿಸಿ"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"ತುರ್ತು ಕರೆ"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"ಕರೆಗೆ ಹಿಂತಿರುಗು"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"ಸರಿಯಾಗಿದೆ!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 5d960dcc0aa7..78c3286eecf3 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"비상 전화를 걸거나 잠금해제하려면 메뉴를 누르세요."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"잠금해제하려면 메뉴를 누르세요."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"잠금해제를 위해 패턴 그리기"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"긴급 전화"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"통화로 돌아가기"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"맞습니다."</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"다시 시도"</string>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index c97324f738b3..671863d68035 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -47,7 +47,7 @@
<string name="mismatchPin" msgid="2929611853228707473">"Терилген PIN\'дер дал келбейт."</string>
<string name="invalidPin" msgid="7542498253319440408">"Узундугу 4төн 8ге чейинки сандан турган PIN-кодду териңиз."</string>
<string name="invalidPuk" msgid="8831151490931907083">"Узундугу 8 же көбүрөөк сандан турган PUK-кодду териңиз."</string>
- <string name="needPuk" msgid="7321876090152422918">"SIM картаңыз PUK менен кулпуланган. Кулпусун ачуу үчүн PUK-кодду териңиз."</string>
+ <string name="needPuk" msgid="7321876090152422918">"SIM картаңыз PUK менен кулпуланган. Кулпусун ачуу үчүн, PUK-кодду териңиз."</string>
<string name="needPuk2" msgid="7032612093451537186">"SIM картаны бөгөттөн чыгаруу үчүн PUK2 кодун териңиз."</string>
<string name="enablePin" msgid="2543771964137091212">"Оңунан чыкпады, SIM/RUIM бөгөттөөсүн жандырыңыз."</string>
<plurals name="pinpuk_attempts" formatted="false" msgid="1619867269012213584">
@@ -241,7 +241,7 @@
<string name="global_action_power_off" msgid="4404936470711393203">"Өчүрүү"</string>
<string name="global_action_power_options" msgid="1185286119330160073">"Кубат"</string>
<string name="global_action_restart" msgid="4678451019561687074">"Өчүрүп күйгүзүү"</string>
- <string name="global_action_emergency" msgid="1387617624177105088">"Тез жардам"</string>
+ <string name="global_action_emergency" msgid="1387617624177105088">"Шашылыш чалуу"</string>
<string name="global_action_bug_report" msgid="5127867163044170003">"Ката тууралуу билдирүү"</string>
<string name="global_action_logout" msgid="6093581310002476511">"Сеансты бүтүрүү"</string>
<string name="global_action_screenshot" msgid="2610053466156478564">"Скриншот"</string>
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Кулпусун ачып же Шашылыш чалуу аткаруу үчүн менюну басыңыз."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Бөгөттөн чыгаруу үчүн Менюну басыңыз."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Кулпуну ачуу үчүн, үлгүнү тартыңыз"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Шашылыш чалуу"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"Чалууга кайтуу"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Туура!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Дагы аракет кылыңыз"</string>
@@ -1321,7 +1320,7 @@
<string name="console_running_notification_title" msgid="6087888939261635904">"Сериялык консоль иштетилди"</string>
<string name="console_running_notification_message" msgid="7892751888125174039">"Майнаптуулугуна таасири тиет. Аны өчүрүү үчүн операциялык тутумду жүктөгүчтү текшериңиз."</string>
<string name="usb_contaminant_detected_title" msgid="4359048603069159678">"USB портунда суюктук же урандылар бар"</string>
- <string name="usb_contaminant_detected_message" msgid="7346100585390795743">"USB порт автоматтык түрдө өчүрүлдү. Кененирээк маалымат алуу үчүн таптап коюңуз."</string>
+ <string name="usb_contaminant_detected_message" msgid="7346100585390795743">"USB порт автоматтык түрдө өчүрүлдү. Кененирээк маалымат алуу үчүн, таптап коюңуз."</string>
<string name="usb_contaminant_not_detected_title" msgid="2651167729563264053">"USB портун колдонууга болот"</string>
<string name="usb_contaminant_not_detected_message" msgid="892863190942660462">"Телефон суюктук менен урандыларды аныктаган жок."</string>
<string name="taking_remote_bugreport_notification_title" msgid="1582531382166919850">"Мүчүлүштүк тууралуу кабар алынууда…"</string>
diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml
index c1b3fe473aed..44511398c694 100644
--- a/core/res/res/values-lo/strings.xml
+++ b/core/res/res/values-lo/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"ກົດ ເມນູ ເພື່ອປົດລັອກ ຫຼື ໂທອອກຫາເບີສຸກເສີນ."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"ກົດ \"ເມນູ\" ເພື່ອປົດລັອກ."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"ແຕ້ມຮູບແບບເພື່ອປົດລັອກ"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"ການໂທສຸກເສີນ"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"ກັບໄປຫາການໂທ"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"ຖືກຕ້ອງ!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"ລອງໃໝ່ອີກຄັ້ງ"</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index fc5709c0e089..fa0797846de4 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -838,8 +838,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Paspauskite „Meniu“, kad atrakintumėte ar skambintumėte pagalbos numeriu."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Paspauskite „Meniu“, jei norite atrakinti."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Nustatyti modelį, kad atrakintų"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Skambutis pagalbos numeriu"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"grįžti prie skambučio"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Teisingai!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Bandykite dar kartą"</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index d780b14ae11a..e8107fb0c744 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -835,8 +835,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Nospiediet Izvēlne, lai atbloķētu, vai veiciet ārkārtas zvanu."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Lai atbloķētu, nospiediet vienumu Izvēlne."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Zīmējiet kombināciju, lai atbloķētu."</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Ārkārtas izsaukums"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"Atpakaļ pie zvana"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Pareizi!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Mēģināt vēlreiz"</string>
@@ -1816,8 +1815,8 @@
<string name="package_updated_device_owner" msgid="7560272363805506941">"Atjaunināja administrators"</string>
<string name="package_deleted_device_owner" msgid="2292335928930293023">"Dzēsa administrators"</string>
<string name="confirm_battery_saver" msgid="5247976246208245754">"Labi"</string>
- <string name="battery_saver_description_with_learn_more" msgid="4424488535318105801">"Lai paildzinātu akumulatora darbības laiku, ieslēdzot akumulatora jaudas taupīšanas režīmu, tiek veiktas tālāk norādītās darbības.\n\n• Tiek ieslēgts tumšais motīvs.\n• Tiek izslēgtas vai ierobežotas fonā veiktās darbības, daži vizuālie efekti un citas funkcijas, piemēram, “Ok Google”.\n\n"<annotation id="url">"Uzzināt vairāk"</annotation></string>
- <string name="battery_saver_description" msgid="6794188153647295212">"Lai paildzinātu akumulatora darbības laiku, ieslēdzot akumulatora jaudas taupīšanas režīmu, tiek veiktas tālāk norādītās darbības.\n\n• Tiek ieslēgts tumšais motīvs.\n• Tiek izslēgtas vai ierobežotas fonā veiktās darbības, daži vizuālie efekti un citas funkcijas, piemēram, “Ok Google”."</string>
+ <string name="battery_saver_description_with_learn_more" msgid="4424488535318105801">"Lai paildzinātu akumulatora darbības laiku, ieslēdzot akumulatora enerģijas taupīšanas režīmu, tiek veiktas tālāk norādītās darbības.\n\n• Tiek ieslēgts tumšais motīvs.\n• Tiek izslēgtas vai ierobežotas fonā veiktās darbības, daži vizuālie efekti un citas funkcijas, piemēram, “Ok Google”.\n\n"<annotation id="url">"Uzzināt vairāk"</annotation></string>
+ <string name="battery_saver_description" msgid="6794188153647295212">"Lai paildzinātu akumulatora darbības laiku, ieslēdzot akumulatora enerģijas taupīšanas režīmu, tiek veiktas tālāk norādītās darbības.\n\n• Tiek ieslēgts tumšais motīvs.\n• Tiek izslēgtas vai ierobežotas fonā veiktās darbības, daži vizuālie efekti un citas funkcijas, piemēram, “Ok Google”."</string>
<string name="data_saver_description" msgid="4995164271550590517">"Lai samazinātu datu lietojumu, datu lietojuma samazinātājs neļauj dažām lietotnēm fonā nosūtīt vai saņemt datus. Lietotne, kuru pašlaik izmantojat, var piekļūt datiem, bet, iespējams, piekļūs tiem retāk (piemēram, attēli tiks parādīti tikai tad, kad tiem pieskarsieties)."</string>
<string name="data_saver_enable_title" msgid="7080620065745260137">"Vai ieslēgt datu lietojuma samazinātāju?"</string>
<string name="data_saver_enable_button" msgid="4399405762586419726">"Ieslēgt"</string>
@@ -2034,9 +2033,9 @@
<string name="notification_feedback_indicator" msgid="663476517711323016">"Sniegt atsauksmes"</string>
<string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Informatīvs paziņojums par akumulatoru"</string>
<string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Akumulators var izlādēties pirms parastā uzlādes laika"</string>
- <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Aktivizēts akumulatora jaudas taupīšanas režīms, lai palielinātu akumulatora darbības ilgumu"</string>
- <string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"Akumulatora jaudas taupīšanas režīms"</string>
- <string name="battery_saver_off_notification_title" msgid="7637255960468032515">"Akumulatora jaudas taupīšanas režīms ir izslēgts"</string>
+ <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Aktivizēts akumulatora enerģijas taupīšanas režīms, lai palielinātu akumulatora darbības ilgumu"</string>
+ <string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"Akumulatora enerģijas taupīšanas režīms"</string>
+ <string name="battery_saver_off_notification_title" msgid="7637255960468032515">"Akumulatora enerģijas taupīšanas režīms ir izslēgts"</string>
<string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"Tālruņa uzlādes līmenis ir pietiekams. Funkcijas vairs netiek ierobežotas."</string>
<string name="battery_saver_charged_notification_summary" product="tablet" msgid="4426317048139996888">"Planšetdatora uzlādes līmenis ir pietiekams. Funkcijas vairs netiek ierobežotas."</string>
<string name="battery_saver_charged_notification_summary" product="device" msgid="1031562417867646649">"Ierīces uzlādes līmenis ir pietiekams. Funkcijas vairs netiek ierobežotas."</string>
diff --git a/core/res/res/values-mcc260/config.xml b/core/res/res/values-mcc260/config.xml
new file mode 100644
index 000000000000..79eefb7cecbe
--- /dev/null
+++ b/core/res/res/values-mcc260/config.xml
@@ -0,0 +1,25 @@
+<?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.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+ for different hardware and product builds. -->
+<resources>
+ <!-- Set to false to disable emergency alert. -->
+ <bool name="config_cellBroadcastAppLinks">false</bool>
+</resources> \ No newline at end of file
diff --git a/core/res/res/values-mcc262/config.xml b/core/res/res/values-mcc262/config.xml
new file mode 100644
index 000000000000..79eefb7cecbe
--- /dev/null
+++ b/core/res/res/values-mcc262/config.xml
@@ -0,0 +1,25 @@
+<?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.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+ for different hardware and product builds. -->
+<resources>
+ <!-- Set to false to disable emergency alert. -->
+ <bool name="config_cellBroadcastAppLinks">false</bool>
+</resources> \ No newline at end of file
diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml
index b50c608190e4..8871293c1b2f 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Притисни „Мени“ да се отклучи или да направи итен повик."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Притиснете „Мени“ за да се отклучи."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Употребете ја шемата за да се отклучи"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Итен повик"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"Врати се на повик"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Точно!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Обидете се повторно"</string>
diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml
index b769fd23ab1e..af75969910d2 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"അൺലോക്ക് ചെയ്യുന്നതിനായി മെനു അമർത്തുക അല്ലെങ്കിൽ അടിയന്തര കോൾ വിളിക്കുക."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"അൺലോക്കുചെയ്യാൻ മെനു അമർത്തുക."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"അൺലോക്ക് ചെയ്യാൻ പാറ്റേൺ വരയ്‌ക്കുക"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"എമർജൻസി കോൾ"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"കോളിലേക്ക് മടങ്ങുക"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"ശരി!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"വീണ്ടും ശ്രമിക്കുക"</string>
diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml
index 7b41501e6a0f..a65f80c9332f 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Яаралтай дуудлага хийх буюу эсвэл түгжээг тайлах бол цэсийг дарна уу."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Тайлах бол цэсийг дарна уу."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Тайлах хээгээ зурна уу"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Яаралтай дуудлага"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"Дуудлагаруу буцах"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Зөв!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Дахин оролдох"</string>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index 577803334c33..ec240c1c36fc 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"अनलॉक करण्‍यासाठी मेनू दाबा किंवा आणीबाणीचा कॉल करा."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"अनलॉक करण्यासाठी मेनू दाबा."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"अनलॉक करण्यासाठी पॅटर्न काढा"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"आणीबाणी कॉल"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"कॉलवर परत या"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"अचूक!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"पुन्हा प्रयत्न करा"</string>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index c30bcfc1800f..2e78b45cbb67 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Tekan Menu untuk menyahsekat atau membuat panggilan kecemasan."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Tekan Menu untuk membuka kunci."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Lukiskan corak untuk membuka kunci"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Panggilan kecemasan"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"Kembali ke panggilan"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Betul!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Cuba lagi"</string>
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index 243357eca3c2..1ebafa47f76e 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"ဖွင့်ရန်သို့မဟုတ်အရေးပေါ်ခေါ်ဆိုခြင်းပြုလုပ်ရန် မီနူးကိုနှိပ်ပါ"</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"မီးနူးကို နှိပ်ခြင်းဖြင့် သော့ဖွင့်ပါ"</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"ဖွင့်ရန်ပုံစံဆွဲပါ"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"အရေးပေါ် ခေါ်ဆိုမှု"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"ခေါ်ဆိုမှုထံပြန်သွားရန်"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"မှန်ပါသည်"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"ထပ် စမ်းပါ"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 0a31b49c555c..ac21aec0080e 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Trykk på menyknappen for å låse opp eller ringe et nødnummer."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Trykk på menyknappen for å låse opp."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Tegn mønster for å låse opp"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Nødanrop"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"Tilbake til samtale"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Riktig!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Prøv på nytt"</string>
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index 9712b480b97b..fd7b1b2ab55a 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"अनलक वा आपतकालीन कल गर्न मेनु थिच्नुहोस्।"</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"अनलक गर्न मेनु थिच्नुहोस्।"</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"अनलक गर्नु ढाँचा खिच्नुहोस्"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"आपतकालीन कल"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"कलमा फर्किनुहोस्"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"सही!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"फेरि प्रयास गर्नुहोस्"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index d1a342c99590..f63e64760957 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -326,7 +326,7 @@
<string name="capability_title_canControlMagnification" msgid="7701572187333415795">"Schermvergroting bedienen"</string>
<string name="capability_desc_canControlMagnification" msgid="2206586716709254805">"Het zoomniveau en de positionering van het scherm bedienen."</string>
<string name="capability_title_canPerformGestures" msgid="9106545062106728987">"Gebaren uitvoeren"</string>
- <string name="capability_desc_canPerformGestures" msgid="6619457251067929726">"Kan tikken, vegen, samenknijpen en andere gebaren uitvoeren."</string>
+ <string name="capability_desc_canPerformGestures" msgid="6619457251067929726">"Kan tikken, swipen, knijpen en andere gebaren uitvoeren."</string>
<string name="capability_title_canCaptureFingerprintGestures" msgid="1189053104594608091">"Vingerafdrukgebaren"</string>
<string name="capability_desc_canCaptureFingerprintGestures" msgid="6861869337457461274">"Kan gebaren registreren die op de vingerafdruksensor van het apparaat worden getekend."</string>
<string name="capability_title_canTakeScreenshot" msgid="3895812893130071930">"Screenshot maken"</string>
@@ -451,7 +451,7 @@
<string name="permlab_accessImsCallService" msgid="442192920714863782">"toegang tot IMS-service voor bellen"</string>
<string name="permdesc_accessImsCallService" msgid="6328551241649687162">"Hiermee kan de app de IMS-service gebruiken om te bellen zonder je tussenkomst."</string>
<string name="permlab_readPhoneState" msgid="8138526903259297969">"telefoonstatus en -identiteit lezen"</string>
- <string name="permdesc_readPhoneState" msgid="7229063553502788058">"Hiermee kan de app toegang krijgen tot de telefoonfuncties van het apparaat, Met deze toestemming kan de app het telefoonnummer en de apparaat-ID\'s bepalen, of een gesprek actief is, en het andere telefoonnummer waarmee wordt gebeld."</string>
+ <string name="permdesc_readPhoneState" msgid="7229063553502788058">"Hiermee kan de app toegang krijgen tot de telefoonfuncties van het apparaat, Met deze rechten kan de app het telefoonnummer en de apparaat-ID\'s bepalen, of een gesprek actief is, en het andere telefoonnummer waarmee wordt gebeld."</string>
<string name="permlab_manageOwnCalls" msgid="9033349060307561370">"gesprekken doorschakelen via het systeem"</string>
<string name="permdesc_manageOwnCalls" msgid="4431178362202142574">"Hiermee kan de app de bijbehorende gesprekken doorschakelen via het systeem om de belfunctionaliteit te verbeteren."</string>
<string name="permlab_callCompanionApp" msgid="3654373653014126884">"gesprekken via het systeem bekijken en beheren"</string>
@@ -489,7 +489,7 @@
<string name="permlab_accessNetworkState" msgid="2349126720783633918">"netwerkverbindingen weergeven"</string>
<string name="permdesc_accessNetworkState" msgid="4394564702881662849">"Hiermee kan de app informatie bekijken over netwerkverbindingen, zoals welke netwerken er zijn en welke verbonden zijn."</string>
<string name="permlab_createNetworkSockets" msgid="3224420491603590541">"volledige netwerktoegang"</string>
- <string name="permdesc_createNetworkSockets" msgid="7722020828749535988">"Hiermee kan de app netwerksockets maken en aangepaste netwerkprotocollen gebruiken. De browser en andere apps bieden mogelijkheden om gegevens via internet te verzenden, dus deze toestemming is niet vereist om gegevens via internet te verzenden."</string>
+ <string name="permdesc_createNetworkSockets" msgid="7722020828749535988">"Hiermee kan de app netwerksockets maken en aangepaste netwerkprotocollen gebruiken. De browser en andere apps bieden mogelijkheden om gegevens via internet te verzenden, dus deze rechten zijn niet vereist om gegevens via internet te verzenden."</string>
<string name="permlab_changeNetworkState" msgid="8945711637530425586">"netwerkverbinding wijzigen"</string>
<string name="permdesc_changeNetworkState" msgid="649341947816898736">"Hiermee kan de app de status van de netwerkverbinding wijzigen."</string>
<string name="permlab_changeTetherState" msgid="9079611809931863861">"getetherde verbinding wijzigen"</string>
@@ -569,7 +569,7 @@
<string name="fingerprint_name_template" msgid="8941662088160289778">"Vinger <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
- <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Vingerafdruk-pictogram"</string>
+ <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Vingerafdruk-icoon"</string>
<string name="permlab_manageFace" msgid="4569549381889283282">"hardware voor ontgrendelen via gezichtsherkenning beheren"</string>
<string name="permdesc_manageFace" msgid="6204569688492710471">"Hiermee kan de app methoden aanroepen om gezichtstemplates toe te voegen en te verwijderen voor gebruik."</string>
<string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"hardware voor ontgrendelen via gezichtsherkenning gebruiken"</string>
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Druk op \'Menu\' om te ontgrendelen of noodoproep te plaatsen."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Druk op \'Menu\' om te ontgrendelen."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Patroon tekenen om te ontgrendelen"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Noodoproep"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"Terug naar gesprek"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Juist!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Opnieuw proberen"</string>
@@ -954,12 +953,12 @@
<string name="autofill_parish" msgid="6847960518334530198">"Gemeente"</string>
<string name="autofill_area" msgid="8289022370678448983">"Gebied"</string>
<string name="autofill_emirate" msgid="2544082046790551168">"Emiraat"</string>
- <string name="permlab_readHistoryBookmarks" msgid="9102293913842539697">"je webbladwijzers en -geschiedenis lezen"</string>
- <string name="permdesc_readHistoryBookmarks" msgid="2323799501008967852">"Hiermee kan de app de geschiedenis lezen van alle URL\'s die in de systeemeigen browser zijn bezocht, en alle bookmarks in de systeemeigen browser. Let op: deze toestemming kan niet worden geforceerd door andere browsers of andere apps met internetmogelijkheden."</string>
- <string name="permlab_writeHistoryBookmarks" msgid="6090259925187986937">"webbladwijzers en -geschiedenis schrijven"</string>
- <string name="permdesc_writeHistoryBookmarks" product="tablet" msgid="573341025292489065">"Hiermee kan de app de webgeschiedenis wijzigen in de systeemeigen browser en de bookmarks die zijn opgeslagen op je tablet. Deze toestemming kan niet worden geforceerd door andere browsers of andere apps met internetmogelijkheden.."</string>
+ <string name="permlab_readHistoryBookmarks" msgid="9102293913842539697">"je webbookmarks en -geschiedenis lezen"</string>
+ <string name="permdesc_readHistoryBookmarks" msgid="2323799501008967852">"Hiermee kan de app de geschiedenis lezen van alle URL\'s die in de systeemeigen browser zijn bezocht, en alle bookmarks in de systeemeigen browser. Let op: deze rechten kunnen niet worden geforceerd door andere browsers of andere apps met internetmogelijkheden."</string>
+ <string name="permlab_writeHistoryBookmarks" msgid="6090259925187986937">"webbookmarks en -geschiedenis schrijven"</string>
+ <string name="permdesc_writeHistoryBookmarks" product="tablet" msgid="573341025292489065">"Hiermee kan de app de webgeschiedenis wijzigen in de systeemeigen browser en de bookmarks die zijn opgeslagen op je tablet. Deze rechten kunnen niet worden geforceerd door andere browsers of andere apps met internetmogelijkheden."</string>
<string name="permdesc_writeHistoryBookmarks" product="tv" msgid="88642768580408561">"Hiermee kan de app de browsergeschiedenis of opgeslagen bookmarks bewerken op je Android TV-apparaat. Hierdoor kan de app mogelijk browsergegevens wissen of aanpassen. Opmerking: Dit recht kan niet worden afgedwongen door andere browsers of andere apps met internetmogelijkheden."</string>
- <string name="permdesc_writeHistoryBookmarks" product="default" msgid="2245203087160913652">"Hiermee kan de app de webgeschiedenis wijzigen in de systeemeigen browser en de bookmarks die zijn opgeslagen op je telefoon. Deze toestemming kan niet worden geforceerd door andere browsers of andere apps met internetmogelijkheden."</string>
+ <string name="permdesc_writeHistoryBookmarks" product="default" msgid="2245203087160913652">"Hiermee kan de app de webgeschiedenis wijzigen in de systeemeigen browser en de bookmarks die zijn opgeslagen op je telefoon. Deze rechten kunnen niet worden geforceerd door andere browsers of andere apps met internetmogelijkheden."</string>
<string name="permlab_setAlarm" msgid="1158001610254173567">"een wekker instellen"</string>
<string name="permdesc_setAlarm" msgid="2185033720060109640">"Hiermee kan de app een wekker instellen in een geïnstalleerde wekker-app. Deze functie wordt door sommige wekker-apps niet geïmplementeerd."</string>
<string name="permlab_addVoicemail" msgid="4770245808840814471">"voicemail toevoegen"</string>
@@ -970,7 +969,7 @@
<string name="save_password_notnow" msgid="2878327088951240061">"Niet nu"</string>
<string name="save_password_remember" msgid="6490888932657708341">"Onthouden"</string>
<string name="save_password_never" msgid="6776808375903410659">"Nooit"</string>
- <string name="open_permission_deny" msgid="5136793905306987251">"Je hebt geen toestemming om deze pagina te openen."</string>
+ <string name="open_permission_deny" msgid="5136793905306987251">"Je hebt geen rechten om deze pagina te openen."</string>
<string name="text_copied" msgid="2531420577879738860">"Tekst naar klembord gekopieerd."</string>
<string name="copied" msgid="4675902854553014676">"Gekopieerd"</string>
<string name="more_item_label" msgid="7419249600215749115">"Meer"</string>
@@ -1398,7 +1397,7 @@
<string name="permlab_requestDeletePackages" msgid="2541172829260106795">"verwijdering van pakketten aanvragen"</string>
<string name="permdesc_requestDeletePackages" msgid="6133633516423860381">"Hiermee kan een app verwijdering van pakketten aanvragen."</string>
<string name="permlab_requestIgnoreBatteryOptimizations" msgid="7646611326036631439">"vragen om batterijoptimalisatie te negeren"</string>
- <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="634260656917874356">"Hiermee kan een app toestemming vragen om batterijoptimalisatie voor die app te negeren."</string>
+ <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="634260656917874356">"Hiermee kan een app rechten vragen om batterijoptimalisatie voor die app te negeren."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"Tik twee keer voor zoomregeling"</string>
<string name="gadget_host_error_inflating" msgid="2449961590495198720">"Kan widget niet toevoegen."</string>
<string name="ime_action_go" msgid="5536744546326495436">"Ga"</string>
@@ -1410,13 +1409,13 @@
<string name="ime_action_default" msgid="8265027027659800121">"Uitvoeren"</string>
<string name="dial_number_using" msgid="6060769078933953531">"Nummer bellen\nmet <xliff:g id="NUMBER">%s</xliff:g>"</string>
<string name="create_contact_using" msgid="6200708808003692594">"Contact maken\nmet <xliff:g id="NUMBER">%s</xliff:g>"</string>
- <string name="grant_credentials_permission_message_header" msgid="5365733888842570481">"De volgende apps verzoeken om toegang tot je account, nu en in de toekomst."</string>
+ <string name="grant_credentials_permission_message_header" msgid="5365733888842570481">"De volgende apps willen toegangsrechten voor je account, nu en in de toekomst."</string>
<string name="grant_credentials_permission_message_footer" msgid="1886710210516246461">"Wil je dit verzoek toestaan?"</string>
<string name="grant_permissions_header_text" msgid="3420736827804657201">"Verzoek om toegang"</string>
<string name="allow" msgid="6195617008611933762">"Toestaan"</string>
<string name="deny" msgid="6632259981847676572">"Weigeren"</string>
- <string name="permission_request_notification_title" msgid="1810025922441048273">"Toestemming gevraagd"</string>
- <string name="permission_request_notification_with_subtitle" msgid="3743417870360129298">"Toestemming gevraagd\nvoor account <xliff:g id="ACCOUNT">%s</xliff:g>."</string>
+ <string name="permission_request_notification_title" msgid="1810025922441048273">"Rechten gevraagd"</string>
+ <string name="permission_request_notification_with_subtitle" msgid="3743417870360129298">"Rechten gevraagd\nvoor account <xliff:g id="ACCOUNT">%s</xliff:g>."</string>
<string name="forward_intent_to_owner" msgid="4620359037192871015">"Je gebruikt deze app buiten je werkprofiel"</string>
<string name="forward_intent_to_work" msgid="3620262405636021151">"U gebruikt deze app in je werkprofiel"</string>
<string name="input_method_binding_label" msgid="1166731601721983656">"Invoermethode"</string>
@@ -1502,7 +1501,7 @@
<string name="shareactionprovider_share_with" msgid="2753089758467748982">"Delen met"</string>
<string name="shareactionprovider_share_with_application" msgid="4902832247173666973">"Delen met <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
<string name="content_description_sliding_handle" msgid="982510275422590757">"Schuifgreep. Tikken en blijven aanraken."</string>
- <string name="description_target_unlock_tablet" msgid="7431571180065859551">"Vegen om te ontgrendelen"</string>
+ <string name="description_target_unlock_tablet" msgid="7431571180065859551">"Swipen om te ontgrendelen"</string>
<string name="action_bar_home_description" msgid="1501655419158631974">"Navigeren naar startpositie"</string>
<string name="action_bar_up_description" msgid="6611579697195026932">"Omhoog navigeren"</string>
<string name="action_menu_overflow_description" msgid="4579536843510088170">"Meer opties"</string>
@@ -1773,7 +1772,7 @@
</plurals>
<string name="restr_pin_try_later" msgid="5897719962541636727">"Probeer het later opnieuw"</string>
<string name="immersive_cling_title" msgid="2307034298721541791">"Volledig scherm wordt weergegeven"</string>
- <string name="immersive_cling_description" msgid="7092737175345204832">"Veeg omlaag vanaf de bovenkant van het scherm om af te sluiten."</string>
+ <string name="immersive_cling_description" msgid="7092737175345204832">"Swipe omlaag vanaf de bovenkant van het scherm om af te sluiten."</string>
<string name="immersive_cling_positive" msgid="7047498036346489883">"Ik snap het"</string>
<string name="done_label" msgid="7283767013231718521">"Gereed"</string>
<string name="hour_picker_description" msgid="5153757582093524635">"Ronde schuifregelaar voor uren"</string>
diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml
index 84815f7a6133..a1fd3f022555 100644
--- a/core/res/res/values-or/strings.xml
+++ b/core/res/res/values-or/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"ଅନଲକ୍‌ କରିବା ପାଇଁ ମେନୁକୁ ଦବାନ୍ତୁ କିମ୍ବା ଜରୁରୀକାଳୀନ କଲ୍‌ କରନ୍ତୁ।"</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"ଅନଲକ୍‌ କରିବା ପାଇଁ ମେନୁକୁ ଦବାନ୍ତୁ।"</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"ଅନଲକ୍‌ କରିବା ପାଇଁ ପାଟର୍ନ ଆଙ୍କନ୍ତୁ"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"ଜରୁରୀକାଳୀନ କଲ୍"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"କଲ୍‌କୁ ଫେରନ୍ତୁ"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"ଠିକ୍!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ"</string>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index c29308fd4c5b..903ff83a0572 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"ਅਣਲਾਕ ਕਰਨ ਲਈ ਮੀਨੂ ਦਬਾਓ ਜਾਂ ਸੰਕਟਕਾਲੀਨ ਕਾਲ ਕਰੋ।"</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"ਅਣਲਾਕ ਕਰਨ ਲਈ ਮੀਨੂ ਦਬਾਓ।"</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"ਅਣਲਾਕ ਕਰਨ ਲਈ ਪੈਟਰਨ ਡ੍ਰਾ ਕਰੋ"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"ਸੰਕਟਕਾਲੀਨ ਕਾਲ"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"ਕਾਲ ਤੇ ਵਾਪਸ ਜਾਓ"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"ਸਹੀ!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index df56457da65a..aeebf8845567 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -838,8 +838,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Naciśnij Menu, aby odblokować lub wykonać połączenie alarmowe."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Naciśnij Menu, aby odblokować."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Narysuj wzór, aby odblokować"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Połączenie alarmowe"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"Powrót do połączenia"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Poprawnie!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Spróbuj ponownie."</string>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index 3ecf28d34ffd..aedc0471ac6f 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Pressione Menu para desbloquear ou fazer uma chamada de emergência."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Pressione Menu para desbloquear."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Desenhe o padrão para desbloquear"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Chamada de emergência"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"Retornar à chamada"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Correto!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Tente novamente"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index dcc8e17609ac..883e4bf09251 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Prima Menu para desbloquear ou efectuar uma chamada de emergência."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Prima Menu para desbloquear."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Desenhar padrão para desbloquear"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Chamada de emergência"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"Regressar à chamada"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Correcto!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Tentar novamente"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 3ecf28d34ffd..aedc0471ac6f 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Pressione Menu para desbloquear ou fazer uma chamada de emergência."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Pressione Menu para desbloquear."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Desenhe o padrão para desbloquear"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Chamada de emergência"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"Retornar à chamada"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Correto!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Tente novamente"</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 64936689ee6e..ebc5827c2a7a 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -835,8 +835,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Apăsați Meniu pentru a debloca sau pentru a efectua apeluri de urgență."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Apăsați Meniu pentru deblocare."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Desenați modelul pentru a debloca"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Apel de urgență"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"Reveniți la apel"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Corect!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Încercați din nou"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 07abf6dbb28d..f3d13ceec060 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -838,8 +838,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Нажмите \"Меню\", чтобы разблокировать экран или вызвать службу экстренной помощи."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Для разблокировки нажмите \"Меню\"."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Введите графический ключ"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Экстренный вызов"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"Вернуться к вызову"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Правильно!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Повторите попытку"</string>
diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml
index d494a36520bf..cc6783a4fb3d 100644
--- a/core/res/res/values-si/strings.xml
+++ b/core/res/res/values-si/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"අගුළු හැරීමට මෙනුව ඔබන්න හෝ හදිසි ඇමතුම ලබාගන්න."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"අගුළු හැරීමට මෙනු ඔබන්න."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"අගුළු ඇරීමට රටාව අඳින්න"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"හදිසි ඇමතුම"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"ඇමතුම වෙත නැවත යන්න"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"නිවැරදියි!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"නැවත උත්සාහ කරන්න"</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 52c53015743b..b6125657f408 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -838,8 +838,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Ak chcete odomknúť telefón alebo uskutočniť tiesňové volanie, stlačte Menu."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Telefón odomknete stlačením tlačidla Menu."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Odomknite nakreslením vzoru"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Tiesňové volanie"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"Zavolať späť"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Správne!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Skúsiť znova"</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index a43c900fb585..9f23a76de1d2 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -838,8 +838,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Če želite odkleniti napravo ali opraviti klic v sili, pritisnite meni."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Če želite odkleniti, pritisnite meni."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Če želite odkleniti, narišite vzorec"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Klic v sili"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"Nazaj na klic"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Pravilno."</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Poskusi znova"</string>
diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml
index 625962fb9bd1..3e7ca92681c5 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Shtyp \"Meny\" për të shkyçur ose për të kryer telefonatë urgjence."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Shtyp \"Meny\" për të shkyçur."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Vizato modelin për ta shkyçur"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Telefonata e urgjencës"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"Kthehu te telefonata"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Saktë!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Provo sërish"</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 6101dac65f95..a3eb3e412c55 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -835,8 +835,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Притисните „Мени“ да бисте откључали телефон или упутите хитан позив."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Притисните „Мени“ за откључавање."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Унесите шаблон за откључавање"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Хитни позив"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"Назад на позив"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Тачно!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Пробајте поново"</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index e30bb14384f9..e1442437df77 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Tryck på Menu för att låsa upp eller ringa nödsamtal."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Tryck på Menu för att låsa upp."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Rita grafiskt lösenord för att låsa upp"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Nödsamtal"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"Tillbaka till samtal"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Korrekt!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Försök igen"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 4e4c0f656c9f..22736d8bca87 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Bonyeza Menyu ili kufungua au kupiga simu ya dharura."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Bonyeza Menyu ili kufungua."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Chora ruwaza ili kufungua"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Simu ya dharura"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"Rudi kwa kupiga simu"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Sahihi!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Jaribu tena"</string>
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index a617248071e0..42b2d9c2f273 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"தடைநீக்க மெனுவை அழுத்தவும் அல்லது அவசர அழைப்பை மேற்கொள்ளவும்."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"திறக்க, மெனுவை அழுத்தவும்."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"திறக்க வடிவத்தை வரையவும்"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"அவசர அழைப்பு"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"அழைப்பிற்குத் திரும்பு"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"சரி!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"மீண்டும் முயற்சிக்கவும்"</string>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index 794fec85bcf7..854427b983a0 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"అన్‌లాక్ చేయడానికి లేదా అత్యవసర కాల్ చేయడానికి మెను నొక్కండి."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"అన్‌లాక్ చేయడానికి మెను నొక్కండి."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"అన్‌లాక్ చేయడానికి నమూనాను గీయండి"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"ఎమర్జెన్సీ కాల్"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"కాల్‌కు తిరిగి వెళ్లు"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"సరైనది!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"మళ్లీ ప్రయత్నించండి"</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 3deb9b2b7b82..4b39c63a1bdf 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"กด เมนู เพื่อปลดล็อกหรือโทรฉุกเฉิน"</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"กด เมนู เพื่อปลดล็อก"</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"วาดรูปแบบเพื่อปลดล็อก"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"หมายเลขฉุกเฉิน"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"กลับสู่การโทร"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"ถูกต้อง!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"ลองอีกครั้ง"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index ccda1c46059e..beebbd23448c 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Pindutin ang Menu upang i-unlock o magsagawa ng pang-emergency na tawag."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Pindutin ang Menu upang i-unlock."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Iguhit ang pattern upang i-unlock"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Emergency na tawag"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"Bumalik sa tawag"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Tama!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Subukang muli"</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 85c69860eb81..17852a6615de 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Kilidi açmak veya acil çağrı yapmak için Menü\'ye basın."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Kilidi açmak için Menü\'ye basın."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Kilit açmak için deseni çizin"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Acil durum araması"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"Çağrıya dön"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Doğru!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Tekrar deneyin"</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 8ae20a50f7f3..31684e0d1b29 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -838,8 +838,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Натис. меню, щоб розбл. чи зробити авар. виклик."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Натисн. меню, щоб розбл."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Намал. ключ, щоб розбл."</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Екстрений виклик"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"Поверн. до дзвін."</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Правильно!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Повторіть спробу"</string>
diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml
index 94c6cd450a6c..ed32b2453bf3 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"غیر مقفل کرنے کیلئے مینو دبائیں یا ہنگامی کال کریں۔"</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"غیر مقفل کرنے کیلئے مینو دبائیں۔"</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"غیر مقفل کرنے کیلئے پیٹرن کو ڈرا کریں"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"ہنگامی کال"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"کال پر واپس جائیں"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"صحیح!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"دوبارہ کوشش کریں"</string>
diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml
index 74676dfcf226..4f196440334c 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Qulfdan chiqarish yoki favqulodda qo‘ng‘iroqni amalga oshirish uchun \"Menyu\"ni bosing."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Qulfni ochish uchun \"Menyu\"ga bosing."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Qulfni ochish uchun grafik kalitni chizing"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Favqulodda chaqiruv"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"Qo‘ng‘iroqni qaytarish"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"To‘g‘ri!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Qaytadan urining"</string>
@@ -902,7 +901,7 @@
<string name="keyguard_accessibility_user_selector" msgid="1466067610235696600">"Foydalanuvchi tanlagichi"</string>
<string name="keyguard_accessibility_status" msgid="6792745049712397237">"Holati"</string>
<string name="keyguard_accessibility_camera" msgid="7862557559464986528">"Kamera"</string>
- <string name="keygaurd_accessibility_media_controls" msgid="2267379779900620614">"Media boshqaruvlari"</string>
+ <string name="keygaurd_accessibility_media_controls" msgid="2267379779900620614">"Media boshqaruvi"</string>
<string name="keyguard_accessibility_widget_reorder_start" msgid="7066213328912939191">"Vidjetlarni saralashni boshlandi."</string>
<string name="keyguard_accessibility_widget_reorder_end" msgid="1083806817600593490">"Vidjetlarni saralash tugatildi."</string>
<string name="keyguard_accessibility_widget_deleted" msgid="1509738950119878705">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> vidjeti o‘chirildi."</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 48f38583220d..3cb264da95c3 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Nhấn vào Menu để mở khóa hoặc thực hiện cuộc gọi khẩn cấp."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Nhấn vào Menu để mở khóa."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Vẽ hình để mở khóa"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Cuộc gọi khẩn cấp"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"Quay lại cuộc gọi"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Chính xác!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Thử lại"</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index bf381ec53751..0a241dab0954 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"按 Menu 解锁或进行紧急呼救。"</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"按 MENU 解锁。"</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"绘制解锁图案"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"紧急呼叫"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"返回通话"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"正确!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"重试"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index a3b20d128726..6e584d6182d9 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"按選單鍵解鎖或撥打緊急電話。"</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"按選單鍵解鎖。"</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"畫出解鎖圖形以解除鎖定螢幕"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"緊急電話"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"返回通話"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"正確!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"再試一次"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index f6543c9285d2..ab1a42375871 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"按下 [Menu] 解鎖或撥打緊急電話。"</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"按下 Menu 鍵解鎖。"</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"畫出解鎖圖案"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"緊急電話"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"返回通話"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"正確!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"再試一次"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 85f54e9f9f5e..582d4350882c 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -832,8 +832,7 @@
<string name="lockscreen_instructions_when_pattern_enabled" msgid="7982445492532123308">"Chofoza Menyu ukuvula noma ukwenza ikholi ephuthumayo."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="7434061749374801753">"Chofoza Menyu ukuvula."</string>
<string name="lockscreen_pattern_instructions" msgid="3169991838169244941">"Dweba iphathini ukuvula"</string>
- <!-- no translation found for lockscreen_emergency_call (7549683825868928636) -->
- <skip />
+ <string name="lockscreen_emergency_call" msgid="7549683825868928636">"Ikholi ephuthumayo"</string>
<string name="lockscreen_return_to_call" msgid="3156883574692006382">"Buyela ekholini"</string>
<string name="lockscreen_pattern_correct" msgid="8050630103651508582">"Lungile!"</string>
<string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"Zama futhi"</string>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 28a164f139e1..8913e8b18750 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -983,7 +983,7 @@
with the modem or some other restricted hardware, add "/dev/bus/usb/001/"
to this list. If this is empty, no parts of the host USB bus will be excluded.
-->
- <string-array name="config_usbHostBlacklist" translatable="false">
+ <string-array name="config_usbHostDenylist" translatable="false">
</string-array>
<!-- List of paths to serial ports that are available to the serial manager.
@@ -2286,7 +2286,7 @@
</integer-array>
<!-- Set to true to add links to Cell Broadcast app from Settings and MMS app. -->
- <bool name="config_cellBroadcastAppLinks">false</bool>
+ <bool name="config_cellBroadcastAppLinks">true</bool>
<!-- The default value if the SyncStorageEngine should sync automatically or not -->
<bool name="config_syncstorageengine_masterSyncAutomatically">true</bool>
@@ -2802,6 +2802,9 @@
eutran : eutranSupportedRelease
nfc : contactlessSupportedRelease
crl : rspCrlSupportedVersion
+ nrepc : nrEpcSupportedRelease
+ nr5gc : nr5gcSupportedRelease
+ eutran5gc : eutran5gcSupportedRelease
-->
<string-array translatable="false" name="config_telephonyEuiccDeviceCapabilities">
<!-- Example:
@@ -2813,6 +2816,9 @@
<item>"eutran,11"</item>
<item>"nfc,1"</item>
<item>"crl,1"</item>
+ <item>"nrepc,15"</item>
+ <item>"nr5gc,15"</item>
+ <item>"eutran5gc,15"</item>
-->
</string-array>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 16427cd50577..d5c72da2d29f 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1853,7 +1853,7 @@
<java-symbol type="array" name="config_tether_upstream_types" />
<java-symbol type="array" name="config_tether_usb_regexs" />
<java-symbol type="array" name="config_tether_wifi_regexs" />
- <java-symbol type="array" name="config_usbHostBlacklist" />
+ <java-symbol type="array" name="config_usbHostDenylist" />
<java-symbol type="array" name="config_serialPorts" />
<java-symbol type="array" name="radioAttributes" />
<java-symbol type="array" name="config_oemUsbModeOverride" />
diff --git a/core/sysprop/Android.bp b/core/sysprop/Android.bp
new file mode 100644
index 000000000000..7f20a0ba6642
--- /dev/null
+++ b/core/sysprop/Android.bp
@@ -0,0 +1,21 @@
+// 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.
+
+sysprop_library {
+ name: "com.android.sysprop.localization",
+ srcs: ["LocalizationProperties.sysprop"],
+ property_owner: "Platform",
+ api_packages: ["android.sysprop"],
+ vendor_available: false,
+}
diff --git a/core/sysprop/LocalizationProperties.sysprop b/core/sysprop/LocalizationProperties.sysprop
new file mode 100644
index 000000000000..65f544fa6179
--- /dev/null
+++ b/core/sysprop/LocalizationProperties.sysprop
@@ -0,0 +1,24 @@
+# Copyright (C) 2020 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+module: "android.sysprop.LocalizationProperties"
+owner: Platform
+
+prop {
+ api_name: "locale_filter"
+ type: String
+ prop_name: "ro.localization.locale_filter"
+ scope: Internal
+ access: Readonly
+}
diff --git a/core/sysprop/api/com.android.sysprop.localization-current.txt b/core/sysprop/api/com.android.sysprop.localization-current.txt
new file mode 100644
index 000000000000..fe4f4578683c
--- /dev/null
+++ b/core/sysprop/api/com.android.sysprop.localization-current.txt
@@ -0,0 +1,9 @@
+props {
+ module: "android.sysprop.LocalizationProperties"
+ prop {
+ api_name: "locale_filter"
+ type: String
+ scope: Internal
+ prop_name: "ro.localization.locale_filter"
+ }
+}
diff --git a/core/sysprop/api/com.android.sysprop.localization-latest.txt b/core/sysprop/api/com.android.sysprop.localization-latest.txt
new file mode 100644
index 000000000000..fe4f4578683c
--- /dev/null
+++ b/core/sysprop/api/com.android.sysprop.localization-latest.txt
@@ -0,0 +1,9 @@
+props {
+ module: "android.sysprop.LocalizationProperties"
+ prop {
+ api_name: "locale_filter"
+ type: String
+ scope: Internal
+ prop_name: "ro.localization.locale_filter"
+ }
+}
diff --git a/core/tests/bugreports/Android.bp b/core/tests/bugreports/Android.bp
index 1edd9623ed2d..e42b4b4ae2bf 100644
--- a/core/tests/bugreports/Android.bp
+++ b/core/tests/bugreports/Android.bp
@@ -20,7 +20,11 @@ android_test {
"android.test.runner",
"android.test.base",
],
- static_libs: ["androidx.test.rules", "truth-prebuilt"],
+ static_libs: [
+ "androidx.test.rules",
+ "androidx.test.uiautomator_uiautomator",
+ "truth-prebuilt",
+ ],
test_suites: ["general-tests"],
sdk_version: "test_current",
platform_apis: true,
diff --git a/core/tests/bugreports/src/com/android/os/bugreports/tests/BugreportManagerTest.java b/core/tests/bugreports/src/com/android/os/bugreports/tests/BugreportManagerTest.java
index 153337727e96..9246a2335050 100644
--- a/core/tests/bugreports/src/com/android/os/bugreports/tests/BugreportManagerTest.java
+++ b/core/tests/bugreports/src/com/android/os/bugreports/tests/BugreportManagerTest.java
@@ -18,6 +18,8 @@ package com.android.os.bugreports.tests;
import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import android.Manifest;
@@ -25,17 +27,27 @@ import android.content.Context;
import android.os.BugreportManager;
import android.os.BugreportManager.BugreportCallback;
import android.os.BugreportParams;
+import android.os.FileUtils;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.ParcelFileDescriptor;
+import android.os.StrictMode;
import android.util.Log;
+import androidx.annotation.NonNull;
import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.LargeTest;
+import androidx.test.uiautomator.By;
+import androidx.test.uiautomator.BySelector;
+import androidx.test.uiautomator.UiDevice;
+import androidx.test.uiautomator.UiObject2;
+import androidx.test.uiautomator.Until;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
+import org.junit.rules.ExternalResource;
import org.junit.rules.TestName;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
@@ -51,9 +63,11 @@ import java.util.concurrent.TimeUnit;
@RunWith(JUnit4.class)
public class BugreportManagerTest {
@Rule public TestName name = new TestName();
+ @Rule public ExtendedStrictModeVmPolicy mTemporaryVmPolicy = new ExtendedStrictModeVmPolicy();
private static final String TAG = "BugreportManagerTest";
private static final long BUGREPORT_TIMEOUT_MS = TimeUnit.MINUTES.toMillis(10);
+ private static final long UIAUTOMATOR_TIMEOUT_MS = TimeUnit.SECONDS.toMillis(10);
private Handler mHandler;
private Executor mExecutor;
@@ -86,6 +100,8 @@ public class BugreportManagerTest {
@After
public void teardown() throws Exception {
dropPermissions();
+ FileUtils.closeQuietly(mBugreportFd);
+ FileUtils.closeQuietly(mScreenshotFd);
}
@@ -95,47 +111,45 @@ public class BugreportManagerTest {
// wifi bugreport does not take screenshot
mBrm.startBugreport(mBugreportFd, null /*screenshotFd = null*/, wifi(),
mExecutor, callback);
+ shareConsentDialog(ConsentReply.ALLOW);
waitTillDoneOrTimeout(callback);
assertThat(callback.isDone()).isTrue();
// Wifi bugreports should not receive any progress.
assertThat(callback.hasReceivedProgress()).isFalse();
- // TODO: Because of b/130234145, consent dialog is not shown; so we get a timeout error.
- // When the bug is fixed, accept consent via UIAutomator and verify contents
- // of mBugreportFd.
- assertThat(callback.getErrorCode()).isEqualTo(
- BugreportCallback.BUGREPORT_ERROR_USER_CONSENT_TIMED_OUT);
+ assertThat(mBugreportFile.length()).isGreaterThan(0L);
assertFdsAreClosed(mBugreportFd);
}
+ @LargeTest
@Test
public void normalFlow_interactive() throws Exception {
BugreportCallbackImpl callback = new BugreportCallbackImpl();
// interactive bugreport does not take screenshot
mBrm.startBugreport(mBugreportFd, null /*screenshotFd = null*/, interactive(),
mExecutor, callback);
-
+ shareConsentDialog(ConsentReply.ALLOW);
waitTillDoneOrTimeout(callback);
+
assertThat(callback.isDone()).isTrue();
// Interactive bugreports show progress updates.
assertThat(callback.hasReceivedProgress()).isTrue();
- assertThat(callback.getErrorCode()).isEqualTo(
- BugreportCallback.BUGREPORT_ERROR_USER_CONSENT_TIMED_OUT);
+ assertThat(mBugreportFile.length()).isGreaterThan(0L);
assertFdsAreClosed(mBugreportFd);
}
+ @LargeTest
@Test
public void normalFlow_full() throws Exception {
BugreportCallbackImpl callback = new BugreportCallbackImpl();
mBrm.startBugreport(mBugreportFd, mScreenshotFd, full(), mExecutor, callback);
-
+ shareConsentDialog(ConsentReply.ALLOW);
waitTillDoneOrTimeout(callback);
+
assertThat(callback.isDone()).isTrue();
- assertThat(callback.getErrorCode()).isEqualTo(
- BugreportCallback.BUGREPORT_ERROR_USER_CONSENT_TIMED_OUT);
- // bugreport and screenshot files should be empty when user consent timed out.
- assertThat(mBugreportFile.length()).isEqualTo(0);
- assertThat(mScreenshotFile.length()).isEqualTo(0);
+ // bugreport and screenshot files shouldn't be empty when user consents.
+ assertThat(mBugreportFile.length()).isGreaterThan(0L);
+ assertThat(mScreenshotFile.length()).isGreaterThan(0L);
assertFdsAreClosed(mBugreportFd, mScreenshotFd);
}
@@ -144,6 +158,8 @@ public class BugreportManagerTest {
// Start bugreport #1
BugreportCallbackImpl callback = new BugreportCallbackImpl();
mBrm.startBugreport(mBugreportFd, mScreenshotFd, wifi(), mExecutor, callback);
+ // TODO(b/162389762) Make sure the wait time is reasonable
+ shareConsentDialog(ConsentReply.ALLOW);
// Before #1 is done, try to start #2.
assertThat(callback.isDone()).isFalse();
@@ -375,4 +391,88 @@ public class BugreportManagerTest {
private static BugreportParams full() {
return new BugreportParams(BugreportParams.BUGREPORT_MODE_FULL);
}
+
+ /* Allow/deny the consent dialog to sharing bugreport data or check existence only. */
+ private enum ConsentReply {
+ ALLOW,
+ DENY,
+ TIMEOUT
+ }
+
+ /*
+ * Ensure the consent dialog is shown and take action according to <code>consentReply<code/>.
+ * It will fail if the dialog is not shown when <code>ignoreNotFound<code/> is false.
+ */
+ private void shareConsentDialog(@NonNull ConsentReply consentReply) throws Exception {
+ mTemporaryVmPolicy.permitIncorrectContextUse();
+ final UiDevice device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
+
+ // Unlock before finding/clicking an object.
+ device.wakeUp();
+ device.executeShellCommand("wm dismiss-keyguard");
+
+ final BySelector consentTitleObj = By.res("android", "alertTitle");
+ if (!device.wait(Until.hasObject(consentTitleObj), UIAUTOMATOR_TIMEOUT_MS)) {
+ fail("The consent dialog is not found");
+ }
+ if (consentReply.equals(ConsentReply.TIMEOUT)) {
+ return;
+ }
+ final BySelector selector;
+ if (consentReply.equals(ConsentReply.ALLOW)) {
+ selector = By.res("android", "button1");
+ Log.d(TAG, "Allow the consent dialog");
+ } else { // ConsentReply.DENY
+ selector = By.res("android", "button2");
+ Log.d(TAG, "Deny the consent dialog");
+ }
+ final UiObject2 btnObj = device.findObject(selector);
+ assertNotNull("The button of consent dialog is not found", btnObj);
+ btnObj.click();
+
+ Log.d(TAG, "Wait for the dialog to be dismissed");
+ assertTrue(device.wait(Until.gone(consentTitleObj), UIAUTOMATOR_TIMEOUT_MS));
+ }
+
+ /**
+ * A rule to change strict mode vm policy temporarily till test method finished.
+ *
+ * To permit the non-visual context usage in tests while taking bugreports need user consent,
+ * or UiAutomator/BugreportManager.DumpstateListener would run into error.
+ * UiDevice#findObject creates UiObject2, its Gesture object and ViewConfiguration and
+ * UiObject2#click need to know bounds. Both of them access to WindowManager internally without
+ * visual context comes from InstrumentationRegistry and violate the policy.
+ * Also <code>DumpstateListener<code/> violate the policy when onScreenshotTaken is called.
+ *
+ * TODO(b/161201609) Remove this class once violations fixed.
+ */
+ static class ExtendedStrictModeVmPolicy extends ExternalResource {
+ private boolean mWasVmPolicyChanged = false;
+ private StrictMode.VmPolicy mOldVmPolicy;
+
+ @Override
+ protected void after() {
+ restoreVmPolicyIfNeeded();
+ }
+
+ public void permitIncorrectContextUse() {
+ // Allow to call multiple times without losing old policy.
+ if (mOldVmPolicy == null) {
+ mOldVmPolicy = StrictMode.getVmPolicy();
+ }
+ StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
+ .detectAll()
+ .permitIncorrectContextUse()
+ .penaltyLog()
+ .build());
+ mWasVmPolicyChanged = true;
+ }
+
+ private void restoreVmPolicyIfNeeded() {
+ if (mWasVmPolicyChanged && mOldVmPolicy != null) {
+ StrictMode.setVmPolicy(mOldVmPolicy);
+ mOldVmPolicy = null;
+ }
+ }
+ }
}
diff --git a/core/tests/coretests/src/android/os/VintfObjectTest.java b/core/tests/coretests/src/android/os/VintfObjectTest.java
index af3660a6dab9..ae6e79a040f7 100644
--- a/core/tests/coretests/src/android/os/VintfObjectTest.java
+++ b/core/tests/coretests/src/android/os/VintfObjectTest.java
@@ -20,7 +20,7 @@ import junit.framework.TestCase;
public class VintfObjectTest extends TestCase {
/**
- * Sanity check for {@link VintfObject#report VintfObject.report()}.
+ * Quick check for {@link VintfObject#report VintfObject.report()}.
*/
public void testReport() {
String[] xmls = VintfObject.report();
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 0286a7148b0b..f834ce798a27 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -436,6 +436,14 @@ applications that come with the platform
<permission name="android.car.permission.CAR_DRIVING_STATE" />
<!-- Permissions required for ATS tests - AtsDeviceInfo, AtsAudioDeviceTestCases -->
<permission name="android.car.permission.CAR_CONTROL_AUDIO_VOLUME" />
+ <!-- Permissions required for ATS tests - AtsDeviceInfo -->
+ <permission name="android.car.permission.CAR_DIAGNOSTICS" />
+ <!-- Permissions required for ATS tests - AtsDeviceInfo -->
+ <permission name="android.car.permission.CLEAR_CAR_DIAGNOSTICS" />
+ <!-- Permissions required for ATS tests - AtsCarHostTestCases -->
+ <permission name="android.car.permission.CONTROL_APP_BLOCKING" />
+ <!-- Permissions required for ATS tests - AtsCarHostTestCases -->
+ <permission name="android.car.permission.CAR_UX_RESTRICTIONS_CONFIGURATION" />
</privapp-permissions>
<privapp-permissions package="com.android.statementservice">
diff --git a/data/keyboards/Generic.kl b/data/keyboards/Generic.kl
index d92dbb2125ab..4cdfbb8ce27f 100644
--- a/data/keyboards/Generic.kl
+++ b/data/keyboards/Generic.kl
@@ -412,6 +412,7 @@ key 582 VOICE_ASSIST
key 583 ASSIST
# Keys defined by HID usages
+key usage 0x0c0067 WINDOW
key usage 0x0c006F BRIGHTNESS_UP
key usage 0x0c0070 BRIGHTNESS_DOWN
diff --git a/graphics/java/android/graphics/HardwareRenderer.java b/graphics/java/android/graphics/HardwareRenderer.java
index 1da434496297..b3103fd516dd 100644
--- a/graphics/java/android/graphics/HardwareRenderer.java
+++ b/graphics/java/android/graphics/HardwareRenderer.java
@@ -23,6 +23,7 @@ import android.annotation.Nullable;
import android.app.Activity;
import android.app.ActivityManager;
import android.content.Context;
+import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.hardware.display.DisplayManager;
import android.os.IBinder;
@@ -157,7 +158,7 @@ public class HardwareRenderer {
protected RenderNode mRootNode;
private boolean mOpaque = true;
private boolean mForceDark = false;
- private boolean mIsWideGamut = false;
+ private @ActivityInfo.ColorMode int mColorMode = ActivityInfo.COLOR_MODE_DEFAULT;
/**
* Creates a new instance of a HardwareRenderer. The HardwareRenderer will default
@@ -167,7 +168,7 @@ public class HardwareRenderer {
ProcessInitializer.sInstance.initDisplayInfo();
mRootNode = RenderNode.adopt(nCreateRootRenderNode());
mRootNode.setClipToBounds(false);
- mNativeProxy = nCreateProxy(!mOpaque, mIsWideGamut, mRootNode.mNativeRenderNode);
+ mNativeProxy = nCreateProxy(!mOpaque, mRootNode.mNativeRenderNode);
if (mNativeProxy == 0) {
throw new OutOfMemoryError("Unable to create hardware renderer");
}
@@ -619,17 +620,17 @@ public class HardwareRenderer {
}
/**
- * Enable/disable wide gamut rendering on this renderer. Whether or not the actual rendering
- * will be wide gamut depends on the hardware support for such rendering.
+ * Sets the desired color mode on this renderer. Whether or not the actual rendering
+ * will use the requested colorMode depends on the hardware support for such rendering.
*
- * @param wideGamut true if this renderer should render in wide gamut, false if it should
- * render in sRGB
- * TODO: Figure out color...
+ * @param colorMode The @{@link ActivityInfo.ColorMode} to request
* @hide
*/
- public void setWideGamut(boolean wideGamut) {
- mIsWideGamut = wideGamut;
- nSetWideGamut(mNativeProxy, wideGamut);
+ public void setColorMode(@ActivityInfo.ColorMode int colorMode) {
+ if (mColorMode != colorMode) {
+ mColorMode = colorMode;
+ nSetColorMode(mNativeProxy, colorMode);
+ }
}
/**
@@ -804,11 +805,6 @@ public class HardwareRenderer {
nSetPictureCaptureCallback(mNativeProxy, callback);
}
- /** @hide */
- public boolean isWideGamut() {
- return mIsWideGamut;
- }
-
/** called by native */
static void invokePictureCapturedCallback(long picturePtr, PictureCapturedCallback callback) {
Picture picture = new Picture(picturePtr);
@@ -1207,8 +1203,7 @@ public class HardwareRenderer {
private static native long nCreateRootRenderNode();
- private static native long nCreateProxy(boolean translucent, boolean isWideGamut,
- long rootRenderNode);
+ private static native long nCreateProxy(boolean translucent, long rootRenderNode);
private static native void nDeleteProxy(long nativeProxy);
@@ -1230,7 +1225,7 @@ public class HardwareRenderer {
private static native void nSetOpaque(long nativeProxy, boolean opaque);
- private static native void nSetWideGamut(long nativeProxy, boolean wideGamut);
+ private static native void nSetColorMode(long nativeProxy, int colorMode);
private static native int nSyncAndDrawFrame(long nativeProxy, long[] frameInfo, int size);
diff --git a/graphics/proto/Android.bp b/graphics/proto/Android.bp
index ddced597759f..ea79b731a365 100644
--- a/graphics/proto/Android.bp
+++ b/graphics/proto/Android.bp
@@ -1,10 +1,10 @@
java_library_static {
- name: "game-driver-protos",
+ name: "updatable-driver-protos",
host_supported: true,
proto: {
type: "lite",
},
- srcs: ["game_driver.proto"],
+ srcs: ["updatable_driver.proto"],
jarjar_rules: "jarjar-rules.txt",
- sdk_version: "28",
+ sdk_version: "30",
}
diff --git a/graphics/proto/game_driver.proto b/graphics/proto/updatable_driver.proto
index fd7ffccac24c..cbc9424854d1 100644
--- a/graphics/proto/game_driver.proto
+++ b/graphics/proto/updatable_driver.proto
@@ -16,16 +16,16 @@
syntax = "proto2";
-package android.gamedriver;
+package android.updatabledriver;
-option java_package = "android.gamedriver";
-option java_outer_classname = "GameDriverProto";
+option java_package = "android.updatabledriver";
+option java_outer_classname = "UpdatableDriverProto";
-message Blacklist {
+message Denylist {
optional int64 version_code = 1;
repeated string package_names = 2;
}
-message Blacklists {
- repeated Blacklist blacklists = 1;
+message Denylists {
+ repeated Denylist denylists = 1;
}
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/sidecar/SettingsSidecarImpl.java b/libs/WindowManager/Jetpack/src/androidx/window/sidecar/SettingsSidecarImpl.java
index 92e575804bbe..ca3a5112bc55 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/sidecar/SettingsSidecarImpl.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/sidecar/SettingsSidecarImpl.java
@@ -192,7 +192,7 @@ class SettingsSidecarImpl extends StubSidecar {
Rect featureRect = new Rect(left, top, right, bottom);
rotateRectToDisplayRotation(featureRect, displayId);
transformToWindowSpaceRect(featureRect, windowToken);
- if (!featureRect.isEmpty()) {
+ if (isNotZero(featureRect)) {
SidecarDisplayFeature feature = new SidecarDisplayFeature();
feature.setRect(featureRect);
feature.setType(type);
@@ -207,6 +207,10 @@ class SettingsSidecarImpl extends StubSidecar {
return features;
}
+ private static boolean isNotZero(Rect rect) {
+ return rect.height() > 0 || rect.width() > 0;
+ }
+
@Override
protected void onListenersChanged() {
if (mSettingsObserver == null) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java
index 338ece5afbc2..aeda2d923490 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java
@@ -68,12 +68,15 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged
private final SparseArray<PerDisplay> mImePerDisplay = new SparseArray<>();
private final ArrayList<ImePositionProcessor> mPositionProcessors = new ArrayList<>();
- public DisplayImeController(IWindowManager wmService, DisplayController displayController,
+ protected DisplayImeController(IWindowManager wmService, DisplayController displayController,
Handler mainHandler, TransactionPool transactionPool) {
mHandler = mainHandler;
mWmService = wmService;
mTransactionPool = transactionPool;
mDisplayController = displayController;
+ }
+
+ protected void startMonitorDisplays() {
mDisplayController.addDisplayWindowListener(this);
}
@@ -490,4 +493,29 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged
return IInputMethodManager.Stub.asInterface(
ServiceManager.getService(Context.INPUT_METHOD_SERVICE));
}
+
+ /** Builds {@link DisplayImeController} instance. */
+ public static class Builder {
+ private IWindowManager mWmService;
+ private DisplayController mDisplayController;
+ private Handler mHandler;
+ private TransactionPool mTransactionPool;
+
+ public Builder(IWindowManager wmService, DisplayController displayController,
+ Handler handler, TransactionPool transactionPool) {
+ mWmService = wmService;
+ mDisplayController = displayController;
+ mHandler = handler;
+ mTransactionPool = transactionPool;
+ }
+
+ /** Builds and initializes {@link DisplayImeController} instance. */
+ public DisplayImeController build() {
+ DisplayImeController displayImeController = new DisplayImeController(mWmService,
+ mDisplayController, mHandler, mTransactionPool);
+ // Separates startMonitorDisplays from constructor to prevent circular init issue.
+ displayImeController.startMonitorDisplays();
+ return displayImeController;
+ }
+ }
}
diff --git a/libs/androidfw/Android.bp b/libs/androidfw/Android.bp
index 3893041b05d9..8ab7da5257ab 100644
--- a/libs/androidfw/Android.bp
+++ b/libs/androidfw/Android.bp
@@ -101,7 +101,7 @@ cc_library {
},
},
sanitize: {
- blacklist: "libandroidfw_blacklist.txt",
+ blocklist: "libandroidfw_blocklist.txt",
},
}
diff --git a/libs/androidfw/libandroidfw_blacklist.txt b/libs/androidfw/libandroidfw_blocklist.txt
index dd17e4d5b1e8..dd17e4d5b1e8 100644
--- a/libs/androidfw/libandroidfw_blacklist.txt
+++ b/libs/androidfw/libandroidfw_blocklist.txt
diff --git a/libs/hwui/AutoBackendTextureRelease.cpp b/libs/hwui/AutoBackendTextureRelease.cpp
index 72747e8fa543..33264d5d5c86 100644
--- a/libs/hwui/AutoBackendTextureRelease.cpp
+++ b/libs/hwui/AutoBackendTextureRelease.cpp
@@ -25,7 +25,8 @@ using namespace android::uirenderer::renderthread;
namespace android {
namespace uirenderer {
-AutoBackendTextureRelease::AutoBackendTextureRelease(GrContext* context, AHardwareBuffer* buffer) {
+AutoBackendTextureRelease::AutoBackendTextureRelease(GrDirectContext* context,
+ AHardwareBuffer* buffer) {
AHardwareBuffer_Desc desc;
AHardwareBuffer_describe(buffer, &desc);
bool createProtectedImage = 0 != (desc.usage & AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT);
@@ -67,8 +68,9 @@ static void releaseProc(SkImage::ReleaseContext releaseContext) {
textureRelease->unref(false);
}
-void AutoBackendTextureRelease::makeImage(AHardwareBuffer* buffer, android_dataspace dataspace,
- GrContext* context) {
+void AutoBackendTextureRelease::makeImage(AHardwareBuffer* buffer,
+ android_dataspace dataspace,
+ GrDirectContext* context) {
AHardwareBuffer_Desc desc;
AHardwareBuffer_describe(buffer, &desc);
SkColorType colorType = GrAHardwareBufferUtils::GetSkColorTypeFromBufferFormat(desc.format);
@@ -81,7 +83,7 @@ void AutoBackendTextureRelease::makeImage(AHardwareBuffer* buffer, android_datas
}
}
-void AutoBackendTextureRelease::newBufferContent(GrContext* context) {
+void AutoBackendTextureRelease::newBufferContent(GrDirectContext* context) {
if (mBackendTexture.isValid()) {
mUpdateProc(mImageCtx, context);
}
diff --git a/libs/hwui/AutoBackendTextureRelease.h b/libs/hwui/AutoBackendTextureRelease.h
index acdd63cb7921..06f51fcd1105 100644
--- a/libs/hwui/AutoBackendTextureRelease.h
+++ b/libs/hwui/AutoBackendTextureRelease.h
@@ -31,7 +31,8 @@ namespace uirenderer {
*/
class AutoBackendTextureRelease final {
public:
- AutoBackendTextureRelease(GrContext* context, AHardwareBuffer* buffer);
+ AutoBackendTextureRelease(GrDirectContext* context,
+ AHardwareBuffer* buffer);
const GrBackendTexture& getTexture() const { return mBackendTexture; }
@@ -42,9 +43,11 @@ public:
inline sk_sp<SkImage> getImage() const { return mImage; }
- void makeImage(AHardwareBuffer* buffer, android_dataspace dataspace, GrContext* context);
+ void makeImage(AHardwareBuffer* buffer,
+ android_dataspace dataspace,
+ GrDirectContext* context);
- void newBufferContent(GrContext* context);
+ void newBufferContent(GrDirectContext* context);
private:
// The only way to invoke dtor is with unref, when mUsageCount is 0.
diff --git a/libs/hwui/ColorMode.h b/libs/hwui/ColorMode.h
new file mode 100644
index 000000000000..6d387f9ef43d
--- /dev/null
+++ b/libs/hwui/ColorMode.h
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+namespace android::uirenderer {
+
+// Must match the constants in ActivityInfo.java
+enum class ColorMode {
+ // SRGB means HWUI will produce buffer in SRGB color space.
+ Default = 0,
+ // WideColorGamut selects the most optimal colorspace & format for the device's display
+ // Most commonly DisplayP3 + RGBA_8888 currently.
+ WideColorGamut = 1,
+ // HDR Rec2020 + F16
+ Hdr = 2,
+ // HDR Rec2020 + 1010102
+ Hdr10 = 3,
+};
+
+} // namespace android::uirenderer
diff --git a/libs/hwui/DeferredLayerUpdater.cpp b/libs/hwui/DeferredLayerUpdater.cpp
index 67d8c07e61de..6589dbd50cf7 100644
--- a/libs/hwui/DeferredLayerUpdater.cpp
+++ b/libs/hwui/DeferredLayerUpdater.cpp
@@ -189,7 +189,7 @@ void DeferredLayerUpdater::detachSurfaceTexture() {
sk_sp<SkImage> DeferredLayerUpdater::ImageSlot::createIfNeeded(AHardwareBuffer* buffer,
android_dataspace dataspace,
bool forceCreate,
- GrContext* context) {
+ GrDirectContext* context) {
if (!mTextureRelease || !mTextureRelease->getImage().get() || dataspace != mDataspace ||
forceCreate || mBuffer != buffer) {
if (buffer != mBuffer) {
diff --git a/libs/hwui/DeferredLayerUpdater.h b/libs/hwui/DeferredLayerUpdater.h
index 05f3774d6951..6731e9c428d6 100644
--- a/libs/hwui/DeferredLayerUpdater.h
+++ b/libs/hwui/DeferredLayerUpdater.h
@@ -106,7 +106,7 @@ private:
~ImageSlot() { clear(); }
sk_sp<SkImage> createIfNeeded(AHardwareBuffer* buffer, android_dataspace dataspace,
- bool forceCreate, GrContext* context);
+ bool forceCreate, GrDirectContext* context);
private:
void clear();
diff --git a/libs/hwui/HardwareBitmapUploader.cpp b/libs/hwui/HardwareBitmapUploader.cpp
index c2d2ff874816..87244427a719 100644
--- a/libs/hwui/HardwareBitmapUploader.cpp
+++ b/libs/hwui/HardwareBitmapUploader.cpp
@@ -21,7 +21,7 @@
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
#include <GLES3/gl3.h>
-#include <GrContext.h>
+#include <GrDirectContext.h>
#include <SkCanvas.h>
#include <SkImage.h>
#include <utils/GLUtils.h>
@@ -285,7 +285,7 @@ private:
return (image.get() != nullptr);
}
- sk_sp<GrContext> mGrContext;
+ sk_sp<GrDirectContext> mGrContext;
renderthread::VulkanManager mVulkanManager;
std::mutex mVkLock;
};
diff --git a/libs/hwui/Readback.cpp b/libs/hwui/Readback.cpp
index 0dea354b7200..b71bb07dbc86 100644
--- a/libs/hwui/Readback.cpp
+++ b/libs/hwui/Readback.cpp
@@ -118,7 +118,7 @@ CopyResult Readback::copyImageInto(const sk_sp<SkImage>& image, Matrix4& texTran
}
int imgWidth = image->width();
int imgHeight = image->height();
- sk_sp<GrContext> grContext = sk_ref_sp(mRenderThread.getGrContext());
+ sk_sp<GrDirectContext> grContext = sk_ref_sp(mRenderThread.getGrContext());
if (bitmap->colorType() == kRGBA_F16_SkColorType &&
!grContext->colorTypeSupportedAsSurface(bitmap->colorType())) {
diff --git a/libs/hwui/jni/android_graphics_HardwareRenderer.cpp b/libs/hwui/jni/android_graphics_HardwareRenderer.cpp
index 42743db3061c..7d6875f59d17 100644
--- a/libs/hwui/jni/android_graphics_HardwareRenderer.cpp
+++ b/libs/hwui/jni/android_graphics_HardwareRenderer.cpp
@@ -143,11 +143,10 @@ static jlong android_view_ThreadedRenderer_createRootRenderNode(JNIEnv* env, job
}
static jlong android_view_ThreadedRenderer_createProxy(JNIEnv* env, jobject clazz,
- jboolean translucent, jboolean isWideGamut, jlong rootRenderNodePtr) {
+ jboolean translucent, jlong rootRenderNodePtr) {
RootRenderNode* rootRenderNode = reinterpret_cast<RootRenderNode*>(rootRenderNodePtr);
ContextFactoryImpl factory(rootRenderNode);
RenderProxy* proxy = new RenderProxy(translucent, rootRenderNode, &factory);
- proxy->setWideGamut(isWideGamut);
return (jlong) proxy;
}
@@ -218,10 +217,10 @@ static void android_view_ThreadedRenderer_setOpaque(JNIEnv* env, jobject clazz,
proxy->setOpaque(opaque);
}
-static void android_view_ThreadedRenderer_setWideGamut(JNIEnv* env, jobject clazz,
- jlong proxyPtr, jboolean wideGamut) {
+static void android_view_ThreadedRenderer_setColorMode(JNIEnv* env, jobject clazz,
+ jlong proxyPtr, jint colorMode) {
RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
- proxy->setWideGamut(wideGamut);
+ proxy->setColorMode(static_cast<ColorMode>(colorMode));
}
static int android_view_ThreadedRenderer_syncAndDrawFrame(JNIEnv* env, jobject clazz,
@@ -659,7 +658,7 @@ static const JNINativeMethod gMethods[] = {
(void*)android_view_ThreadedRenderer_setProcessStatsBuffer},
{"nGetRenderThreadTid", "(J)I", (void*)android_view_ThreadedRenderer_getRenderThreadTid},
{"nCreateRootRenderNode", "()J", (void*)android_view_ThreadedRenderer_createRootRenderNode},
- {"nCreateProxy", "(ZZJ)J", (void*)android_view_ThreadedRenderer_createProxy},
+ {"nCreateProxy", "(ZJ)J", (void*)android_view_ThreadedRenderer_createProxy},
{"nDeleteProxy", "(J)V", (void*)android_view_ThreadedRenderer_deleteProxy},
{"nLoadSystemProperties", "(J)Z",
(void*)android_view_ThreadedRenderer_loadSystemProperties},
@@ -671,7 +670,7 @@ static const JNINativeMethod gMethods[] = {
{"nSetLightAlpha", "(JFF)V", (void*)android_view_ThreadedRenderer_setLightAlpha},
{"nSetLightGeometry", "(JFFFF)V", (void*)android_view_ThreadedRenderer_setLightGeometry},
{"nSetOpaque", "(JZ)V", (void*)android_view_ThreadedRenderer_setOpaque},
- {"nSetWideGamut", "(JZ)V", (void*)android_view_ThreadedRenderer_setWideGamut},
+ {"nSetColorMode", "(JI)V", (void*)android_view_ThreadedRenderer_setColorMode},
{"nSyncAndDrawFrame", "(J[JI)I", (void*)android_view_ThreadedRenderer_syncAndDrawFrame},
{"nDestroy", "(JJ)V", (void*)android_view_ThreadedRenderer_destroy},
{"nRegisterAnimatingRenderNode", "(JJ)V",
diff --git a/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp b/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp
index 14a297f785fc..dd0fc695c246 100644
--- a/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp
+++ b/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp
@@ -15,7 +15,7 @@
*/
#include "GLFunctorDrawable.h"
-#include <GrContext.h>
+#include <GrDirectContext.h>
#include <private/hwui/DrawGlInfo.h>
#include "FunctorDrawable.h"
#include "GrBackendSurface.h"
diff --git a/libs/hwui/pipeline/skia/LayerDrawable.cpp b/libs/hwui/pipeline/skia/LayerDrawable.cpp
index f839213e9007..f95f347cffaf 100644
--- a/libs/hwui/pipeline/skia/LayerDrawable.cpp
+++ b/libs/hwui/pipeline/skia/LayerDrawable.cpp
@@ -29,7 +29,7 @@ namespace skiapipeline {
void LayerDrawable::onDraw(SkCanvas* canvas) {
Layer* layer = mLayerUpdater->backingLayer();
if (layer) {
- DrawLayer(canvas->getGrContext(), canvas, layer, nullptr, nullptr, true);
+ DrawLayer(canvas->recordingContext(), canvas, layer, nullptr, nullptr, true);
}
}
@@ -67,8 +67,12 @@ static bool shouldFilterRect(const SkMatrix& matrix, const SkRect& srcRect, cons
isIntegerAligned(dstDevRect.y()));
}
-bool LayerDrawable::DrawLayer(GrContext* context, SkCanvas* canvas, Layer* layer,
- const SkRect* srcRect, const SkRect* dstRect,
+// TODO: Context arg probably doesn't belong here – do debug check at callsite instead.
+bool LayerDrawable::DrawLayer(GrRecordingContext* context,
+ SkCanvas* canvas,
+ Layer* layer,
+ const SkRect* srcRect,
+ const SkRect* dstRect,
bool useLayerTransform) {
if (context == nullptr) {
SkDEBUGF(("Attempting to draw LayerDrawable into an unsupported surface"));
diff --git a/libs/hwui/pipeline/skia/LayerDrawable.h b/libs/hwui/pipeline/skia/LayerDrawable.h
index 7cd515ae9fcb..ffbb480023ac 100644
--- a/libs/hwui/pipeline/skia/LayerDrawable.h
+++ b/libs/hwui/pipeline/skia/LayerDrawable.h
@@ -32,8 +32,12 @@ class LayerDrawable : public SkDrawable {
public:
explicit LayerDrawable(DeferredLayerUpdater* layerUpdater) : mLayerUpdater(layerUpdater) {}
- static bool DrawLayer(GrContext* context, SkCanvas* canvas, Layer* layer, const SkRect* srcRect,
- const SkRect* dstRect, bool useLayerTransform);
+ static bool DrawLayer(GrRecordingContext* context,
+ SkCanvas* canvas,
+ Layer* layer,
+ const SkRect* srcRect,
+ const SkRect* dstRect,
+ bool useLayerTransform);
protected:
virtual SkRect onGetBounds() override {
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
index 24a6228242a5..389fe7eed7c7 100644
--- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
@@ -87,6 +87,8 @@ bool SkiaOpenGLPipeline::draw(const Frame& frame, const SkRect& screenDirty, con
// Note: The default preference of pixel format is RGBA_8888, when other
// pixel format is available, we should branch out and do more check.
fboInfo.fFormat = GL_RGBA8;
+ } else if (colorType == kRGBA_1010102_SkColorType) {
+ fboInfo.fFormat = GL_RGB10_A2;
} else {
LOG_ALWAYS_FATAL("Unsupported color type.");
}
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.cpp b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
index 89a1c713ef62..6dd36981e8aa 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
@@ -35,6 +35,7 @@
#include "VectorDrawable.h"
#include "thread/CommonPool.h"
#include "tools/SkSharingProc.h"
+#include "utils/Color.h"
#include "utils/String8.h"
#include "utils/TraceUtils.h"
@@ -587,14 +588,23 @@ void SkiaPipeline::dumpResourceCacheUsage() const {
void SkiaPipeline::setSurfaceColorProperties(ColorMode colorMode) {
mColorMode = colorMode;
- if (colorMode == ColorMode::SRGB) {
- mSurfaceColorType = SkColorType::kN32_SkColorType;
- mSurfaceColorSpace = SkColorSpace::MakeSRGB();
- } else if (colorMode == ColorMode::WideColorGamut) {
- mSurfaceColorType = DeviceInfo::get()->getWideColorType();
- mSurfaceColorSpace = DeviceInfo::get()->getWideColorSpace();
- } else {
- LOG_ALWAYS_FATAL("Unreachable: unsupported color mode.");
+ switch (colorMode) {
+ case ColorMode::Default:
+ mSurfaceColorType = SkColorType::kN32_SkColorType;
+ mSurfaceColorSpace = SkColorSpace::MakeSRGB();
+ break;
+ case ColorMode::WideColorGamut:
+ mSurfaceColorType = DeviceInfo::get()->getWideColorType();
+ mSurfaceColorSpace = DeviceInfo::get()->getWideColorSpace();
+ break;
+ case ColorMode::Hdr:
+ mSurfaceColorType = SkColorType::kRGBA_F16_SkColorType;
+ mSurfaceColorSpace = SkColorSpace::MakeRGB(GetPQSkTransferFunction(), SkNamedGamut::kRec2020);
+ break;
+ case ColorMode::Hdr10:
+ mSurfaceColorType = SkColorType::kRGBA_1010102_SkColorType;
+ mSurfaceColorSpace = SkColorSpace::MakeRGB(GetPQSkTransferFunction(), SkNamedGamut::kRec2020);
+ break;
}
}
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.h b/libs/hwui/pipeline/skia/SkiaPipeline.h
index 8341164edc19..100bfb6b159a 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.h
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.h
@@ -50,7 +50,7 @@ public:
bool createOrUpdateLayer(RenderNode* node, const DamageAccumulator& damageAccumulator,
ErrorHandler* errorHandler) override;
- void setSurfaceColorProperties(renderthread::ColorMode colorMode) override;
+ void setSurfaceColorProperties(ColorMode colorMode) override;
SkColorType getSurfaceColorType() const override { return mSurfaceColorType; }
sk_sp<SkColorSpace> getSurfaceColorSpace() override { return mSurfaceColorSpace; }
@@ -76,7 +76,7 @@ protected:
renderthread::RenderThread& mRenderThread;
- renderthread::ColorMode mColorMode = renderthread::ColorMode::SRGB;
+ ColorMode mColorMode = ColorMode::Default;
SkColorType mSurfaceColorType;
sk_sp<SkColorSpace> mSurfaceColorSpace;
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index a362bd220936..13d544c68e95 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -174,7 +174,10 @@ void CanvasContext::setSurface(ANativeWindow* window, bool enableTimeout) {
} else {
mNativeSurface = nullptr;
}
+ setupPipelineSurface();
+}
+void CanvasContext::setupPipelineSurface() {
bool hasSurface = mRenderPipeline->setSurface(
mNativeSurface ? mNativeSurface->getNativeWindow() : nullptr, mSwapBehavior);
@@ -184,7 +187,7 @@ void CanvasContext::setSurface(ANativeWindow* window, bool enableTimeout) {
mFrameNumber = -1;
- if (window != nullptr && hasSurface) {
+ if (mNativeSurface != nullptr && hasSurface) {
mHaveNewSurface = true;
mSwapHistory.clear();
// Enable frame stats after the surface has been bound to the appropriate graphics API.
@@ -239,9 +242,9 @@ void CanvasContext::setOpaque(bool opaque) {
mOpaque = opaque;
}
-void CanvasContext::setWideGamut(bool wideGamut) {
- ColorMode colorMode = wideGamut ? ColorMode::WideColorGamut : ColorMode::SRGB;
- mRenderPipeline->setSurfaceColorProperties(colorMode);
+void CanvasContext::setColorMode(ColorMode mode) {
+ mRenderPipeline->setSurfaceColorProperties(mode);
+ setupPipelineSurface();
}
bool CanvasContext::makeCurrent() {
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index 0306eeccc5d4..cba710f01063 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -30,6 +30,7 @@
#include "renderthread/RenderTask.h"
#include "renderthread/RenderThread.h"
#include "utils/RingBuffer.h"
+#include "ColorMode.h"
#include <SkBitmap.h>
#include <SkRect.h>
@@ -119,7 +120,7 @@ public:
void setLightAlpha(uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha);
void setLightGeometry(const Vector3& lightCenter, float lightRadius);
void setOpaque(bool opaque);
- void setWideGamut(bool wideGamut);
+ void setColorMode(ColorMode mode);
bool makeCurrent();
void prepareTree(TreeInfo& info, int64_t* uiFrameInfo, int64_t syncQueued, RenderNode* target);
void draw();
@@ -211,6 +212,7 @@ private:
bool isSwapChainStuffed();
bool surfaceRequiresRedraw();
void setPresentTime();
+ void setupPipelineSurface();
SkRect computeDirtyRect(const Frame& frame, SkRect* dirty);
diff --git a/libs/hwui/renderthread/EglManager.cpp b/libs/hwui/renderthread/EglManager.cpp
index c7013531c07f..2a8aa8c3e5b7 100644
--- a/libs/hwui/renderthread/EglManager.cpp
+++ b/libs/hwui/renderthread/EglManager.cpp
@@ -76,6 +76,7 @@ static struct {
bool glColorSpace = false;
bool scRGB = false;
bool displayP3 = false;
+ bool hdr = false;
bool contextPriority = false;
bool surfacelessContext = false;
bool nativeFenceSync = false;
@@ -86,7 +87,8 @@ static struct {
EglManager::EglManager()
: mEglDisplay(EGL_NO_DISPLAY)
, mEglConfig(nullptr)
- , mEglConfigWideGamut(nullptr)
+ , mEglConfigF16(nullptr)
+ , mEglConfig1010102(nullptr)
, mEglContext(EGL_NO_CONTEXT)
, mPBufferSurface(EGL_NO_SURFACE)
, mCurrentSurface(EGL_NO_SURFACE)
@@ -143,8 +145,7 @@ void EglManager::initialize() {
} else {
LOG_ALWAYS_FATAL("Unsupported wide color space.");
}
- mHasWideColorGamutSupport = EglExtensions.glColorSpace && hasWideColorSpaceExtension &&
- mEglConfigWideGamut != EGL_NO_CONFIG_KHR;
+ mHasWideColorGamutSupport = EglExtensions.glColorSpace && hasWideColorSpaceExtension;
}
EGLConfig EglManager::load8BitsConfig(EGLDisplay display, EglManager::SwapBehavior swapBehavior) {
@@ -177,6 +178,35 @@ EGLConfig EglManager::load8BitsConfig(EGLDisplay display, EglManager::SwapBehavi
return config;
}
+EGLConfig EglManager::load1010102Config(EGLDisplay display, SwapBehavior swapBehavior) {
+ EGLint eglSwapBehavior =
+ (swapBehavior == SwapBehavior::Preserved) ? EGL_SWAP_BEHAVIOR_PRESERVED_BIT : 0;
+ // If we reached this point, we have a valid swap behavior
+ EGLint attribs[] = {EGL_RENDERABLE_TYPE,
+ EGL_OPENGL_ES2_BIT,
+ EGL_RED_SIZE,
+ 10,
+ EGL_GREEN_SIZE,
+ 10,
+ EGL_BLUE_SIZE,
+ 10,
+ EGL_ALPHA_SIZE,
+ 2,
+ EGL_DEPTH_SIZE,
+ 0,
+ EGL_STENCIL_SIZE,
+ STENCIL_BUFFER_SIZE,
+ EGL_SURFACE_TYPE,
+ EGL_WINDOW_BIT | eglSwapBehavior,
+ EGL_NONE};
+ EGLConfig config = EGL_NO_CONFIG_KHR;
+ EGLint numConfigs = 1;
+ if (!eglChooseConfig(display, attribs, &config, numConfigs, &numConfigs) || numConfigs != 1) {
+ return EGL_NO_CONFIG_KHR;
+ }
+ return config;
+}
+
EGLConfig EglManager::loadFP16Config(EGLDisplay display, SwapBehavior swapBehavior) {
EGLint eglSwapBehavior =
(swapBehavior == SwapBehavior::Preserved) ? EGL_SWAP_BEHAVIOR_PRESERVED_BIT : 0;
@@ -230,6 +260,7 @@ void EglManager::initExtensions() {
EglExtensions.pixelFormatFloat = extensions.has("EGL_EXT_pixel_format_float");
EglExtensions.scRGB = extensions.has("EGL_EXT_gl_colorspace_scrgb");
EglExtensions.displayP3 = extensions.has("EGL_EXT_gl_colorspace_display_p3_passthrough");
+ EglExtensions.hdr = extensions.has("EGL_EXT_gl_colorspace_bt2020_pq");
EglExtensions.contextPriority = extensions.has("EGL_IMG_context_priority");
EglExtensions.surfacelessContext = extensions.has("EGL_KHR_surfaceless_context");
EglExtensions.fenceSync = extensions.has("EGL_KHR_fence_sync");
@@ -260,18 +291,20 @@ void EglManager::loadConfigs() {
LOG_ALWAYS_FATAL("Failed to choose config, error = %s", eglErrorString());
}
}
- SkColorType wideColorType = DeviceInfo::get()->getWideColorType();
// When we reach this point, we have a valid swap behavior
- if (wideColorType == SkColorType::kRGBA_F16_SkColorType && EglExtensions.pixelFormatFloat) {
- mEglConfigWideGamut = loadFP16Config(mEglDisplay, mSwapBehavior);
- if (mEglConfigWideGamut == EGL_NO_CONFIG_KHR) {
+ if (EglExtensions.pixelFormatFloat) {
+ mEglConfigF16 = loadFP16Config(mEglDisplay, mSwapBehavior);
+ if (mEglConfigF16 == EGL_NO_CONFIG_KHR) {
ALOGE("Device claims wide gamut support, cannot find matching config, error = %s",
eglErrorString());
EglExtensions.pixelFormatFloat = false;
}
- } else if (wideColorType == SkColorType::kN32_SkColorType) {
- mEglConfigWideGamut = load8BitsConfig(mEglDisplay, mSwapBehavior);
+ }
+ mEglConfig1010102 = load1010102Config(mEglDisplay, mSwapBehavior);
+ if (mEglConfig1010102 == EGL_NO_CONFIG_KHR) {
+ ALOGW("Failed to initialize 101010-2 format, error = %s",
+ eglErrorString());
}
}
@@ -311,8 +344,9 @@ Result<EGLSurface, EGLint> EglManager::createSurface(EGLNativeWindowType window,
sk_sp<SkColorSpace> colorSpace) {
LOG_ALWAYS_FATAL_IF(!hasEglContext(), "Not initialized");
- bool wideColorGamut = colorMode == ColorMode::WideColorGamut && mHasWideColorGamutSupport &&
- EglExtensions.noConfigContext;
+ if (!mHasWideColorGamutSupport || !EglExtensions.noConfigContext) {
+ colorMode = ColorMode::Default;
+ }
// The color space we want to use depends on whether linear blending is turned
// on and whether the app has requested wide color gamut rendering. When wide
@@ -338,26 +372,47 @@ Result<EGLSurface, EGLint> EglManager::createSurface(EGLNativeWindowType window,
// list is considered empty if the first entry is EGL_NONE
EGLint attribs[] = {EGL_NONE, EGL_NONE, EGL_NONE};
+ EGLConfig config = mEglConfig;
+ if (DeviceInfo::get()->getWideColorType() == kRGBA_F16_SkColorType) {
+ if (mEglConfigF16 == EGL_NO_CONFIG_KHR) {
+ colorMode = ColorMode::Default;
+ } else {
+ config = mEglConfigF16;
+ }
+ }
if (EglExtensions.glColorSpace) {
attribs[0] = EGL_GL_COLORSPACE_KHR;
- if (wideColorGamut) {
- skcms_Matrix3x3 colorGamut;
- LOG_ALWAYS_FATAL_IF(!colorSpace->toXYZD50(&colorGamut),
- "Could not get gamut matrix from color space");
- if (memcmp(&colorGamut, &SkNamedGamut::kDisplayP3, sizeof(colorGamut)) == 0) {
- attribs[1] = EGL_GL_COLORSPACE_DISPLAY_P3_PASSTHROUGH_EXT;
- } else if (memcmp(&colorGamut, &SkNamedGamut::kSRGB, sizeof(colorGamut)) == 0) {
- attribs[1] = EGL_GL_COLORSPACE_SCRGB_EXT;
- } else {
- LOG_ALWAYS_FATAL("Unreachable: unsupported wide color space.");
+ switch (colorMode) {
+ case ColorMode::Default:
+ attribs[1] = EGL_GL_COLORSPACE_LINEAR_KHR;
+ break;
+ case ColorMode::WideColorGamut: {
+ skcms_Matrix3x3 colorGamut;
+ LOG_ALWAYS_FATAL_IF(!colorSpace->toXYZD50(&colorGamut),
+ "Could not get gamut matrix from color space");
+ if (memcmp(&colorGamut, &SkNamedGamut::kDisplayP3, sizeof(colorGamut)) == 0) {
+ attribs[1] = EGL_GL_COLORSPACE_DISPLAY_P3_PASSTHROUGH_EXT;
+ } else if (memcmp(&colorGamut, &SkNamedGamut::kSRGB, sizeof(colorGamut)) == 0) {
+ attribs[1] = EGL_GL_COLORSPACE_SCRGB_EXT;
+ } else if (memcmp(&colorGamut, &SkNamedGamut::kRec2020, sizeof(colorGamut)) == 0) {
+ attribs[1] = EGL_GL_COLORSPACE_BT2020_PQ_EXT;
+ } else {
+ LOG_ALWAYS_FATAL("Unreachable: unsupported wide color space.");
+ }
+ break;
}
- } else {
- attribs[1] = EGL_GL_COLORSPACE_LINEAR_KHR;
+ case ColorMode::Hdr:
+ config = mEglConfigF16;
+ attribs[1] = EGL_GL_COLORSPACE_BT2020_PQ_EXT;
+ break;
+ case ColorMode::Hdr10:
+ config = mEglConfig1010102;
+ attribs[1] = EGL_GL_COLORSPACE_BT2020_PQ_EXT;
+ break;
}
}
- EGLSurface surface = eglCreateWindowSurface(
- mEglDisplay, wideColorGamut ? mEglConfigWideGamut : mEglConfig, window, attribs);
+ EGLSurface surface = eglCreateWindowSurface(mEglDisplay, config, window, attribs);
if (surface == EGL_NO_SURFACE) {
return Error<EGLint>{eglGetError()};
}
diff --git a/libs/hwui/renderthread/EglManager.h b/libs/hwui/renderthread/EglManager.h
index f67fb31db951..69f3ed014c53 100644
--- a/libs/hwui/renderthread/EglManager.h
+++ b/libs/hwui/renderthread/EglManager.h
@@ -88,6 +88,7 @@ private:
static EGLConfig load8BitsConfig(EGLDisplay display, SwapBehavior swapBehavior);
static EGLConfig loadFP16Config(EGLDisplay display, SwapBehavior swapBehavior);
+ static EGLConfig load1010102Config(EGLDisplay display, SwapBehavior swapBehavior);
void initExtensions();
void createPBufferSurface();
@@ -97,7 +98,8 @@ private:
EGLDisplay mEglDisplay;
EGLConfig mEglConfig;
- EGLConfig mEglConfigWideGamut;
+ EGLConfig mEglConfigF16;
+ EGLConfig mEglConfig1010102;
EGLContext mEglContext;
EGLSurface mPBufferSurface;
EGLSurface mCurrentSurface;
diff --git a/libs/hwui/renderthread/IRenderPipeline.h b/libs/hwui/renderthread/IRenderPipeline.h
index c3c22869a42f..a04738d6a6f0 100644
--- a/libs/hwui/renderthread/IRenderPipeline.h
+++ b/libs/hwui/renderthread/IRenderPipeline.h
@@ -22,6 +22,7 @@
#include "Lighting.h"
#include "SwapBehavior.h"
#include "hwui/Bitmap.h"
+#include "ColorMode.h"
#include <SkRect.h>
#include <utils/RefBase.h>
@@ -42,16 +43,6 @@ namespace renderthread {
enum class MakeCurrentResult { AlreadyCurrent, Failed, Succeeded };
-enum class ColorMode {
- // SRGB means HWUI will produce buffer in SRGB color space.
- SRGB,
- // WideColorGamut means HWUI would support rendering scRGB non-linear into
- // a signed buffer with enough range to support the wide color gamut of the
- // display.
- WideColorGamut,
- // Hdr
-};
-
class Frame;
class IRenderPipeline {
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index b764f74bf116..aad0cca80cdc 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -109,8 +109,8 @@ void RenderProxy::setOpaque(bool opaque) {
mRenderThread.queue().post([=]() { mContext->setOpaque(opaque); });
}
-void RenderProxy::setWideGamut(bool wideGamut) {
- mRenderThread.queue().post([=]() { mContext->setWideGamut(wideGamut); });
+void RenderProxy::setColorMode(ColorMode mode) {
+ mRenderThread.queue().post([=]() { mContext->setColorMode(mode); });
}
int64_t* RenderProxy::frameInfo() {
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
index 16eabadc064c..33dabc9895b1 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -24,6 +24,7 @@
#include "../FrameMetricsObserver.h"
#include "../IContextFactory.h"
+#include "ColorMode.h"
#include "DrawFrameTask.h"
#include "SwapBehavior.h"
#include "hwui/Bitmap.h"
@@ -77,7 +78,7 @@ public:
void setLightAlpha(uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha);
void setLightGeometry(const Vector3& lightCenter, float lightRadius);
void setOpaque(bool opaque);
- void setWideGamut(bool wideGamut);
+ void setColorMode(ColorMode mode);
int64_t* frameInfo();
int syncAndDrawFrame();
void destroy();
diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp
index 206b58f62ea7..bea6121905a5 100644
--- a/libs/hwui/renderthread/RenderThread.cpp
+++ b/libs/hwui/renderthread/RenderThread.cpp
@@ -162,6 +162,7 @@ void RenderThread::initializeChoreographer() {
}
void RenderThread::initThreadLocals() {
+ HardwareBitmapUploader::initialize();
setupFrameInterval();
initializeChoreographer();
mEglManager = new EglManager();
@@ -190,7 +191,7 @@ void RenderThread::requireGlContext() {
auto glesVersion = reinterpret_cast<const char*>(glGetString(GL_VERSION));
auto size = glesVersion ? strlen(glesVersion) : -1;
cacheManager().configureContext(&options, glesVersion, size);
- sk_sp<GrContext> grContext(GrContext::MakeGL(std::move(glInterface), options));
+ sk_sp<GrDirectContext> grContext(GrDirectContext::MakeGL(std::move(glInterface), options));
LOG_ALWAYS_FATAL_IF(!grContext.get());
setGrContext(grContext);
}
@@ -204,7 +205,7 @@ void RenderThread::requireVkContext() {
initGrContextOptions(options);
auto vkDriverVersion = mVkManager->getDriverVersion();
cacheManager().configureContext(&options, &vkDriverVersion, sizeof(vkDriverVersion));
- sk_sp<GrContext> grContext = mVkManager->createContext(options);
+ sk_sp<GrDirectContext> grContext = mVkManager->createContext(options);
LOG_ALWAYS_FATAL_IF(!grContext.get());
setGrContext(grContext);
}
@@ -263,7 +264,7 @@ Readback& RenderThread::readback() {
return *mReadback;
}
-void RenderThread::setGrContext(sk_sp<GrContext> context) {
+void RenderThread::setGrContext(sk_sp<GrDirectContext> context) {
mCacheManager->reset(context);
if (mGrContext) {
mRenderState->onContextDestroyed();
@@ -390,10 +391,12 @@ void RenderThread::preload() {
if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaGL) {
std::thread eglInitThread([]() { eglGetDisplay(EGL_DEFAULT_DISPLAY); });
eglInitThread.detach();
- } else {
- requireVkContext();
}
- HardwareBitmapUploader::initialize();
+ // TODO: uncomment only after http://b/135536511 is fixed.
+ // else {
+ // uint32_t apiVersion;
+ // vkEnumerateInstanceVersion(&apiVersion);
+ //}
}
} /* namespace renderthread */
diff --git a/libs/hwui/renderthread/RenderThread.h b/libs/hwui/renderthread/RenderThread.h
index 2c295bcd8105..b8ce55650516 100644
--- a/libs/hwui/renderthread/RenderThread.h
+++ b/libs/hwui/renderthread/RenderThread.h
@@ -17,7 +17,7 @@
#ifndef RENDERTHREAD_H_
#define RENDERTHREAD_H_
-#include <GrContext.h>
+#include <GrDirectContext.h>
#include <SkBitmap.h>
#include <apex/choreographer.h>
#include <cutils/compiler.h>
@@ -106,8 +106,8 @@ public:
ProfileDataContainer& globalProfileData() { return mGlobalProfileData; }
Readback& readback();
- GrContext* getGrContext() const { return mGrContext.get(); }
- void setGrContext(sk_sp<GrContext> cxt);
+ GrDirectContext* getGrContext() const { return mGrContext.get(); }
+ void setGrContext(sk_sp<GrDirectContext> cxt);
CacheManager& cacheManager() { return *mCacheManager; }
VulkanManager& vulkanManager() { return *mVkManager; }
@@ -186,7 +186,7 @@ private:
ProfileDataContainer mGlobalProfileData;
Readback* mReadback = nullptr;
- sk_sp<GrContext> mGrContext;
+ sk_sp<GrDirectContext> mGrContext;
CacheManager* mCacheManager;
VulkanManager* mVkManager;
};
diff --git a/libs/hwui/renderthread/VulkanManager.cpp b/libs/hwui/renderthread/VulkanManager.cpp
index 3cb16074dd5e..249936eb485e 100644
--- a/libs/hwui/renderthread/VulkanManager.cpp
+++ b/libs/hwui/renderthread/VulkanManager.cpp
@@ -20,7 +20,7 @@
#include <EGL/eglext.h>
#include <GrBackendSemaphore.h>
#include <GrBackendSurface.h>
-#include <GrContext.h>
+#include <GrDirectContext.h>
#include <GrTypes.h>
#include <android/sync.h>
#include <ui/FatVector.h>
@@ -369,7 +369,7 @@ void VulkanManager::initialize() {
}
}
-sk_sp<GrContext> VulkanManager::createContext(const GrContextOptions& options) {
+sk_sp<GrDirectContext> VulkanManager::createContext(const GrContextOptions& options) {
auto getProc = [](const char* proc_name, VkInstance instance, VkDevice device) {
if (device != VK_NULL_HANDLE) {
return vkGetDeviceProcAddr(device, proc_name);
@@ -388,7 +388,7 @@ sk_sp<GrContext> VulkanManager::createContext(const GrContextOptions& options) {
backendContext.fDeviceFeatures2 = &mPhysicalDeviceFeatures2;
backendContext.fGetProc = std::move(getProc);
- return GrContext::MakeVulkan(backendContext, options);
+ return GrDirectContext::MakeVulkan(backendContext, options);
}
VkFunctorInitParams VulkanManager::getVkFunctorInitParams() const {
@@ -562,9 +562,11 @@ void VulkanManager::destroySurface(VulkanSurface* surface) {
delete surface;
}
-VulkanSurface* VulkanManager::createSurface(ANativeWindow* window, ColorMode colorMode,
+VulkanSurface* VulkanManager::createSurface(ANativeWindow* window,
+ ColorMode colorMode,
sk_sp<SkColorSpace> surfaceColorSpace,
- SkColorType surfaceColorType, GrContext* grContext,
+ SkColorType surfaceColorType,
+ GrDirectContext* grContext,
uint32_t extraBuffers) {
LOG_ALWAYS_FATAL_IF(!hasVkContext(), "Not initialized");
if (!window) {
@@ -575,7 +577,7 @@ VulkanSurface* VulkanManager::createSurface(ANativeWindow* window, ColorMode col
*this, extraBuffers);
}
-status_t VulkanManager::fenceWait(int fence, GrContext* grContext) {
+status_t VulkanManager::fenceWait(int fence, GrDirectContext* grContext) {
if (!hasVkContext()) {
ALOGE("VulkanManager::fenceWait: VkDevice not initialized");
return INVALID_OPERATION;
@@ -623,7 +625,7 @@ status_t VulkanManager::fenceWait(int fence, GrContext* grContext) {
return OK;
}
-status_t VulkanManager::createReleaseFence(int* nativeFence, GrContext* grContext) {
+status_t VulkanManager::createReleaseFence(int* nativeFence, GrDirectContext* grContext) {
*nativeFence = -1;
if (!hasVkContext()) {
ALOGE("VulkanManager::createReleaseFence: VkDevice not initialized");
diff --git a/libs/hwui/renderthread/VulkanManager.h b/libs/hwui/renderthread/VulkanManager.h
index 8b19f13fdfb9..3f2df8d75d89 100644
--- a/libs/hwui/renderthread/VulkanManager.h
+++ b/libs/hwui/renderthread/VulkanManager.h
@@ -57,9 +57,11 @@ public:
bool hasVkContext() { return mDevice != VK_NULL_HANDLE; }
// Create and destroy functions for wrapping an ANativeWindow in a VulkanSurface
- VulkanSurface* createSurface(ANativeWindow* window, ColorMode colorMode,
+ VulkanSurface* createSurface(ANativeWindow* window,
+ ColorMode colorMode,
sk_sp<SkColorSpace> surfaceColorSpace,
- SkColorType surfaceColorType, GrContext* grContext,
+ SkColorType surfaceColorType,
+ GrDirectContext* grContext,
uint32_t extraBuffers);
void destroySurface(VulkanSurface* surface);
@@ -70,18 +72,18 @@ public:
void destroy();
// Inserts a wait on fence command into the Vulkan command buffer.
- status_t fenceWait(int fence, GrContext* grContext);
+ status_t fenceWait(int fence, GrDirectContext* grContext);
// Creates a fence that is signaled when all the pending Vulkan commands are finished on the
// GPU.
- status_t createReleaseFence(int* nativeFence, GrContext* grContext);
+ status_t createReleaseFence(int* nativeFence, GrDirectContext* grContext);
// Returned pointers are owned by VulkanManager.
// An instance of VkFunctorInitParams returned from getVkFunctorInitParams refers to
// the internal state of VulkanManager: VulkanManager must be alive to use the returned value.
VkFunctorInitParams getVkFunctorInitParams() const;
- sk_sp<GrContext> createContext(const GrContextOptions& options);
+ sk_sp<GrDirectContext> createContext(const GrContextOptions& options);
uint32_t getDriverVersion() const { return mDriverVersion; }
diff --git a/libs/hwui/tests/unit/CacheManagerTests.cpp b/libs/hwui/tests/unit/CacheManagerTests.cpp
index a4d7b825520d..edd3e4e4f4d4 100644
--- a/libs/hwui/tests/unit/CacheManagerTests.cpp
+++ b/libs/hwui/tests/unit/CacheManagerTests.cpp
@@ -26,7 +26,7 @@ using namespace android;
using namespace android::uirenderer;
using namespace android::uirenderer::renderthread;
-static size_t getCacheUsage(GrContext* grContext) {
+static size_t getCacheUsage(GrDirectContext* grContext) {
size_t cacheUsage;
grContext->getResourceCacheUsage(nullptr, &cacheUsage);
return cacheUsage;
@@ -35,7 +35,7 @@ static size_t getCacheUsage(GrContext* grContext) {
RENDERTHREAD_SKIA_PIPELINE_TEST(CacheManager, trimMemory) {
int32_t width = DeviceInfo::get()->getWidth();
int32_t height = DeviceInfo::get()->getHeight();
- GrContext* grContext = renderThread.getGrContext();
+ GrDirectContext* grContext = renderThread.getGrContext();
ASSERT_TRUE(grContext != nullptr);
// create pairs of offscreen render targets and images until we exceed the
diff --git a/libs/hwui/utils/Color.cpp b/libs/hwui/utils/Color.cpp
index ca1bf690cfd0..eff34a83af1b 100644
--- a/libs/hwui/utils/Color.cpp
+++ b/libs/hwui/utils/Color.cpp
@@ -344,5 +344,27 @@ SkColor LabToSRGB(const Lab& lab, SkAlpha alpha) {
static_cast<uint8_t>(rgb.b * 255));
}
+// Note that SkColorSpace doesn't have the notion of an unspecified SDR white
+// level.
+static constexpr float kDefaultSDRWhiteLevel = 150.f;
+
+skcms_TransferFunction GetPQSkTransferFunction(float sdr_white_level) {
+ if (sdr_white_level <= 0.f) {
+ sdr_white_level = kDefaultSDRWhiteLevel;
+ }
+ // The generic PQ transfer function produces normalized luminance values i.e.
+ // the range 0-1 represents 0-10000 nits for the reference display, but we
+ // want to map 1.0 to |sdr_white_level| nits so we need to scale accordingly.
+ const double w = 10000. / sdr_white_level;
+ // Distribute scaling factor W by scaling A and B with X ^ (1/F):
+ // ((A + Bx^C) / (D + Ex^C))^F * W = ((A + Bx^C) / (D + Ex^C) * W^(1/F))^F
+ // See https://crbug.com/1058580#c32 for discussion.
+ skcms_TransferFunction fn = SkNamedTransferFn::kPQ;
+ const double ws = pow(w, 1. / fn.f);
+ fn.a = ws * fn.a;
+ fn.b = ws * fn.b;
+ return fn;
+}
+
} // namespace uirenderer
} // namespace android
diff --git a/libs/hwui/utils/Color.h b/libs/hwui/utils/Color.h
index 71ed68371a9a..1654072fd264 100644
--- a/libs/hwui/utils/Color.h
+++ b/libs/hwui/utils/Color.h
@@ -126,6 +126,7 @@ struct Lab {
Lab sRGBToLab(SkColor color);
SkColor LabToSRGB(const Lab& lab, SkAlpha alpha);
+skcms_TransferFunction GetPQSkTransferFunction(float sdr_white_level = 0.f);
} /* namespace uirenderer */
} /* namespace android */
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 3ac71b2cff1d..928fb62e07f0 100755
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -3801,7 +3801,7 @@ public class AudioManager {
final IAudioService service = getService();
try {
service.unregisterAudioPolicyAsync(policy.cb());
- policy.setRegistration(null);
+ policy.reset();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -3823,7 +3823,7 @@ public class AudioManager {
try {
policy.invalidateCaptorsAndInjectors();
service.unregisterAudioPolicy(policy.cb());
- policy.setRegistration(null);
+ policy.reset();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java
index 4d26b8d3f7af..c9cdbb0ed277 100644
--- a/media/java/android/media/AudioRecord.java
+++ b/media/java/android/media/AudioRecord.java
@@ -487,6 +487,11 @@ public class AudioRecord implements AudioRouting, MicrophoneDirection,
}
}
+ /** @hide */
+ public AudioAttributes getAudioAttributes() {
+ return mAudioAttributes;
+ }
+
/**
* Builder class for {@link AudioRecord} objects.
* Use this class to configure and create an <code>AudioRecord</code> instance. By setting the
diff --git a/media/java/android/media/ExifInterface.java b/media/java/android/media/ExifInterface.java
index 4a6724a09c1e..57e8e438d592 100644
--- a/media/java/android/media/ExifInterface.java
+++ b/media/java/android/media/ExifInterface.java
@@ -70,16 +70,17 @@ import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.TimeZone;
+import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.zip.CRC32;
/**
- * This is a class for reading and writing Exif tags in a JPEG file or a RAW image file.
+ * This is a class for reading and writing Exif tags in various image file formats.
* <p>
- * Supported formats are: JPEG, DNG, CR2, NEF, NRW, ARW, RW2, ORF, PEF, SRW, RAF and HEIF.
+ * Supported for reading: JPEG, PNG, WebP, HEIF, DNG, CR2, NEF, NRW, ARW, RW2, ORF, PEF, SRW, RAF.
* <p>
- * Attribute mutation is supported for JPEG image files.
+ * Supported for writing: JPEG, PNG, WebP.
* <p>
* Note: It is recommended to use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a>
* <a href="{@docRoot}reference/androidx/exifinterface/media/ExifInterface.html">ExifInterface
@@ -585,6 +586,15 @@ public class ExifInterface {
private static final int WEBP_FILE_SIZE_BYTE_LENGTH = 4;
private static final byte[] WEBP_CHUNK_TYPE_EXIF = new byte[]{(byte) 0x45, (byte) 0x58,
(byte) 0x49, (byte) 0x46};
+ private static final byte[] WEBP_VP8_SIGNATURE = new byte[]{(byte) 0x9d, (byte) 0x01,
+ (byte) 0x2a};
+ private static final byte WEBP_VP8L_SIGNATURE = (byte) 0x2f;
+ private static final byte[] WEBP_CHUNK_TYPE_VP8X = "VP8X".getBytes(Charset.defaultCharset());
+ private static final byte[] WEBP_CHUNK_TYPE_VP8L = "VP8L".getBytes(Charset.defaultCharset());
+ private static final byte[] WEBP_CHUNK_TYPE_VP8 = "VP8 ".getBytes(Charset.defaultCharset());
+ private static final byte[] WEBP_CHUNK_TYPE_ANIM = "ANIM".getBytes(Charset.defaultCharset());
+ private static final byte[] WEBP_CHUNK_TYPE_ANMF = "ANMF".getBytes(Charset.defaultCharset());
+ private static final int WEBP_CHUNK_TYPE_VP8X_DEFAULT_LENGTH = 10;
private static final int WEBP_CHUNK_TYPE_BYTE_LENGTH = 4;
private static final int WEBP_CHUNK_SIZE_BYTE_LENGTH = 4;
@@ -1609,7 +1619,7 @@ public class ExifInterface {
}
/**
- * Returns whether ExifInterface currently supports parsing data from the specified mime type
+ * Returns whether ExifInterface currently supports reading data from the specified mime type
* or not.
*
* @param mimeType the string value of mime type
@@ -1633,6 +1643,8 @@ public class ExifInterface {
case "image/x-fuji-raf":
case "image/heic":
case "image/heif":
+ case "image/png":
+ case "image/webp":
return true;
default:
return false;
@@ -2046,18 +2058,21 @@ public class ExifInterface {
* {@link #setAttribute(String,String)} to set all attributes to write and
* make a single call rather than multiple calls for each attribute.
* <p>
- * This method is only supported for JPEG and PNG files.
+ * This method is supported for JPEG, PNG and WebP files.
* <p class="note">
* Note: after calling this method, any attempts to obtain range information
* from {@link #getAttributeRange(String)} or {@link #getThumbnailRange()}
* will throw {@link IllegalStateException}, since the offsets may have
* changed in the newly written file.
+ * <p>
+ * For WebP format, the Exif data will be stored as an Extended File Format, and it may not be
+ * supported for older readers.
* </p>
*/
public void saveAttributes() throws IOException {
- if (!mIsSupportedFile || (mMimeType != IMAGE_TYPE_JPEG && mMimeType != IMAGE_TYPE_PNG)) {
- throw new IOException("ExifInterface only supports saving attributes on JPEG or PNG "
- + "formats.");
+ if (!isSupportedFormatForSavingAttributes()) {
+ throw new IOException("ExifInterface only supports saving attributes on JPEG, PNG, "
+ + "or WebP formats.");
}
if (mIsInputStream || (mSeekableFileDescriptor == null && mFilename == null)) {
throw new IOException(
@@ -2081,16 +2096,15 @@ public class ExifInterface {
try {
// Move the original file to temporary file.
if (mFilename != null) {
- tempFile = new File(mFilename + ".tmp");
+ String parent = originalFile.getParent();
+ String name = originalFile.getName();
+ String tempPrefix = UUID.randomUUID().toString() + "_";
+ tempFile = new File(parent, tempPrefix + name);
if (!originalFile.renameTo(tempFile)) {
throw new IOException("Couldn't rename to " + tempFile.getAbsolutePath());
}
} else if (mSeekableFileDescriptor != null) {
- if (mMimeType == IMAGE_TYPE_JPEG) {
- tempFile = File.createTempFile("temp", "jpg");
- } else if (mMimeType == IMAGE_TYPE_PNG) {
- tempFile = File.createTempFile("temp", "png");
- }
+ tempFile = File.createTempFile("temp", "tmp");
Os.lseek(mSeekableFileDescriptor, 0, OsConstants.SEEK_SET);
in = new FileInputStream(mSeekableFileDescriptor);
out = new FileOutputStream(tempFile);
@@ -2120,6 +2134,8 @@ public class ExifInterface {
saveJpegAttributes(bufferedIn, bufferedOut);
} else if (mMimeType == IMAGE_TYPE_PNG) {
savePngAttributes(bufferedIn, bufferedOut);
+ } else if (mMimeType == IMAGE_TYPE_WEBP) {
+ saveWebpAttributes(bufferedIn, bufferedOut);
}
}
} catch (Exception e) {
@@ -2601,7 +2617,6 @@ public class ExifInterface {
ByteOrderedDataInputStream signatureInputStream = null;
try {
signatureInputStream = new ByteOrderedDataInputStream(signatureCheckBytes);
- signatureInputStream.setByteOrder(ByteOrder.BIG_ENDIAN);
long chunkSize = signatureInputStream.readInt();
byte[] chunkType = new byte[4];
@@ -3392,6 +3407,9 @@ public class ExifInterface {
bytesRead += in.skipBytes(WEBP_SIGNATURE_2.length);
try {
while (true) {
+ // TODO: Check the first Chunk Type, and if it is VP8X, check if the chunks are
+ // ordered properly.
+
// Each chunk is made up of three parts:
// 1) Chunk FourCC: 4-byte concatenating four ASCII characters.
// 2) Chunk Size: 4-byte unsigned integer indicating the size of the chunk.
@@ -3417,6 +3435,9 @@ public class ExifInterface {
// Save offset values for handling thumbnail and attribute offsets.
mExifOffset = bytesRead;
readExifSegment(payload, IFD_TYPE_PRIMARY);
+
+ // Save offset values for handleThumbnailFromJfif() function
+ mExifOffset = bytesRead;
break;
} else {
// Add a single padding byte at end if chunk size is odd
@@ -3610,6 +3631,263 @@ public class ExifInterface {
copy(dataInputStream, dataOutputStream);
}
+ // A WebP file has a header and a series of chunks.
+ // The header is composed of:
+ // "RIFF" + File Size + "WEBP"
+ //
+ // The structure of the chunks can be divided largely into two categories:
+ // 1) Contains only image data,
+ // 2) Contains image data and extra data.
+ // In the first category, there is only one chunk: type "VP8" (compression with loss) or "VP8L"
+ // (lossless compression).
+ // In the second category, the first chunk will be of type "VP8X", which contains flags
+ // indicating which extra data exist in later chunks. The proceeding chunks must conform to
+ // the following order based on type (if they exist):
+ // Color Profile ("ICCP") + Animation Control Data ("ANIM") + Image Data ("VP8"/"VP8L")
+ // + Exif metadata ("EXIF") + XMP metadata ("XMP")
+ //
+ // And in order to have EXIF data, a WebP file must be of the second structure and thus follow
+ // the following rules:
+ // 1) "VP8X" chunk as the first chunk,
+ // 2) flag for EXIF inside "VP8X" chunk set to 1, and
+ // 3) contain the "EXIF" chunk in the correct order amongst other chunks.
+ //
+ // Based on these rules, this API will support three different cases depending on the contents
+ // of the original file:
+ // 1) "EXIF" chunk already exists
+ // -> replace it with the new "EXIF" chunk
+ // 2) "EXIF" chunk does not exist and the first chunk is "VP8" or "VP8L"
+ // -> add "VP8X" before the "VP8"/"VP8L" chunk (with EXIF flag set to 1), and add new
+ // "EXIF" chunk after the "VP8"/"VP8L" chunk.
+ // 3) "EXIF" chunk does not exist and the first chunk is "VP8X"
+ // -> set EXIF flag in "VP8X" chunk to 1, and add new "EXIF" chunk at the proper location.
+ //
+ // See https://developers.google.com/speed/webp/docs/riff_container for more details.
+ private void saveWebpAttributes(InputStream inputStream, OutputStream outputStream)
+ throws IOException {
+ if (DEBUG) {
+ Log.d(TAG, "saveWebpAttributes starting with (inputStream: " + inputStream
+ + ", outputStream: " + outputStream + ")");
+ }
+ ByteOrderedDataInputStream totalInputStream =
+ new ByteOrderedDataInputStream(inputStream, ByteOrder.LITTLE_ENDIAN);
+ ByteOrderedDataOutputStream totalOutputStream =
+ new ByteOrderedDataOutputStream(outputStream, ByteOrder.LITTLE_ENDIAN);
+
+ // WebP signature
+ copy(totalInputStream, totalOutputStream, WEBP_SIGNATURE_1.length);
+ // File length will be written after all the chunks have been written
+ totalInputStream.skipBytes(WEBP_FILE_SIZE_BYTE_LENGTH + WEBP_SIGNATURE_2.length);
+
+ // Create a separate byte array to calculate file length
+ ByteArrayOutputStream nonHeaderByteArrayOutputStream = null;
+ try {
+ nonHeaderByteArrayOutputStream = new ByteArrayOutputStream();
+ ByteOrderedDataOutputStream nonHeaderOutputStream =
+ new ByteOrderedDataOutputStream(nonHeaderByteArrayOutputStream,
+ ByteOrder.LITTLE_ENDIAN);
+
+ if (mExifOffset != 0) {
+ // EXIF chunk exists in the original file
+ // Tested by webp_with_exif.webp
+ int bytesRead = WEBP_SIGNATURE_1.length + WEBP_FILE_SIZE_BYTE_LENGTH
+ + WEBP_SIGNATURE_2.length;
+ copy(totalInputStream, nonHeaderOutputStream,
+ mExifOffset - bytesRead - WEBP_CHUNK_TYPE_BYTE_LENGTH
+ - WEBP_CHUNK_SIZE_BYTE_LENGTH);
+
+ // Skip input stream to the end of the EXIF chunk
+ totalInputStream.skipBytes(WEBP_CHUNK_TYPE_BYTE_LENGTH);
+ int exifChunkLength = totalInputStream.readInt();
+ totalInputStream.skipBytes(exifChunkLength);
+
+ // Write new EXIF chunk to output stream
+ int exifSize = writeExifSegment(nonHeaderOutputStream);
+ } else {
+ // EXIF chunk does not exist in the original file
+ byte[] firstChunkType = new byte[WEBP_CHUNK_TYPE_BYTE_LENGTH];
+ if (totalInputStream.read(firstChunkType) != firstChunkType.length) {
+ throw new IOException("Encountered invalid length while parsing WebP chunk "
+ + "type");
+ }
+
+ if (Arrays.equals(firstChunkType, WEBP_CHUNK_TYPE_VP8X)) {
+ // Original file already includes other extra data
+ int size = totalInputStream.readInt();
+ // WebP files have a single padding byte at the end if the chunk size is odd.
+ byte[] data = new byte[(size % 2) == 1 ? size + 1 : size];
+ totalInputStream.read(data);
+
+ // Set the EXIF flag to 1
+ data[0] = (byte) (data[0] | (1 << 3));
+
+ // Retrieve Animation flag--in order to check where EXIF data should start
+ boolean containsAnimation = ((data[0] >> 1) & 1) == 1;
+
+ // Write the original VP8X chunk
+ nonHeaderOutputStream.write(WEBP_CHUNK_TYPE_VP8X);
+ nonHeaderOutputStream.writeInt(size);
+ nonHeaderOutputStream.write(data);
+
+ // Animation control data is composed of 1 ANIM chunk and multiple ANMF
+ // chunks and since the image data (VP8/VP8L) chunks are included in the ANMF
+ // chunks, EXIF data should come after the last ANMF chunk.
+ // Also, because there is no value indicating the amount of ANMF chunks, we need
+ // to keep iterating through chunks until we either reach the end of the file or
+ // the XMP chunk (if it exists).
+ // Tested by webp_with_anim_without_exif.webp
+ if (containsAnimation) {
+ copyChunksUpToGivenChunkType(totalInputStream, nonHeaderOutputStream,
+ WEBP_CHUNK_TYPE_ANIM, null);
+
+ while (true) {
+ byte[] type = new byte[WEBP_CHUNK_TYPE_BYTE_LENGTH];
+ int read = inputStream.read(type);
+ if (!Arrays.equals(type, WEBP_CHUNK_TYPE_ANMF)) {
+ // Either we have reached EOF or the start of a non-ANMF chunk
+ writeExifSegment(nonHeaderOutputStream);
+ break;
+ }
+ copyWebPChunk(totalInputStream, nonHeaderOutputStream, type);
+ }
+ } else {
+ // Skip until we find the VP8 or VP8L chunk
+ copyChunksUpToGivenChunkType(totalInputStream, nonHeaderOutputStream,
+ WEBP_CHUNK_TYPE_VP8, WEBP_CHUNK_TYPE_VP8L);
+ writeExifSegment(nonHeaderOutputStream);
+ }
+ } else if (Arrays.equals(firstChunkType, WEBP_CHUNK_TYPE_VP8)
+ || Arrays.equals(firstChunkType, WEBP_CHUNK_TYPE_VP8L)) {
+ int size = totalInputStream.readInt();
+ int bytesToRead = size;
+ // WebP files have a single padding byte at the end if the chunk size is odd.
+ if (size % 2 == 1) {
+ bytesToRead += 1;
+ }
+
+ // Retrieve image width/height
+ int widthAndHeight = 0;
+ int width = 0;
+ int height = 0;
+ int alpha = 0;
+ // Save VP8 frame data for later
+ byte[] vp8Frame = new byte[3];
+
+ if (Arrays.equals(firstChunkType, WEBP_CHUNK_TYPE_VP8)) {
+ totalInputStream.read(vp8Frame);
+
+ // Check signature
+ byte[] vp8Signature = new byte[3];
+ if (totalInputStream.read(vp8Signature) != vp8Signature.length
+ || !Arrays.equals(WEBP_VP8_SIGNATURE, vp8Signature)) {
+ throw new IOException("Encountered error while checking VP8 "
+ + "signature");
+ }
+
+ // Retrieve image width/height
+ widthAndHeight = totalInputStream.readInt();
+ width = (widthAndHeight << 18) >> 18;
+ height = (widthAndHeight << 2) >> 18;
+ bytesToRead -= (vp8Frame.length + vp8Signature.length + 4);
+ } else if (Arrays.equals(firstChunkType, WEBP_CHUNK_TYPE_VP8L)) {
+ // Check signature
+ byte vp8lSignature = totalInputStream.readByte();
+ if (vp8lSignature != WEBP_VP8L_SIGNATURE) {
+ throw new IOException("Encountered error while checking VP8L "
+ + "signature");
+ }
+
+ // Retrieve image width/height
+ widthAndHeight = totalInputStream.readInt();
+ // VP8L stores width - 1 and height - 1 values. See "2 RIFF Header" of
+ // "WebP Lossless Bitstream Specification"
+ width = ((widthAndHeight << 18) >> 18) + 1;
+ height = ((widthAndHeight << 4) >> 18) + 1;
+ // Retrieve alpha bit
+ alpha = widthAndHeight & (1 << 3);
+ bytesToRead -= (1 /* VP8L signature */ + 4);
+ }
+
+ // Create VP8X with Exif flag set to 1
+ nonHeaderOutputStream.write(WEBP_CHUNK_TYPE_VP8X);
+ nonHeaderOutputStream.writeInt(WEBP_CHUNK_TYPE_VP8X_DEFAULT_LENGTH);
+ byte[] data = new byte[WEBP_CHUNK_TYPE_VP8X_DEFAULT_LENGTH];
+ // EXIF flag
+ data[0] = (byte) (data[0] | (1 << 3));
+ // ALPHA flag
+ data[0] = (byte) (data[0] | (alpha << 4));
+ // VP8X stores Width - 1 and Height - 1 values
+ width -= 1;
+ height -= 1;
+ data[4] = (byte) width;
+ data[5] = (byte) (width >> 8);
+ data[6] = (byte) (width >> 16);
+ data[7] = (byte) height;
+ data[8] = (byte) (height >> 8);
+ data[9] = (byte) (height >> 16);
+ nonHeaderOutputStream.write(data);
+
+ // Write VP8 or VP8L data
+ nonHeaderOutputStream.write(firstChunkType);
+ nonHeaderOutputStream.writeInt(size);
+ if (Arrays.equals(firstChunkType, WEBP_CHUNK_TYPE_VP8)) {
+ nonHeaderOutputStream.write(vp8Frame);
+ nonHeaderOutputStream.write(WEBP_VP8_SIGNATURE);
+ nonHeaderOutputStream.writeInt(widthAndHeight);
+ } else if (Arrays.equals(firstChunkType, WEBP_CHUNK_TYPE_VP8L)) {
+ nonHeaderOutputStream.write(WEBP_VP8L_SIGNATURE);
+ nonHeaderOutputStream.writeInt(widthAndHeight);
+ }
+ copy(totalInputStream, nonHeaderOutputStream, bytesToRead);
+
+ // Write EXIF chunk
+ writeExifSegment(nonHeaderOutputStream);
+ }
+ }
+
+ // Copy the rest of the file
+ copy(totalInputStream, nonHeaderOutputStream);
+
+ // Write file length + second signature
+ totalOutputStream.writeInt(nonHeaderByteArrayOutputStream.size()
+ + WEBP_SIGNATURE_2.length);
+ totalOutputStream.write(WEBP_SIGNATURE_2);
+ nonHeaderByteArrayOutputStream.writeTo(totalOutputStream);
+ } catch (Exception e) {
+ throw new IOException("Failed to save WebP file", e);
+ } finally {
+ closeQuietly(nonHeaderByteArrayOutputStream);
+ }
+ }
+
+ private void copyChunksUpToGivenChunkType(ByteOrderedDataInputStream inputStream,
+ ByteOrderedDataOutputStream outputStream, byte[] firstGivenType,
+ byte[] secondGivenType) throws IOException {
+ while (true) {
+ byte[] type = new byte[WEBP_CHUNK_TYPE_BYTE_LENGTH];
+ if (inputStream.read(type) != type.length) {
+ throw new IOException("Encountered invalid length while copying WebP chunks up to"
+ + "chunk type " + new String(firstGivenType, ASCII)
+ + ((secondGivenType == null) ? "" : " or " + new String(secondGivenType,
+ ASCII)));
+ }
+ copyWebPChunk(inputStream, outputStream, type);
+ if (Arrays.equals(type, firstGivenType)
+ || (secondGivenType != null && Arrays.equals(type, secondGivenType))) {
+ break;
+ }
+ }
+ }
+
+ private void copyWebPChunk(ByteOrderedDataInputStream inputStream,
+ ByteOrderedDataOutputStream outputStream, byte[] type) throws IOException {
+ int size = inputStream.readInt();
+ outputStream.write(type);
+ outputStream.writeInt(size);
+ // WebP files have a single padding byte at the end if the chunk size is odd.
+ copy(inputStream, outputStream, (size % 2) == 1 ? size + 1 : size);
+ }
+
// Reads the given EXIF byte area and save its tag data into attributes.
private void readExifSegment(byte[] exifBytes, int imageType) throws IOException {
ByteOrderedDataInputStream dataInputStream =
@@ -4360,14 +4638,22 @@ public class ExifInterface {
ifdOffsets[IFD_TYPE_INTEROPERABILITY], mExifByteOrder));
}
- if (mMimeType == IMAGE_TYPE_JPEG) {
- // Write JPEG specific data (APP1 size, APP1 identifier)
- dataOutputStream.writeUnsignedShort(totalSize);
- dataOutputStream.write(IDENTIFIER_EXIF_APP1);
- } else if (mMimeType == IMAGE_TYPE_PNG) {
- // Write PNG specific data (chunk size, chunk type)
- dataOutputStream.writeInt(totalSize);
- dataOutputStream.write(PNG_CHUNK_TYPE_EXIF);
+ switch (mMimeType) {
+ case IMAGE_TYPE_JPEG:
+ // Write JPEG specific data (APP1 size, APP1 identifier)
+ dataOutputStream.writeUnsignedShort(totalSize);
+ dataOutputStream.write(IDENTIFIER_EXIF_APP1);
+ break;
+ case IMAGE_TYPE_PNG:
+ // Write PNG specific data (chunk size, chunk type)
+ dataOutputStream.writeInt(totalSize);
+ dataOutputStream.write(PNG_CHUNK_TYPE_EXIF);
+ break;
+ case IMAGE_TYPE_WEBP:
+ // Write WebP specific data (chunk type, chunk size)
+ dataOutputStream.write(WEBP_CHUNK_TYPE_EXIF);
+ dataOutputStream.writeInt(totalSize);
+ break;
}
// Write TIFF Headers. See JEITA CP-3451C Section 4.5.2. Table 1.
@@ -4436,6 +4722,11 @@ public class ExifInterface {
dataOutputStream.write(getThumbnailBytes());
}
+ // For WebP files, add a single padding byte at end if chunk size is odd
+ if (mMimeType == IMAGE_TYPE_WEBP && totalSize % 2 == 1) {
+ dataOutputStream.writeByte(0);
+ }
+
// Reset the byte order to big endian in order to write remaining parts of the JPEG file.
dataOutputStream.setByteOrder(ByteOrder.BIG_ENDIAN);
@@ -4537,12 +4828,17 @@ public class ExifInterface {
private int mPosition;
public ByteOrderedDataInputStream(InputStream in) throws IOException {
+ this(in, ByteOrder.BIG_ENDIAN);
+ }
+
+ ByteOrderedDataInputStream(InputStream in, ByteOrder byteOrder) throws IOException {
mInputStream = in;
mDataInputStream = new DataInputStream(in);
mLength = mDataInputStream.available();
mPosition = 0;
// TODO (b/142218289): Need to handle case where input stream does not support mark
mDataInputStream.mark(mLength);
+ mByteOrder = byteOrder;
}
public ByteOrderedDataInputStream(byte[] bytes) throws IOException {
@@ -4867,4 +5163,12 @@ public class ExifInterface {
}
}
}
+
+ private boolean isSupportedFormatForSavingAttributes() {
+ if (mIsSupportedFile && (mMimeType == IMAGE_TYPE_JPEG || mMimeType == IMAGE_TYPE_PNG
+ || mMimeType == IMAGE_TYPE_WEBP)) {
+ return true;
+ }
+ return false;
+ }
}
diff --git a/media/java/android/media/audiopolicy/AudioPolicy.java b/media/java/android/media/audiopolicy/AudioPolicy.java
index d3e9c7e91056..8a17465c53b3 100644
--- a/media/java/android/media/audiopolicy/AudioPolicy.java
+++ b/media/java/android/media/audiopolicy/AudioPolicy.java
@@ -553,6 +553,12 @@ public class AudioPolicy {
}
}
+ /** @hide */
+ public void reset() {
+ setRegistration(null);
+ mConfig.reset();
+ }
+
public void setRegistration(String regId) {
synchronized (mLock) {
mRegistrationId = regId;
@@ -566,6 +572,11 @@ public class AudioPolicy {
sendMsg(MSG_POLICY_STATUS_CHANGE);
}
+ /**@hide*/
+ public String getRegistration() {
+ return mRegistrationId;
+ }
+
private boolean policyReadyToUse() {
synchronized (mLock) {
if (mStatus != POLICY_STATUS_REGISTERED) {
diff --git a/media/java/android/media/audiopolicy/AudioPolicyConfig.java b/media/java/android/media/audiopolicy/AudioPolicyConfig.java
index 91b9bb3f64c0..561a8847feed 100644
--- a/media/java/android/media/audiopolicy/AudioPolicyConfig.java
+++ b/media/java/android/media/audiopolicy/AudioPolicyConfig.java
@@ -162,7 +162,7 @@ public class AudioPolicyConfig implements Parcelable {
public String toLogFriendlyString () {
String textDump = new String("android.media.audiopolicy.AudioPolicyConfig:\n");
- textDump += mMixes.size() + " AudioMix: "+ mRegistrationId + "\n";
+ textDump += mMixes.size() + " AudioMix, reg:" + mRegistrationId + "\n";
for(AudioMix mix : mMixes) {
// write mix route flags
textDump += "* route flags=0x" + Integer.toHexString(mix.getRouteFlags()) + "\n";
@@ -220,6 +220,10 @@ public class AudioPolicyConfig implements Parcelable {
return textDump;
}
+ protected void reset() {
+ mMixCounter = 0;
+ }
+
protected void setRegistration(String regId) {
final boolean currentRegNull = (mRegistrationId == null) || mRegistrationId.isEmpty();
final boolean newRegNull = (regId == null) || regId.isEmpty();
diff --git a/media/jni/android_media_tv_Tuner.cpp b/media/jni/android_media_tv_Tuner.cpp
index 6e26f2c2da9e..3cd40818ae2a 100644
--- a/media/jni/android_media_tv_Tuner.cpp
+++ b/media/jni/android_media_tv_Tuner.cpp
@@ -337,33 +337,44 @@ jobject MediaEvent::getLinearBlock() {
}
mIonHandle = new C2HandleIon(dup(mAvHandle->data[0]), mDataLength);
std::shared_ptr<C2LinearBlock> block = _C2BlockFactory::CreateLinearBlock(mIonHandle);
-
- JNIEnv *env = AndroidRuntime::getJNIEnv();
- std::unique_ptr<JMediaCodecLinearBlock> context{new JMediaCodecLinearBlock};
- context->mBlock = block;
- std::shared_ptr<C2Buffer> pC2Buffer = context->toC2Buffer(0, mDataLength);
- context->mBuffer = pC2Buffer;
- mC2Buffer = pC2Buffer;
- if (mAvHandle->numInts > 0) {
- // use first int in the native_handle as the index
- int index = mAvHandle->data[mAvHandle->numFds];
- std::shared_ptr<C2Param> c2param = std::make_shared<C2DataIdInfo>(index, mDataId);
- std::shared_ptr<C2Info> info(std::static_pointer_cast<C2Info>(c2param));
- pC2Buffer->setInfo(info);
- }
- pC2Buffer->registerOnDestroyNotify(&DestroyCallback, this);
- jobject linearBlock =
- env->NewObject(
- env->FindClass("android/media/MediaCodec$LinearBlock"),
- gFields.linearBlockInitID);
- env->CallVoidMethod(
- linearBlock,
- gFields.linearBlockSetInternalStateID,
- (jlong)context.release(),
- true);
- mLinearBlockObj = env->NewWeakGlobalRef(linearBlock);
- mAvHandleRefCnt++;
- return mLinearBlockObj;
+ if (block != nullptr) {
+ // CreateLinearBlock delete mIonHandle after it create block successfully.
+ // ToDo: coordinate who is response to delete mIonHandle
+ mIonHandle = NULL;
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+ std::unique_ptr<JMediaCodecLinearBlock> context{new JMediaCodecLinearBlock};
+ context->mBlock = block;
+ std::shared_ptr<C2Buffer> pC2Buffer = context->toC2Buffer(0, mDataLength);
+ context->mBuffer = pC2Buffer;
+ mC2Buffer = pC2Buffer;
+ if (mAvHandle->numInts > 0) {
+ // use first int in the native_handle as the index
+ int index = mAvHandle->data[mAvHandle->numFds];
+ std::shared_ptr<C2Param> c2param = std::make_shared<C2DataIdInfo>(index, mDataId);
+ std::shared_ptr<C2Info> info(std::static_pointer_cast<C2Info>(c2param));
+ pC2Buffer->setInfo(info);
+ }
+ pC2Buffer->registerOnDestroyNotify(&DestroyCallback, this);
+ jobject linearBlock =
+ env->NewObject(
+ env->FindClass("android/media/MediaCodec$LinearBlock"),
+ gFields.linearBlockInitID);
+ env->CallVoidMethod(
+ linearBlock,
+ gFields.linearBlockSetInternalStateID,
+ (jlong)context.release(),
+ true);
+ mLinearBlockObj = env->NewWeakGlobalRef(linearBlock);
+ mAvHandleRefCnt++;
+ return mLinearBlockObj;
+ } else {
+ native_handle_close(const_cast<native_handle_t*>(
+ reinterpret_cast<const native_handle_t*>(mIonHandle)));
+ native_handle_delete(const_cast<native_handle_t*>(
+ reinterpret_cast<const native_handle_t*>(mIonHandle)));
+ mIonHandle = NULL;
+ return NULL;
+ }
}
uint64_t MediaEvent::getAudioHandle() {
diff --git a/non-updatable-api/current.txt b/non-updatable-api/current.txt
index 2b95992b1edf..5aaca435e71e 100644
--- a/non-updatable-api/current.txt
+++ b/non-updatable-api/current.txt
@@ -5957,6 +5957,7 @@ package android.app {
method public long[] getVibrationPattern();
method public boolean hasUserSetImportance();
method public boolean hasUserSetSound();
+ method public boolean isDemoted();
method public boolean isImportantConversation();
method public void setAllowBubbles(boolean);
method public void setBypassDnd(boolean);
@@ -43604,6 +43605,7 @@ package android.system {
package android.telecom {
public final class Call {
+ method public void addConferenceParticipants(@NonNull java.util.List<android.net.Uri>);
method public void answer(int);
method public void conference(android.telecom.Call);
method public void deflect(android.net.Uri);
@@ -43712,6 +43714,7 @@ package android.telecom {
method public static boolean hasProperty(int, int);
method public boolean hasProperty(int);
method public static String propertiesToString(int);
+ field public static final int CAPABILITY_ADD_PARTICIPANT = 33554432; // 0x2000000
field public static final int CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO = 4194304; // 0x400000
field public static final int CAPABILITY_CAN_PAUSE_VIDEO = 1048576; // 0x100000
field public static final int CAPABILITY_CAN_PULL_CALL = 8388608; // 0x800000
@@ -43741,6 +43744,7 @@ package android.telecom {
field public static final int PROPERTY_GENERIC_CONFERENCE = 2; // 0x2
field public static final int PROPERTY_HAS_CDMA_VOICE_PRIVACY = 128; // 0x80
field public static final int PROPERTY_HIGH_DEF_AUDIO = 16; // 0x10
+ field public static final int PROPERTY_IS_ADHOC_CONFERENCE = 8192; // 0x2000
field public static final int PROPERTY_IS_EXTERNAL_CALL = 64; // 0x40
field public static final int PROPERTY_NETWORK_IDENTIFIED_EMERGENCY_CALL = 2048; // 0x800
field public static final int PROPERTY_RTT = 1024; // 0x400
@@ -43818,6 +43822,7 @@ package android.telecom {
public abstract class Conference extends android.telecom.Conferenceable {
ctor public Conference(android.telecom.PhoneAccountHandle);
method public final boolean addConnection(android.telecom.Connection);
+ method @NonNull public static android.telecom.Conference createFailedConference(@NonNull android.telecom.DisconnectCause, @NonNull android.telecom.PhoneAccountHandle);
method public final void destroy();
method public final android.telecom.CallAudioState getCallAudioState();
method public final java.util.List<android.telecom.Connection> getConferenceableConnections();
@@ -43833,6 +43838,9 @@ package android.telecom {
method public final android.telecom.StatusHints getStatusHints();
method public android.telecom.Connection.VideoProvider getVideoProvider();
method public int getVideoState();
+ method public final boolean isRingbackRequested();
+ method public void onAddConferenceParticipants(@NonNull java.util.List<android.net.Uri>);
+ method public void onAnswer(int);
method public void onCallAudioStateChanged(android.telecom.CallAudioState);
method public void onConnectionAdded(android.telecom.Connection);
method public void onDisconnect();
@@ -43841,6 +43849,7 @@ package android.telecom {
method public void onMerge(android.telecom.Connection);
method public void onMerge();
method public void onPlayDtmfTone(char);
+ method public void onReject();
method public void onSeparate(android.telecom.Connection);
method public void onStopDtmfTone();
method public void onSwap();
@@ -43861,6 +43870,8 @@ package android.telecom {
method public final void setDisconnected(android.telecom.DisconnectCause);
method public final void setExtras(@Nullable android.os.Bundle);
method public final void setOnHold();
+ method public final void setRingbackRequested(boolean);
+ method public final void setRinging();
method public final void setStatusHints(android.telecom.StatusHints);
method public final void setVideoProvider(android.telecom.Connection, android.telecom.Connection.VideoProvider);
method public final void setVideoState(android.telecom.Connection, int);
@@ -43897,6 +43908,7 @@ package android.telecom {
method public final boolean isRingbackRequested();
method public final void notifyConferenceMergeFailed();
method public void onAbort();
+ method public void onAddConferenceParticipants(@NonNull java.util.List<android.net.Uri>);
method public void onAnswer(int);
method public void onAnswer();
method public void onCallAudioStateChanged(android.telecom.CallAudioState);
@@ -43976,6 +43988,7 @@ package android.telecom {
field public static final int AUDIO_CODEC_GSM_HR = 10; // 0xa
field public static final int AUDIO_CODEC_NONE = 0; // 0x0
field public static final int AUDIO_CODEC_QCELP13K = 3; // 0x3
+ field public static final int CAPABILITY_ADD_PARTICIPANT = 67108864; // 0x4000000
field public static final int CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO = 8388608; // 0x800000
field public static final int CAPABILITY_CAN_PAUSE_VIDEO = 1048576; // 0x100000
field public static final int CAPABILITY_CAN_PULL_CALL = 16777216; // 0x1000000
@@ -44019,6 +44032,7 @@ package android.telecom {
field public static final int PROPERTY_ASSISTED_DIALING = 512; // 0x200
field public static final int PROPERTY_HAS_CDMA_VOICE_PRIVACY = 32; // 0x20
field public static final int PROPERTY_HIGH_DEF_AUDIO = 4; // 0x4
+ field public static final int PROPERTY_IS_ADHOC_CONFERENCE = 4096; // 0x1000
field public static final int PROPERTY_IS_EXTERNAL_CALL = 16; // 0x10
field public static final int PROPERTY_IS_RTT = 256; // 0x100
field public static final int PROPERTY_NETWORK_IDENTIFIED_EMERGENCY_CALL = 1024; // 0x400
@@ -44114,9 +44128,13 @@ package android.telecom {
method public void onConference(android.telecom.Connection, android.telecom.Connection);
method public void onConnectionServiceFocusGained();
method public void onConnectionServiceFocusLost();
+ method @Nullable public android.telecom.Conference onCreateIncomingConference(@Nullable android.telecom.PhoneAccountHandle, @Nullable android.telecom.ConnectionRequest);
+ method public void onCreateIncomingConferenceFailed(@Nullable android.telecom.PhoneAccountHandle, @Nullable android.telecom.ConnectionRequest);
method public android.telecom.Connection onCreateIncomingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
method public void onCreateIncomingConnectionFailed(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
method public android.telecom.Connection onCreateIncomingHandoverConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
+ method @Nullable public android.telecom.Conference onCreateOutgoingConference(@Nullable android.telecom.PhoneAccountHandle, @Nullable android.telecom.ConnectionRequest);
+ method public void onCreateOutgoingConferenceFailed(@Nullable android.telecom.PhoneAccountHandle, @Nullable android.telecom.ConnectionRequest);
method public android.telecom.Connection onCreateOutgoingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
method public void onCreateOutgoingConnectionFailed(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
method public android.telecom.Connection onCreateOutgoingHandoverConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest);
@@ -44427,6 +44445,7 @@ package android.telecom {
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ANSWER_PHONE_CALLS, android.Manifest.permission.MODIFY_PHONE_STATE}) public void acceptRingingCall();
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ANSWER_PHONE_CALLS, android.Manifest.permission.MODIFY_PHONE_STATE}) public void acceptRingingCall(int);
method public void addNewIncomingCall(android.telecom.PhoneAccountHandle, android.os.Bundle);
+ method public void addNewIncomingConference(@NonNull android.telecom.PhoneAccountHandle, @NonNull android.os.Bundle);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void cancelMissedCallsNotification();
method public android.content.Intent createManageBlockedNumbersIntent();
method @Deprecated @RequiresPermission(android.Manifest.permission.ANSWER_PHONE_CALLS) public boolean endCall();
@@ -44454,6 +44473,7 @@ package android.telecom {
method public void registerPhoneAccount(android.telecom.PhoneAccount);
method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public void showInCallScreen(boolean);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void silenceRinger();
+ method @RequiresPermission(android.Manifest.permission.CALL_PHONE) public void startConference(@NonNull java.util.List<android.net.Uri>, @NonNull android.os.Bundle);
method public void unregisterPhoneAccount(android.telecom.PhoneAccountHandle);
field public static final String ACTION_CHANGE_DEFAULT_DIALER = "android.telecom.action.CHANGE_DEFAULT_DIALER";
field public static final String ACTION_CHANGE_PHONE_ACCOUNTS = "android.telecom.action.CHANGE_PHONE_ACCOUNTS";
@@ -44993,6 +45013,8 @@ package android.telephony {
field public static final String KEY_SIM_NETWORK_UNLOCK_ALLOW_DISMISS_BOOL = "sim_network_unlock_allow_dismiss_bool";
field public static final String KEY_SMS_REQUIRES_DESTINATION_NUMBER_CONVERSION_BOOL = "sms_requires_destination_number_conversion_bool";
field public static final String KEY_SUPPORT_3GPP_CALL_FORWARDING_WHILE_ROAMING_BOOL = "support_3gpp_call_forwarding_while_roaming_bool";
+ field public static final String KEY_SUPPORT_ADD_CONFERENCE_PARTICIPANTS_BOOL = "support_add_conference_participants_bool";
+ field public static final String KEY_SUPPORT_ADHOC_CONFERENCE_CALLS_BOOL = "support_adhoc_conference_calls_bool";
field public static final String KEY_SUPPORT_CLIR_NETWORK_DEFAULT_BOOL = "support_clir_network_default_bool";
field public static final String KEY_SUPPORT_CONFERENCE_CALL_BOOL = "support_conference_call_bool";
field public static final String KEY_SUPPORT_EMERGENCY_SMS_OVER_IMS_BOOL = "support_emergency_sms_over_ims_bool";
@@ -46065,12 +46087,13 @@ package android.telephony {
public final class SmsManager {
method public String createAppSpecificSmsToken(android.app.PendingIntent);
method @Nullable public String createAppSpecificSmsTokenWithPackageInfo(@Nullable String, @NonNull android.app.PendingIntent);
+ method @NonNull public android.telephony.SmsManager createForSubscriptionId(int);
method public java.util.ArrayList<java.lang.String> divideMessage(String);
method public void downloadMultimediaMessage(android.content.Context, String, android.net.Uri, android.os.Bundle, android.app.PendingIntent);
method @NonNull public android.os.Bundle getCarrierConfigValues();
- method public static android.telephony.SmsManager getDefault();
+ method @Deprecated public static android.telephony.SmsManager getDefault();
method public static int getDefaultSmsSubscriptionId();
- method public static android.telephony.SmsManager getSmsManagerForSubscriptionId(int);
+ method @Deprecated public static android.telephony.SmsManager getSmsManagerForSubscriptionId(int);
method @RequiresPermission(android.Manifest.permission.SMS_FINANCIAL_TRANSACTIONS) public void getSmsMessagesForFinancialApp(android.os.Bundle, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.SmsManager.FinancialSmsCallback);
method @Nullable @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public String getSmscAddress();
method public int getSubscriptionId();
diff --git a/non-updatable-api/module-lib-current.txt b/non-updatable-api/module-lib-current.txt
index a5ca196ef5b4..45ff6d3893e3 100644
--- a/non-updatable-api/module-lib-current.txt
+++ b/non-updatable-api/module-lib-current.txt
@@ -5,6 +5,10 @@ package android.app {
field public static final String OPSTR_NO_ISOLATED_STORAGE = "android:no_isolated_storage";
}
+ public class NotificationManager {
+ method public boolean hasEnabledNotificationListener(@NonNull String, @NonNull android.os.UserHandle);
+ }
+
}
package android.content.rollback {
@@ -29,6 +33,15 @@ package android.graphics {
package android.os {
+ public class Binder implements android.os.IBinder {
+ method public final void markVintfStability();
+ }
+
+ public interface Parcelable {
+ field public static final int PARCELABLE_STABILITY_LOCAL = 0; // 0x0
+ field public static final int PARCELABLE_STABILITY_VINTF = 1; // 0x1
+ }
+
public class StatsServiceManager {
method @NonNull public android.os.StatsServiceManager.ServiceRegisterer getStatsCompanionServiceRegisterer();
method @NonNull public android.os.StatsServiceManager.ServiceRegisterer getStatsManagerServiceRegisterer();
diff --git a/packages/BackupEncryption/src/com/android/server/backup/encryption/chunking/cdc/Hkdf.java b/packages/BackupEncryption/src/com/android/server/backup/encryption/chunking/cdc/Hkdf.java
index c7af8c8778ce..d0776aef78b6 100644
--- a/packages/BackupEncryption/src/com/android/server/backup/encryption/chunking/cdc/Hkdf.java
+++ b/packages/BackupEncryption/src/com/android/server/backup/encryption/chunking/cdc/Hkdf.java
@@ -40,18 +40,18 @@ public final class Hkdf {
*
* <p>IMPORTANT: The use or edit of this method requires a security review.
*
- * @param masterKey Master key from which to derive sub-keys.
+ * @param mainKey Main key from which to derive sub-keys.
* @param salt A randomly generated 256-bit byte string.
* @param data Arbitrary information that is bound to the derived key (i.e., used in its
* creation).
- * @return Raw derived key bytes = HKDF-SHA256(masterKey, salt, data).
+ * @return Raw derived key bytes = HKDF-SHA256(mainKey, salt, data).
* @throws InvalidKeyException If the salt can not be used as a valid key.
*/
- static byte[] hkdf(byte[] masterKey, byte[] salt, byte[] data) throws InvalidKeyException {
- Objects.requireNonNull(masterKey, "HKDF requires master key to be set.");
+ static byte[] hkdf(byte[] mainKey, byte[] salt, byte[] data) throws InvalidKeyException {
+ Objects.requireNonNull(mainKey, "HKDF requires main key to be set.");
Objects.requireNonNull(salt, "HKDF requires a salt.");
Objects.requireNonNull(data, "No data provided to HKDF.");
- return hkdfSha256Expand(hkdfSha256Extract(masterKey, salt), data);
+ return hkdfSha256Expand(hkdfSha256Extract(mainKey, salt), data);
}
private Hkdf() {}
diff --git a/packages/CarSystemUI/res/values/config.xml b/packages/CarSystemUI/res/values/config.xml
index cf967c02bec5..039f2c039ded 100644
--- a/packages/CarSystemUI/res/values/config.xml
+++ b/packages/CarSystemUI/res/values/config.xml
@@ -24,12 +24,35 @@
<bool name="config_enableFullscreenUserSwitcher">true</bool>
- <!-- configure which system ui bars should be displayed -->
+ <!-- Configure which system bars should be displayed. -->
<bool name="config_enableTopNavigationBar">true</bool>
<bool name="config_enableLeftNavigationBar">false</bool>
<bool name="config_enableRightNavigationBar">false</bool>
<bool name="config_enableBottomNavigationBar">true</bool>
+ <!-- Configure the type of each system bar. Each system bar must have a unique type. -->
+ <!-- STATUS_BAR = 0-->
+ <!-- NAVIGATION_BAR = 1-->
+ <!-- STATUS_BAR_EXTRA = 2-->
+ <!-- NAVIGATION_BAR_EXTRA = 3-->
+ <integer name="config_topSystemBarType">0</integer>
+ <integer name="config_leftSystemBarType">2</integer>
+ <integer name="config_rightSystemBarType">3</integer>
+ <integer name="config_bottomSystemBarType">1</integer>
+
+ <!-- Configure the relative z-order among the system bars. When two system bars overlap (e.g.
+ if both top bar and left bar are enabled, it creates an overlapping space in the upper left
+ corner), the system bar with the higher z-order takes the overlapping space and padding is
+ applied to the other bar.-->
+ <!-- NOTE: If two overlapping system bars have the same z-order, SystemBarConfigs will throw a
+ RuntimeException, since their placing order cannot be determined. Bars that do not overlap
+ are allowed to have the same z-order. -->
+ <!-- NOTE: If the z-order of a bar is 10 or above, it will also appear on top of HUN's. -->
+ <integer name="config_topSystemBarZOrder">1</integer>
+ <integer name="config_leftSystemBarZOrder">0</integer>
+ <integer name="config_rightSystemBarZOrder">0</integer>
+ <integer name="config_bottomSystemBarZOrder">10</integer>
+
<!-- Disable normal notification rendering; we handle that ourselves -->
<bool name="config_renderNotifications">false</bool>
diff --git a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIFactory.java b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIFactory.java
index 1a1b93b33caf..03ea9418415d 100644
--- a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIFactory.java
+++ b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIFactory.java
@@ -32,7 +32,7 @@ public class CarSystemUIFactory extends SystemUIFactory {
@Override
protected SystemUIRootComponent buildSystemUIRootComponent(Context context) {
return DaggerCarSystemUIRootComponent.builder()
- .contextHolder(new ContextHolder(context))
+ .context(context)
.build();
}
diff --git a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java
index 7b6dceb5fcd7..995a3ecde6c1 100644
--- a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java
+++ b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java
@@ -134,9 +134,13 @@ public abstract class CarSystemUIModule {
}
@Singleton
- @Binds
- abstract DisplayImeController bindDisplayImeController(
- DisplaySystemBarsController displaySystemBarsController);
+ @Provides
+ static DisplayImeController provideDisplayImeController(Context context,
+ IWindowManager wmService, DisplayController displayController,
+ @Main Handler mainHandler, TransactionPool transactionPool) {
+ return new DisplaySystemBarsController.Builder(context, wmService, displayController,
+ mainHandler, transactionPool).build();
+ }
@Binds
abstract HeadsUpManager bindHeadsUpManagerPhone(HeadsUpManagerPhone headsUpManagerPhone);
diff --git a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIRootComponent.java b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIRootComponent.java
index 088420eefa9e..ece3bee000f9 100644
--- a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIRootComponent.java
+++ b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIRootComponent.java
@@ -36,12 +36,17 @@ import dagger.Component;
DependencyBinder.class,
PipModule.class,
OneHandedModule.class,
- SystemUIFactory.ContextHolder.class,
SystemServicesModule.class,
SystemUIModule.class,
CarSystemUIModule.class,
CarSystemUIBinder.class
})
public interface CarSystemUIRootComponent extends SystemUIRootComponent {
-
+ /**
+ * Builder for a CarSystemUIRootComponent.
+ */
+ @Component.Builder
+ interface Builder extends SystemUIRootComponent.Builder {
+ CarSystemUIRootComponent build();
+ }
}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBar.java b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBar.java
index 35b2080dddf9..9584850fde7c 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBar.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBar.java
@@ -16,12 +16,8 @@
package com.android.systemui.car.navigationbar;
-import static android.view.InsetsState.ITYPE_BOTTOM_GESTURES;
-import static android.view.InsetsState.ITYPE_CLIMATE_BAR;
-import static android.view.InsetsState.ITYPE_EXTRA_NAVIGATION_BAR;
import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
import static android.view.InsetsState.ITYPE_STATUS_BAR;
-import static android.view.InsetsState.ITYPE_TOP_GESTURES;
import static android.view.InsetsState.containsType;
import static android.view.WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS;
@@ -30,13 +26,11 @@ import static com.android.systemui.statusbar.phone.BarTransitions.MODE_TRANSPARE
import android.content.Context;
import android.content.res.Resources;
-import android.graphics.PixelFormat;
import android.inputmethodservice.InputMethodService;
import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
import android.view.Display;
-import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowInsetsController;
@@ -47,7 +41,6 @@ import androidx.annotation.VisibleForTesting;
import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.statusbar.RegisterStatusBarResult;
import com.android.internal.view.AppearanceRegion;
-import com.android.systemui.R;
import com.android.systemui.SystemUI;
import com.android.systemui.car.CarDeviceProvisionedController;
import com.android.systemui.car.CarDeviceProvisionedListener;
@@ -76,7 +69,6 @@ import dagger.Lazy;
/** Navigation bars customized for the automotive use case. */
public class CarNavigationBar extends SystemUI implements CommandQueue.Callbacks {
-
private final Resources mResources;
private final CarNavigationBarController mCarNavigationBarController;
private final SysuiDarkIconDispatcher mStatusBarIconController;
@@ -93,6 +85,7 @@ public class CarNavigationBar extends SystemUI implements CommandQueue.Callbacks
private final Lazy<StatusBarIconController> mIconControllerLazy;
private final int mDisplayId;
+ private final SystemBarConfigs mSystemBarConfigs;
private StatusBarSignalPolicy mSignalPolicy;
private ActivityManagerWrapper mActivityManagerWrapper;
@@ -141,7 +134,8 @@ public class CarNavigationBar extends SystemUI implements CommandQueue.Callbacks
IStatusBarService barService,
Lazy<KeyguardStateController> keyguardStateControllerLazy,
Lazy<PhoneStatusBarPolicy> iconPolicyLazy,
- Lazy<StatusBarIconController> iconControllerLazy
+ Lazy<StatusBarIconController> iconControllerLazy,
+ SystemBarConfigs systemBarConfigs
) {
super(context);
mResources = resources;
@@ -158,6 +152,7 @@ public class CarNavigationBar extends SystemUI implements CommandQueue.Callbacks
mKeyguardStateControllerLazy = keyguardStateControllerLazy;
mIconPolicyLazy = iconPolicyLazy;
mIconControllerLazy = iconControllerLazy;
+ mSystemBarConfigs = systemBarConfigs;
mDisplayId = context.getDisplayId();
}
@@ -344,103 +339,63 @@ public class CarNavigationBar extends SystemUI implements CommandQueue.Callbacks
private void buildNavBarContent() {
mTopNavigationBarView = mCarNavigationBarController.getTopBar(isDeviceSetupForUser());
if (mTopNavigationBarView != null) {
+ mSystemBarConfigs.insetSystemBar(SystemBarConfigs.TOP, mTopNavigationBarView);
mTopNavigationBarWindow.addView(mTopNavigationBarView);
}
mBottomNavigationBarView = mCarNavigationBarController.getBottomBar(isDeviceSetupForUser());
if (mBottomNavigationBarView != null) {
+ mSystemBarConfigs.insetSystemBar(SystemBarConfigs.BOTTOM, mBottomNavigationBarView);
mBottomNavigationBarWindow.addView(mBottomNavigationBarView);
}
mLeftNavigationBarView = mCarNavigationBarController.getLeftBar(isDeviceSetupForUser());
if (mLeftNavigationBarView != null) {
+ mSystemBarConfigs.insetSystemBar(SystemBarConfigs.LEFT, mLeftNavigationBarView);
mLeftNavigationBarWindow.addView(mLeftNavigationBarView);
}
mRightNavigationBarView = mCarNavigationBarController.getRightBar(isDeviceSetupForUser());
if (mRightNavigationBarView != null) {
+ mSystemBarConfigs.insetSystemBar(SystemBarConfigs.RIGHT, mRightNavigationBarView);
mRightNavigationBarWindow.addView(mRightNavigationBarView);
}
}
private void attachNavBarWindows() {
- if (mTopNavigationBarWindow != null) {
- int height = mResources.getDimensionPixelSize(
- com.android.internal.R.dimen.status_bar_height);
- WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
- ViewGroup.LayoutParams.MATCH_PARENT,
- height,
- WindowManager.LayoutParams.TYPE_STATUS_BAR_ADDITIONAL,
- WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
- | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
- | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
- | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
- PixelFormat.TRANSLUCENT);
- lp.setTitle("TopCarNavigationBar");
- lp.providesInsetsTypes = new int[]{ITYPE_STATUS_BAR, ITYPE_TOP_GESTURES};
- lp.setFitInsetsTypes(0);
- lp.windowAnimations = 0;
- lp.gravity = Gravity.TOP;
- mWindowManager.addView(mTopNavigationBarWindow, lp);
- }
-
- if (mBottomNavigationBarWindow != null && !mBottomNavBarVisible) {
- mBottomNavBarVisible = true;
- int height = mResources.getDimensionPixelSize(
- com.android.internal.R.dimen.navigation_bar_height);
-
- WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
- ViewGroup.LayoutParams.MATCH_PARENT,
- height,
- WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL,
- WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
- | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
- | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
- | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
- PixelFormat.TRANSLUCENT);
- lp.setTitle("BottomCarNavigationBar");
- lp.providesInsetsTypes = new int[]{ITYPE_NAVIGATION_BAR, ITYPE_BOTTOM_GESTURES};
- lp.windowAnimations = 0;
- lp.gravity = Gravity.BOTTOM;
- mWindowManager.addView(mBottomNavigationBarWindow, lp);
- }
-
- if (mLeftNavigationBarWindow != null) {
- int width = mResources.getDimensionPixelSize(
- R.dimen.car_left_navigation_bar_width);
- WindowManager.LayoutParams leftlp = new WindowManager.LayoutParams(
- width, ViewGroup.LayoutParams.MATCH_PARENT,
- WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL,
- WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
- | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
- | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
- | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
- PixelFormat.TRANSLUCENT);
- leftlp.setTitle("LeftCarNavigationBar");
- leftlp.providesInsetsTypes = new int[]{ITYPE_CLIMATE_BAR};
- leftlp.setFitInsetsTypes(0);
- leftlp.windowAnimations = 0;
- leftlp.gravity = Gravity.LEFT;
- mWindowManager.addView(mLeftNavigationBarWindow, leftlp);
- }
+ mSystemBarConfigs.getSystemBarSidesByZOrder().forEach(this::attachNavBarBySide);
+ }
- if (mRightNavigationBarWindow != null) {
- int width = mResources.getDimensionPixelSize(
- R.dimen.car_right_navigation_bar_width);
- WindowManager.LayoutParams rightlp = new WindowManager.LayoutParams(
- width, ViewGroup.LayoutParams.MATCH_PARENT,
- WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL,
- WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
- | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
- | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
- | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
- PixelFormat.TRANSLUCENT);
- rightlp.setTitle("RightCarNavigationBar");
- rightlp.providesInsetsTypes = new int[]{ITYPE_EXTRA_NAVIGATION_BAR};
- rightlp.setFitInsetsTypes(0);
- rightlp.windowAnimations = 0;
- rightlp.gravity = Gravity.RIGHT;
- mWindowManager.addView(mRightNavigationBarWindow, rightlp);
+ private void attachNavBarBySide(int side) {
+ switch(side) {
+ case SystemBarConfigs.TOP:
+ if (mTopNavigationBarWindow != null) {
+ mWindowManager.addView(mTopNavigationBarWindow,
+ mSystemBarConfigs.getLayoutParamsBySide(SystemBarConfigs.TOP));
+ }
+ break;
+ case SystemBarConfigs.BOTTOM:
+ if (mBottomNavigationBarWindow != null && !mBottomNavBarVisible) {
+ mBottomNavBarVisible = true;
+
+ mWindowManager.addView(mBottomNavigationBarWindow,
+ mSystemBarConfigs.getLayoutParamsBySide(SystemBarConfigs.BOTTOM));
+ }
+ break;
+ case SystemBarConfigs.LEFT:
+ if (mLeftNavigationBarWindow != null) {
+ mWindowManager.addView(mLeftNavigationBarWindow,
+ mSystemBarConfigs.getLayoutParamsBySide(SystemBarConfigs.LEFT));
+ }
+ break;
+ case SystemBarConfigs.RIGHT:
+ if (mRightNavigationBarWindow != null) {
+ mWindowManager.addView(mRightNavigationBarWindow,
+ mSystemBarConfigs.getLayoutParamsBySide(SystemBarConfigs.RIGHT));
+ }
+ break;
+ default:
+ return;
}
}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBarController.java b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBarController.java
index ca780ae645c9..fe26040c5eae 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBarController.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBarController.java
@@ -22,7 +22,6 @@ import android.view.ViewGroup;
import androidx.annotation.Nullable;
-import com.android.systemui.R;
import com.android.systemui.car.hvac.HvacController;
import javax.inject.Inject;
@@ -61,7 +60,8 @@ public class CarNavigationBarController {
NavigationBarViewFactory navigationBarViewFactory,
ButtonSelectionStateController buttonSelectionStateController,
Lazy<HvacController> hvacControllerLazy,
- ButtonRoleHolderController buttonRoleHolderController) {
+ ButtonRoleHolderController buttonRoleHolderController,
+ SystemBarConfigs systemBarConfigs) {
mContext = context;
mNavigationBarViewFactory = navigationBarViewFactory;
mButtonSelectionStateController = buttonSelectionStateController;
@@ -69,10 +69,10 @@ public class CarNavigationBarController {
mButtonRoleHolderController = buttonRoleHolderController;
// Read configuration.
- mShowTop = mContext.getResources().getBoolean(R.bool.config_enableTopNavigationBar);
- mShowBottom = mContext.getResources().getBoolean(R.bool.config_enableBottomNavigationBar);
- mShowLeft = mContext.getResources().getBoolean(R.bool.config_enableLeftNavigationBar);
- mShowRight = mContext.getResources().getBoolean(R.bool.config_enableRightNavigationBar);
+ mShowTop = systemBarConfigs.getEnabledStatusBySide(SystemBarConfigs.TOP);
+ mShowBottom = systemBarConfigs.getEnabledStatusBySide(SystemBarConfigs.BOTTOM);
+ mShowLeft = systemBarConfigs.getEnabledStatusBySide(SystemBarConfigs.LEFT);
+ mShowRight = systemBarConfigs.getEnabledStatusBySide(SystemBarConfigs.RIGHT);
}
/**
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBarView.java b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBarView.java
index 0ced4021ce38..ab401bbf06bb 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBarView.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBarView.java
@@ -16,14 +16,10 @@
package com.android.systemui.car.navigationbar;
-import static android.view.WindowInsets.Type.systemBars;
-
import android.content.Context;
-import android.graphics.Insets;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
-import android.view.WindowInsets;
import android.widget.LinearLayout;
import com.android.systemui.Dependency;
@@ -80,30 +76,6 @@ public class CarNavigationBarView extends LinearLayout {
setFocusable(false);
}
- @Override
- public WindowInsets onApplyWindowInsets(WindowInsets windowInsets) {
- applyMargins(windowInsets.getInsets(systemBars()));
- return windowInsets;
- }
-
- private void applyMargins(Insets insets) {
- final int count = getChildCount();
- for (int i = 0; i < count; i++) {
- View child = getChildAt(i);
- if (child.getLayoutParams() instanceof LayoutParams) {
- LayoutParams lp = (LayoutParams) child.getLayoutParams();
- if (lp.rightMargin != insets.right || lp.leftMargin != insets.left
- || lp.topMargin != insets.top || lp.bottomMargin != insets.bottom) {
- lp.rightMargin = insets.right;
- lp.leftMargin = insets.left;
- lp.topMargin = insets.top;
- lp.bottomMargin = insets.bottom;
- child.requestLayout();
- }
- }
- }
- }
-
// Used to forward touch events even if the touch was initiated from a child component
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/SystemBarConfigs.java b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/SystemBarConfigs.java
new file mode 100644
index 000000000000..3527bf93682f
--- /dev/null
+++ b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/SystemBarConfigs.java
@@ -0,0 +1,380 @@
+/*
+ * 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.car.navigationbar;
+
+import android.annotation.IntDef;
+import android.content.res.Resources;
+import android.graphics.PixelFormat;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.Log;
+import android.view.Gravity;
+import android.view.InsetsState;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.R;
+import com.android.systemui.dagger.qualifiers.Main;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Target;
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+/**
+ * Reads configs for system bars for each side (TOP, BOTTOM, LEFT, and RIGHT) and returns the
+ * corresponding {@link android.view.WindowManager.LayoutParams} per the configuration.
+ */
+@Singleton
+public class SystemBarConfigs {
+
+ private static final String TAG = SystemBarConfigs.class.getSimpleName();
+ // The z-order from which system bars will start to appear on top of HUN's.
+ private static final int HUN_ZORDER = 10;
+
+ @IntDef(value = {TOP, BOTTOM, LEFT, RIGHT})
+ @Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE})
+ private @interface SystemBarSide {
+ }
+
+ public static final int TOP = 0;
+ public static final int BOTTOM = 1;
+ public static final int LEFT = 2;
+ public static final int RIGHT = 3;
+
+ /*
+ NOTE: The elements' order in the map below must be preserved as-is since the correct
+ corresponding values are obtained by the index.
+ */
+ private static final int[] BAR_TYPE_MAP = {
+ InsetsState.ITYPE_STATUS_BAR,
+ InsetsState.ITYPE_NAVIGATION_BAR,
+ InsetsState.ITYPE_CLIMATE_BAR,
+ InsetsState.ITYPE_EXTRA_NAVIGATION_BAR
+ };
+
+ private static final Map<@SystemBarSide Integer, Integer> BAR_GRAVITY_MAP = new ArrayMap<>();
+ private static final Map<@SystemBarSide Integer, String> BAR_TITLE_MAP = new ArrayMap<>();
+ private static final Map<@SystemBarSide Integer, Integer> BAR_GESTURE_MAP = new ArrayMap<>();
+
+ private final Resources mResources;
+ private final Map<@SystemBarSide Integer, SystemBarConfig> mSystemBarConfigMap =
+ new ArrayMap<>();
+ private final List<@SystemBarSide Integer> mSystemBarSidesByZOrder = new ArrayList<>();
+
+ private boolean mTopNavBarEnabled;
+ private boolean mBottomNavBarEnabled;
+ private boolean mLeftNavBarEnabled;
+ private boolean mRightNavBarEnabled;
+
+ @Inject
+ public SystemBarConfigs(@Main Resources resources) {
+ mResources = resources;
+
+ populateMaps();
+ readConfigs();
+ checkEnabledBarsHaveUniqueBarTypes();
+ setInsetPaddingsForOverlappingCorners();
+ sortSystemBarSidesByZOrder();
+ }
+
+ protected WindowManager.LayoutParams getLayoutParamsBySide(@SystemBarSide int side) {
+ return mSystemBarConfigMap.get(side) != null
+ ? mSystemBarConfigMap.get(side).getLayoutParams() : null;
+ }
+
+ protected boolean getEnabledStatusBySide(@SystemBarSide int side) {
+ switch (side) {
+ case TOP:
+ return mTopNavBarEnabled;
+ case BOTTOM:
+ return mBottomNavBarEnabled;
+ case LEFT:
+ return mLeftNavBarEnabled;
+ case RIGHT:
+ return mRightNavBarEnabled;
+ default:
+ return false;
+ }
+ }
+
+ protected void insetSystemBar(@SystemBarSide int side, CarNavigationBarView view) {
+ int[] paddings = mSystemBarConfigMap.get(side).getPaddings();
+ view.setPadding(paddings[2], paddings[0], paddings[3], paddings[1]);
+ }
+
+ protected List<Integer> getSystemBarSidesByZOrder() {
+ return mSystemBarSidesByZOrder;
+ }
+
+ @VisibleForTesting
+ protected static int getHunZOrder() {
+ return HUN_ZORDER;
+ }
+
+ private static void populateMaps() {
+ BAR_GRAVITY_MAP.put(TOP, Gravity.TOP);
+ BAR_GRAVITY_MAP.put(BOTTOM, Gravity.BOTTOM);
+ BAR_GRAVITY_MAP.put(LEFT, Gravity.LEFT);
+ BAR_GRAVITY_MAP.put(RIGHT, Gravity.RIGHT);
+
+ BAR_TITLE_MAP.put(TOP, "TopCarSystemBar");
+ BAR_TITLE_MAP.put(BOTTOM, "BottomCarSystemBar");
+ BAR_TITLE_MAP.put(LEFT, "LeftCarSystemBar");
+ BAR_TITLE_MAP.put(RIGHT, "RightCarSystemBar");
+
+ BAR_GESTURE_MAP.put(TOP, InsetsState.ITYPE_TOP_GESTURES);
+ BAR_GESTURE_MAP.put(BOTTOM, InsetsState.ITYPE_BOTTOM_GESTURES);
+ BAR_GESTURE_MAP.put(LEFT, InsetsState.ITYPE_LEFT_GESTURES);
+ BAR_GESTURE_MAP.put(RIGHT, InsetsState.ITYPE_RIGHT_GESTURES);
+ }
+
+ private void readConfigs() {
+ mTopNavBarEnabled = mResources.getBoolean(R.bool.config_enableTopNavigationBar);
+ mBottomNavBarEnabled = mResources.getBoolean(R.bool.config_enableBottomNavigationBar);
+ mLeftNavBarEnabled = mResources.getBoolean(R.bool.config_enableLeftNavigationBar);
+ mRightNavBarEnabled = mResources.getBoolean(R.bool.config_enableRightNavigationBar);
+
+ if (mTopNavBarEnabled) {
+ SystemBarConfig topBarConfig =
+ new SystemBarConfigBuilder()
+ .setSide(TOP)
+ .setGirth(mResources.getDimensionPixelSize(
+ com.android.internal.R.dimen.status_bar_height))
+ .setBarType(mResources.getInteger(R.integer.config_topSystemBarType))
+ .setZOrder(mResources.getInteger(R.integer.config_topSystemBarZOrder))
+ .build();
+ mSystemBarConfigMap.put(TOP, topBarConfig);
+ }
+
+ if (mBottomNavBarEnabled) {
+ SystemBarConfig bottomBarConfig =
+ new SystemBarConfigBuilder()
+ .setSide(BOTTOM)
+ .setGirth(mResources.getDimensionPixelSize(
+ com.android.internal.R.dimen.navigation_bar_height))
+ .setBarType(mResources.getInteger(R.integer.config_bottomSystemBarType))
+ .setZOrder(
+ mResources.getInteger(R.integer.config_bottomSystemBarZOrder))
+ .build();
+ mSystemBarConfigMap.put(BOTTOM, bottomBarConfig);
+ }
+
+ if (mLeftNavBarEnabled) {
+ SystemBarConfig leftBarConfig =
+ new SystemBarConfigBuilder()
+ .setSide(LEFT)
+ .setGirth(mResources.getDimensionPixelSize(
+ R.dimen.car_left_navigation_bar_width))
+ .setBarType(mResources.getInteger(R.integer.config_leftSystemBarType))
+ .setZOrder(mResources.getInteger(R.integer.config_leftSystemBarZOrder))
+ .build();
+ mSystemBarConfigMap.put(LEFT, leftBarConfig);
+ }
+
+ if (mRightNavBarEnabled) {
+ SystemBarConfig rightBarConfig =
+ new SystemBarConfigBuilder()
+ .setSide(RIGHT)
+ .setGirth(mResources.getDimensionPixelSize(
+ R.dimen.car_right_navigation_bar_width))
+ .setBarType(mResources.getInteger(R.integer.config_rightSystemBarType))
+ .setZOrder(mResources.getInteger(R.integer.config_rightSystemBarZOrder))
+ .build();
+ mSystemBarConfigMap.put(RIGHT, rightBarConfig);
+ }
+ }
+
+ private void checkEnabledBarsHaveUniqueBarTypes() throws RuntimeException {
+ Set<Integer> barTypesUsed = new ArraySet<>();
+ int enabledNavBarCount = mSystemBarConfigMap.size();
+
+ for (SystemBarConfig systemBarConfig : mSystemBarConfigMap.values()) {
+ barTypesUsed.add(systemBarConfig.getBarType());
+ }
+
+ // The number of bar types used cannot be fewer than that of enabled system bars.
+ if (barTypesUsed.size() < enabledNavBarCount) {
+ throw new RuntimeException("Each enabled system bar must have a unique bar type. Check "
+ + "the configuration in config.xml");
+ }
+ }
+
+ private void setInsetPaddingsForOverlappingCorners() {
+ setInsetPaddingForOverlappingCorner(TOP, LEFT);
+ setInsetPaddingForOverlappingCorner(TOP, RIGHT);
+ setInsetPaddingForOverlappingCorner(BOTTOM, LEFT);
+ setInsetPaddingForOverlappingCorner(BOTTOM, RIGHT);
+ }
+
+ private void setInsetPaddingForOverlappingCorner(@SystemBarSide int horizontalSide,
+ @SystemBarSide int verticalSide) {
+
+ if (isVerticalBar(horizontalSide) || isHorizontalBar(verticalSide)) {
+ Log.w(TAG, "configureBarPaddings: Returning immediately since the horizontal and "
+ + "vertical sides were not provided correctly.");
+ return;
+ }
+
+ SystemBarConfig horizontalBarConfig = mSystemBarConfigMap.get(horizontalSide);
+ SystemBarConfig verticalBarConfig = mSystemBarConfigMap.get(verticalSide);
+
+ if (verticalBarConfig != null && horizontalBarConfig != null) {
+ int horizontalBarZOrder = horizontalBarConfig.getZOrder();
+ int horizontalBarGirth = horizontalBarConfig.getGirth();
+ int verticalBarZOrder = verticalBarConfig.getZOrder();
+ int verticalBarGirth = verticalBarConfig.getGirth();
+
+ if (horizontalBarZOrder > verticalBarZOrder) {
+ verticalBarConfig.setPaddingBySide(horizontalSide, horizontalBarGirth);
+ } else if (horizontalBarZOrder < verticalBarZOrder) {
+ horizontalBarConfig.setPaddingBySide(verticalSide, verticalBarGirth);
+ } else {
+ throw new RuntimeException(
+ BAR_TITLE_MAP.get(horizontalSide) + " " + BAR_TITLE_MAP.get(verticalSide)
+ + " have the same Z-Order, and so their placing order cannot be "
+ + "determined. Determine which bar should be placed on top of the "
+ + "other bar and change the Z-order in config.xml accordingly."
+ );
+ }
+ }
+ }
+
+ private void sortSystemBarSidesByZOrder() {
+ List<SystemBarConfig> systemBarsByZOrder = new ArrayList<>(mSystemBarConfigMap.values());
+
+ systemBarsByZOrder.sort(new Comparator<SystemBarConfig>() {
+ @Override
+ public int compare(SystemBarConfig o1, SystemBarConfig o2) {
+ return o1.getZOrder() - o2.getZOrder();
+ }
+ });
+
+ systemBarsByZOrder.forEach(systemBarConfig -> {
+ mSystemBarSidesByZOrder.add(systemBarConfig.getSide());
+ });
+ }
+
+ private static boolean isHorizontalBar(@SystemBarSide int side) {
+ return side == TOP || side == BOTTOM;
+ }
+
+ private static boolean isVerticalBar(@SystemBarSide int side) {
+ return side == LEFT || side == RIGHT;
+ }
+
+ private static final class SystemBarConfig {
+ private final int mSide;
+ private final int mBarType;
+ private final int mGirth;
+ private final int mZOrder;
+
+ private int[] mPaddings = new int[]{0, 0, 0, 0};
+
+ private SystemBarConfig(@SystemBarSide int side, int barType, int girth, int zOrder) {
+ mSide = side;
+ mBarType = barType;
+ mGirth = girth;
+ mZOrder = zOrder;
+ }
+
+ private int getSide() {
+ return mSide;
+ }
+
+ private int getBarType() {
+ return mBarType;
+ }
+
+ private int getGirth() {
+ return mGirth;
+ }
+
+ private int getZOrder() {
+ return mZOrder;
+ }
+
+ private int[] getPaddings() {
+ return mPaddings;
+ }
+
+ private WindowManager.LayoutParams getLayoutParams() {
+ WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
+ isHorizontalBar(mSide) ? ViewGroup.LayoutParams.MATCH_PARENT : mGirth,
+ isHorizontalBar(mSide) ? mGirth : ViewGroup.LayoutParams.MATCH_PARENT,
+ mapZOrderToBarType(mZOrder),
+ WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+ | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
+ | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
+ | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
+ PixelFormat.TRANSLUCENT);
+ lp.setTitle(BAR_TITLE_MAP.get(mSide));
+ lp.providesInsetsTypes = new int[]{BAR_TYPE_MAP[mBarType], BAR_GESTURE_MAP.get(mSide)};
+ lp.setFitInsetsTypes(0);
+ lp.windowAnimations = 0;
+ lp.gravity = BAR_GRAVITY_MAP.get(mSide);
+ return lp;
+ }
+
+ private int mapZOrderToBarType(int zOrder) {
+ return zOrder >= HUN_ZORDER ? WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL
+ : WindowManager.LayoutParams.TYPE_STATUS_BAR_ADDITIONAL;
+ }
+
+ private void setPaddingBySide(@SystemBarSide int side, int padding) {
+ mPaddings[side] = padding;
+ }
+ }
+
+ private static final class SystemBarConfigBuilder {
+ private int mSide;
+ private int mBarType;
+ private int mGirth;
+ private int mZOrder;
+
+ private SystemBarConfigBuilder setSide(@SystemBarSide int side) {
+ mSide = side;
+ return this;
+ }
+
+ private SystemBarConfigBuilder setBarType(int type) {
+ mBarType = type;
+ return this;
+ }
+
+ private SystemBarConfigBuilder setGirth(int girth) {
+ mGirth = girth;
+ return this;
+ }
+
+ private SystemBarConfigBuilder setZOrder(int zOrder) {
+ mZOrder = zOrder;
+ return this;
+ }
+
+ private SystemBarConfig build() {
+ return new SystemBarConfig(mSide, mBarType, mGirth, mZOrder);
+ }
+ }
+}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/UserGridRecyclerView.java b/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/UserGridRecyclerView.java
index d0a2aebdb80a..5bd8797c5349 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/UserGridRecyclerView.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/UserGridRecyclerView.java
@@ -33,6 +33,7 @@ import android.car.user.CarUserManager;
import android.car.user.UserCreationResult;
import android.car.user.UserSwitchResult;
import android.car.userlib.UserHelper;
+import android.car.util.concurrent.AsyncFuture;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
@@ -60,7 +61,6 @@ import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
-import com.android.internal.infra.AndroidFuture;
import com.android.internal.util.UserIcons;
import com.android.systemui.R;
@@ -449,7 +449,7 @@ public class UserGridRecyclerView extends RecyclerView {
*/
@Nullable
public UserInfo createNewOrFindExistingGuest(Context context) {
- AndroidFuture<UserCreationResult> future = mCarUserManager.createGuest(mGuestName);
+ AsyncFuture<UserCreationResult> future = mCarUserManager.createGuest(mGuestName);
// CreateGuest will return null if a guest already exists.
UserInfo newGuest = getUserInfo(future);
if (newGuest != null) {
@@ -482,7 +482,7 @@ public class UserGridRecyclerView extends RecyclerView {
}
@Nullable
- private UserInfo getUserInfo(AndroidFuture<UserCreationResult> future) {
+ private UserInfo getUserInfo(AsyncFuture<UserCreationResult> future) {
UserCreationResult userCreationResult;
try {
userCreationResult = future.get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
@@ -504,7 +504,7 @@ public class UserGridRecyclerView extends RecyclerView {
}
private boolean switchUser(@UserIdInt int userId) {
- AndroidFuture<UserSwitchResult> userSwitchResultFuture =
+ AsyncFuture<UserSwitchResult> userSwitchResultFuture =
mCarUserManager.switchUser(userId);
UserSwitchResult userSwitchResult;
try {
@@ -531,7 +531,7 @@ public class UserGridRecyclerView extends RecyclerView {
@Override
protected UserInfo doInBackground(String... userNames) {
- AndroidFuture<UserCreationResult> future = mCarUserManager.createUser(userNames[0],
+ AsyncFuture<UserCreationResult> future = mCarUserManager.createUser(userNames[0],
/* flags= */ 0);
try {
UserInfo user = getUserInfo(future);
diff --git a/packages/CarSystemUI/src/com/android/systemui/wm/DisplaySystemBarsController.java b/packages/CarSystemUI/src/com/android/systemui/wm/DisplaySystemBarsController.java
index 5c80202ba592..e493c97a9b46 100644
--- a/packages/CarSystemUI/src/com/android/systemui/wm/DisplaySystemBarsController.java
+++ b/packages/CarSystemUI/src/com/android/systemui/wm/DisplaySystemBarsController.java
@@ -36,25 +36,20 @@ import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.DisplayImeController;
import com.android.wm.shell.common.TransactionPool;
-import javax.inject.Inject;
-import javax.inject.Singleton;
-
/**
* Controller that maps between displays and {@link IDisplayWindowInsetsController} in order to
* give system bar control to SystemUI.
* {@link R.bool#config_remoteInsetsControllerControlsSystemBars} determines whether this controller
* takes control or not.
*/
-@Singleton
public class DisplaySystemBarsController extends DisplayImeController {
private static final String TAG = "DisplaySystemBarsController";
- private SparseArray<PerDisplay> mPerDisplaySparseArray;
private final Context mContext;
+ private SparseArray<PerDisplay> mPerDisplaySparseArray;
- @Inject
- public DisplaySystemBarsController(
+ private DisplaySystemBarsController(
Context context,
IWindowManager wmService,
DisplayController displayController,
@@ -172,4 +167,33 @@ public class DisplaySystemBarsController extends DisplayImeController {
}
}
}
+
+ /** Builds {@link DisplaySystemBarsController} instance. */
+ public static class Builder {
+ private Context mContext;
+ private IWindowManager mWmService;
+ private DisplayController mDisplayController;
+ private Handler mHandler;
+ private TransactionPool mTransactionPool;
+
+ public Builder(Context context, IWindowManager wmService,
+ DisplayController displayController, Handler handler,
+ TransactionPool transactionPool) {
+ mContext = context;
+ mWmService = wmService;
+ mDisplayController = displayController;
+ mHandler = handler;
+ mTransactionPool = transactionPool;
+ }
+
+ /** Builds and initializes {@link DisplaySystemBarsController} instance. */
+ public DisplaySystemBarsController build() {
+ DisplaySystemBarsController displaySystemBarsController =
+ new DisplaySystemBarsController(
+ mContext, mWmService, mDisplayController, mHandler, mTransactionPool);
+ // Separates startMonitorDisplays from constructor to prevent circular init issue.
+ displaySystemBarsController.startMonitorDisplays();
+ return displaySystemBarsController;
+ }
+ }
}
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationBarControllerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationBarControllerTest.java
index dec8b8ecdfb4..0b164a2e1a51 100644
--- a/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationBarControllerTest.java
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationBarControllerTest.java
@@ -73,7 +73,8 @@ public class CarNavigationBarControllerTest extends SysuiTestCase {
private CarNavigationBarController createNavigationBarController() {
return new CarNavigationBarController(mContext, mNavigationBarViewFactory,
mButtonSelectionStateController, () -> mHvacController,
- mButtonRoleHolderController);
+ mButtonRoleHolderController,
+ new SystemBarConfigs(mTestableResources.getResources()));
}
@Test
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationBarTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationBarTest.java
index d9edfa960858..2b5af71dccaa 100644
--- a/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationBarTest.java
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationBarTest.java
@@ -142,7 +142,7 @@ public class CarNavigationBarTest extends SysuiTestCase {
mWindowManager, mDeviceProvisionedController, new CommandQueue(mContext),
mAutoHideController, mButtonSelectionStateListener, mHandler, mUiBgExecutor,
mBarService, () -> mKeyguardStateController, () -> mIconPolicy,
- () -> mIconController);
+ () -> mIconController, new SystemBarConfigs(mTestableResources.getResources()));
}
@Test
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/SystemBarConfigsTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/SystemBarConfigsTest.java
new file mode 100644
index 000000000000..8b1589913d1d
--- /dev/null
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/SystemBarConfigsTest.java
@@ -0,0 +1,162 @@
+/*
+ * 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.car.navigationbar;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.when;
+
+import android.content.res.Resources;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.view.WindowManager;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.R;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.car.CarSystemUiTest;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@CarSystemUiTest
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+@SmallTest
+public class SystemBarConfigsTest extends SysuiTestCase {
+
+ private SystemBarConfigs mSystemBarConfigs;
+ @Mock
+ private Resources mResources;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ setDefaultValidConfig();
+ }
+
+ @Test
+ public void onInit_allSystemBarsEnabled_eachHasUniqueBarTypes_doesNotThrowException() {
+ mSystemBarConfigs = new SystemBarConfigs(mResources);
+ }
+
+ @Test(expected = RuntimeException.class)
+ public void onInit_allSystemBarsEnabled_twoBarsHaveDuplicateType_throwsRuntimeException() {
+ when(mResources.getInteger(R.integer.config_topSystemBarType)).thenReturn(0);
+ when(mResources.getInteger(R.integer.config_bottomSystemBarType)).thenReturn(0);
+
+ mSystemBarConfigs = new SystemBarConfigs(mResources);
+ }
+
+ @Test
+ public void onInit_allSystemBarsEnabled_systemBarSidesSortedByZOrder() {
+ mSystemBarConfigs = new SystemBarConfigs(mResources);
+ List<Integer> actualOrder = mSystemBarConfigs.getSystemBarSidesByZOrder();
+ List<Integer> expectedOrder = new ArrayList<>();
+ expectedOrder.add(SystemBarConfigs.LEFT);
+ expectedOrder.add(SystemBarConfigs.RIGHT);
+ expectedOrder.add(SystemBarConfigs.TOP);
+ expectedOrder.add(SystemBarConfigs.BOTTOM);
+
+ assertTrue(actualOrder.equals(expectedOrder));
+ }
+
+ @Test(expected = RuntimeException.class)
+ public void onInit_intersectingBarsHaveSameZOrder_throwsRuntimeException() {
+ when(mResources.getInteger(R.integer.config_topSystemBarZOrder)).thenReturn(33);
+ when(mResources.getInteger(R.integer.config_leftSystemBarZOrder)).thenReturn(33);
+
+ mSystemBarConfigs = new SystemBarConfigs(mResources);
+ }
+
+ @Test
+ public void getTopSystemBarLayoutParams_topBarEnabled_returnsTopSystemBarLayoutParams() {
+ mSystemBarConfigs = new SystemBarConfigs(mResources);
+ WindowManager.LayoutParams lp = mSystemBarConfigs.getLayoutParamsBySide(
+ SystemBarConfigs.TOP);
+
+ assertNotNull(lp);
+ }
+
+ @Test
+ public void getTopSystemBarLayoutParams_topBarNotEnabled_returnsNull() {
+ when(mResources.getBoolean(R.bool.config_enableTopNavigationBar)).thenReturn(false);
+ mSystemBarConfigs = new SystemBarConfigs(mResources);
+ WindowManager.LayoutParams lp = mSystemBarConfigs.getLayoutParamsBySide(
+ SystemBarConfigs.TOP);
+
+ assertNull(lp);
+ }
+
+ @Test
+ public void topSystemBarHasHigherZOrderThanHuns_topSystemBarIsNavigationBarPanelType() {
+ when(mResources.getInteger(R.integer.config_topSystemBarZOrder)).thenReturn(
+ SystemBarConfigs.getHunZOrder() + 1);
+ mSystemBarConfigs = new SystemBarConfigs(mResources);
+ WindowManager.LayoutParams lp = mSystemBarConfigs.getLayoutParamsBySide(
+ SystemBarConfigs.TOP);
+
+ assertEquals(lp.type, WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL);
+ }
+
+ @Test
+ public void topSystemBarHasLowerZOrderThanHuns_topSystemBarIsStatusBarAdditionalType() {
+ when(mResources.getInteger(R.integer.config_topSystemBarZOrder)).thenReturn(
+ SystemBarConfigs.getHunZOrder() - 1);
+ mSystemBarConfigs = new SystemBarConfigs(mResources);
+ WindowManager.LayoutParams lp = mSystemBarConfigs.getLayoutParamsBySide(
+ SystemBarConfigs.TOP);
+
+ assertEquals(lp.type, WindowManager.LayoutParams.TYPE_STATUS_BAR_ADDITIONAL);
+ }
+
+ // Set valid config where all system bars are enabled.
+ private void setDefaultValidConfig() {
+ when(mResources.getBoolean(R.bool.config_enableTopNavigationBar)).thenReturn(true);
+ when(mResources.getBoolean(R.bool.config_enableBottomNavigationBar)).thenReturn(true);
+ when(mResources.getBoolean(R.bool.config_enableLeftNavigationBar)).thenReturn(true);
+ when(mResources.getBoolean(R.bool.config_enableRightNavigationBar)).thenReturn(true);
+
+ when(mResources.getDimensionPixelSize(
+ com.android.internal.R.dimen.status_bar_height)).thenReturn(100);
+ when(mResources.getDimensionPixelSize(
+ com.android.internal.R.dimen.navigation_bar_height)).thenReturn(100);
+ when(mResources.getDimensionPixelSize(R.dimen.car_left_navigation_bar_width)).thenReturn(
+ 100);
+ when(mResources.getDimensionPixelSize(R.dimen.car_right_navigation_bar_width)).thenReturn(
+ 100);
+
+ when(mResources.getInteger(R.integer.config_topSystemBarType)).thenReturn(0);
+ when(mResources.getInteger(R.integer.config_bottomSystemBarType)).thenReturn(1);
+ when(mResources.getInteger(R.integer.config_leftSystemBarType)).thenReturn(2);
+ when(mResources.getInteger(R.integer.config_rightSystemBarType)).thenReturn(3);
+
+ when(mResources.getInteger(R.integer.config_topSystemBarZOrder)).thenReturn(5);
+ when(mResources.getInteger(R.integer.config_bottomSystemBarZOrder)).thenReturn(10);
+ when(mResources.getInteger(R.integer.config_leftSystemBarZOrder)).thenReturn(2);
+ when(mResources.getInteger(R.integer.config_rightSystemBarZOrder)).thenReturn(3);
+ }
+}
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/wm/DisplaySystemBarsControllerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/wm/DisplaySystemBarsControllerTest.java
index 391f75e35382..b65578dbe02c 100644
--- a/packages/CarSystemUI/tests/src/com/android/systemui/wm/DisplaySystemBarsControllerTest.java
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/wm/DisplaySystemBarsControllerTest.java
@@ -64,13 +64,13 @@ public class DisplaySystemBarsControllerTest extends SysuiTestCase {
public void setUp() {
MockitoAnnotations.initMocks(this);
- mController = new DisplaySystemBarsController(
+ mController = new DisplaySystemBarsController.Builder(
mContext,
mIWindowManager,
mDisplayController,
mHandler,
mTransactionPool
- );
+ ).build();
}
@Test
diff --git a/packages/DynamicSystemInstallationService/tests/res/values/strings.xml b/packages/DynamicSystemInstallationService/tests/res/values/strings.xml
index fdb620bfe094..019c0c914771 100644
--- a/packages/DynamicSystemInstallationService/tests/res/values/strings.xml
+++ b/packages/DynamicSystemInstallationService/tests/res/values/strings.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- testFromJsonString -->
- <string name="blacklist_json_string" translatable="false">
+ <string name="blocklist_json_string" translatable="false">
{
\"entries\":[
{
diff --git a/packages/DynamicSystemInstallationService/tests/src/com/android/dynsystem/KeyRevocationListTest.java b/packages/DynamicSystemInstallationService/tests/src/com/android/dynsystem/KeyRevocationListTest.java
index 82ce542cf5de..c1233ebab2ec 100644
--- a/packages/DynamicSystemInstallationService/tests/src/com/android/dynsystem/KeyRevocationListTest.java
+++ b/packages/DynamicSystemInstallationService/tests/src/com/android/dynsystem/KeyRevocationListTest.java
@@ -47,32 +47,32 @@ public class KeyRevocationListTest {
private static Context sContext;
- private static String sBlacklistJsonString;
+ private static String sBlocklistJsonString;
@BeforeClass
public static void setUpClass() throws Exception {
sContext = InstrumentationRegistry.getInstrumentation().getContext();
- sBlacklistJsonString =
- sContext.getString(com.android.dynsystem.tests.R.string.blacklist_json_string);
+ sBlocklistJsonString =
+ sContext.getString(com.android.dynsystem.tests.R.string.blocklist_json_string);
}
@Test
@SmallTest
public void testFromJsonString() throws JSONException {
- KeyRevocationList blacklist;
- blacklist = KeyRevocationList.fromJsonString(sBlacklistJsonString);
- Assert.assertNotNull(blacklist);
- Assert.assertFalse(blacklist.mEntries.isEmpty());
- blacklist = KeyRevocationList.fromJsonString("{}");
- Assert.assertNotNull(blacklist);
- Assert.assertTrue(blacklist.mEntries.isEmpty());
+ KeyRevocationList blocklist;
+ blocklist = KeyRevocationList.fromJsonString(sBlocklistJsonString);
+ Assert.assertNotNull(blocklist);
+ Assert.assertFalse(blocklist.mEntries.isEmpty());
+ blocklist = KeyRevocationList.fromJsonString("{}");
+ Assert.assertNotNull(blocklist);
+ Assert.assertTrue(blocklist.mEntries.isEmpty());
}
@Test
@SmallTest
public void testFromUrl() throws IOException, JSONException {
URLConnection mockConnection = mock(URLConnection.class);
- doReturn(new ByteArrayInputStream(sBlacklistJsonString.getBytes()))
+ doReturn(new ByteArrayInputStream(sBlocklistJsonString.getBytes()))
.when(mockConnection).getInputStream();
URL mockUrl = new URL(
"http", // protocol
@@ -97,36 +97,36 @@ public class KeyRevocationListTest {
}
});
- KeyRevocationList blacklist = KeyRevocationList.fromUrl(mockUrl);
- Assert.assertNotNull(blacklist);
- Assert.assertFalse(blacklist.mEntries.isEmpty());
+ KeyRevocationList blocklist = KeyRevocationList.fromUrl(mockUrl);
+ Assert.assertNotNull(blocklist);
+ Assert.assertFalse(blocklist.mEntries.isEmpty());
- blacklist = null;
+ blocklist = null;
try {
- blacklist = KeyRevocationList.fromUrl(mockBadUrl);
+ blocklist = KeyRevocationList.fromUrl(mockBadUrl);
// Up should throw, down should be unreachable
Assert.fail("Expected IOException not thrown");
} catch (IOException e) {
// This is expected, do nothing
}
- Assert.assertNull(blacklist);
+ Assert.assertNull(blocklist);
}
@Test
@SmallTest
public void testIsRevoked() {
- KeyRevocationList blacklist = new KeyRevocationList();
- blacklist.addEntry("key1", "REVOKED", "reason for key1");
+ KeyRevocationList blocklist = new KeyRevocationList();
+ blocklist.addEntry("key1", "REVOKED", "reason for key1");
KeyRevocationList.RevocationStatus revocationStatus =
- blacklist.getRevocationStatusForKey("key1");
+ blocklist.getRevocationStatusForKey("key1");
Assert.assertNotNull(revocationStatus);
Assert.assertEquals(revocationStatus.mReason, "reason for key1");
- revocationStatus = blacklist.getRevocationStatusForKey("key2");
+ revocationStatus = blocklist.getRevocationStatusForKey("key2");
Assert.assertNull(revocationStatus);
- Assert.assertTrue(blacklist.isRevoked("key1"));
- Assert.assertFalse(blacklist.isRevoked("key2"));
+ Assert.assertTrue(blocklist.isRevoked("key1"));
+ Assert.assertFalse(blocklist.isRevoked("key2"));
}
}
diff --git a/packages/SettingsLib/res/values-be/strings.xml b/packages/SettingsLib/res/values-be/strings.xml
index 1b5062efa23e..01d7682416fa 100644
--- a/packages/SettingsLib/res/values-be/strings.xml
+++ b/packages/SettingsLib/res/values-be/strings.xml
@@ -42,10 +42,10 @@
<string name="connected_via_app" msgid="3532267661404276584">"Падключана праз праграму \"<xliff:g id="NAME">%1$s</xliff:g>\""</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"Даступна праз %1$s"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"Націсніце, каб зарэгістравацца"</string>
- <string name="wifi_connected_no_internet" msgid="5087420713443350646">"Не падключана да інтэрнэту"</string>
+ <string name="wifi_connected_no_internet" msgid="5087420713443350646">"Няма падключэння да інтэрнэту"</string>
<string name="private_dns_broken" msgid="1984159464346556931">"Не ўдалося атрымаць доступ да прыватнага DNS-сервера"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Абмежаваныя магчымасці падключэння"</string>
- <string name="wifi_status_no_internet" msgid="3799933875988829048">"Не падключана да інтэрнэту"</string>
+ <string name="wifi_status_no_internet" msgid="3799933875988829048">"Няма падключэння да інтэрнэту"</string>
<string name="wifi_status_sign_in_required" msgid="2236267500459526855">"Трэба выканаць уваход"</string>
<string name="wifi_ap_unable_to_handle_new_sta" msgid="5885145407184194503">"Пункт доступу часова заняты"</string>
<string name="connected_via_carrier" msgid="1968057009076191514">"Падключана праз %1$s"</string>
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 8e8368f9bc62..03161d051342 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -659,9 +659,6 @@
<!-- Setting Checkbox title for enabling Bluetooth Gabeldorsche. [CHAR LIMIT=40] -->
<string name="bluetooth_enable_gabeldorsche">Enable Gabeldorsche</string>
- <!-- Setting Checkbox title for enabling Enhanced Connectivity [CHAR LIMIT=80] -->
- <string name="enhanced_connectivity">Enhanced Connectivity</string>
-
<!-- UI debug setting: Select Bluetooth AVRCP Version -->
<string name="bluetooth_select_avrcp_version_string">Bluetooth AVRCP Version</string>
<!-- UI debug setting: Select Bluetooth AVRCP Version -->
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index ef3bdbc95809..df0137d8179e 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -785,14 +785,14 @@ class SettingsProtoDumpUtil {
Settings.Global.GAME_DRIVER_OPT_OUT_APPS,
GlobalSettingsProto.Gpu.GAME_DRIVER_OPT_OUT_APPS);
dumpSetting(s, p,
- Settings.Global.GAME_DRIVER_BLACKLIST,
- GlobalSettingsProto.Gpu.GAME_DRIVER_BLACKLIST);
+ Settings.Global.GAME_DRIVER_DENYLIST,
+ GlobalSettingsProto.Gpu.GAME_DRIVER_DENYLIST);
dumpSetting(s, p,
- Settings.Global.GAME_DRIVER_WHITELIST,
- GlobalSettingsProto.Gpu.GAME_DRIVER_WHITELIST);
+ Settings.Global.GAME_DRIVER_ALLOWLIST,
+ GlobalSettingsProto.Gpu.GAME_DRIVER_ALLOWLIST);
dumpSetting(s, p,
- Settings.Global.GAME_DRIVER_BLACKLISTS,
- GlobalSettingsProto.Gpu.GAME_DRIVER_BLACKLISTS);
+ Settings.Global.GAME_DRIVER_DENYLISTS,
+ GlobalSettingsProto.Gpu.GAME_DRIVER_DENYLISTS);
dumpSetting(s, p,
Settings.Global.GAME_DRIVER_SPHAL_LIBRARIES,
GlobalSettingsProto.Gpu.GAME_DRIVER_SPHAL_LIBRARIES);
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/WriteFallbackSettingsFilesJobService.java b/packages/SettingsProvider/src/com/android/providers/settings/WriteFallbackSettingsFilesJobService.java
index 6e5b8890438d..66aa7baa3b51 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/WriteFallbackSettingsFilesJobService.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/WriteFallbackSettingsFilesJobService.java
@@ -35,19 +35,17 @@ import java.util.List;
public class WriteFallbackSettingsFilesJobService extends JobService {
@Override
public boolean onStartJob(final JobParameters params) {
- switch (params.getJobId()) {
- case WRITE_FALLBACK_SETTINGS_FILES_JOB_ID:
- final List<String> settingsFiles = new ArrayList<>();
- settingsFiles.add(params.getExtras().getString(TABLE_GLOBAL, ""));
- settingsFiles.add(params.getExtras().getString(TABLE_SYSTEM, ""));
- settingsFiles.add(params.getExtras().getString(TABLE_SECURE, ""));
- settingsFiles.add(params.getExtras().getString(TABLE_SSAID, ""));
- settingsFiles.add(params.getExtras().getString(TABLE_CONFIG, ""));
- SettingsProvider.writeFallBackSettingsFiles(settingsFiles);
- return true;
- default:
- return false;
+ if (params.getJobId() != WRITE_FALLBACK_SETTINGS_FILES_JOB_ID) {
+ return false;
}
+ final List<String> settingsFiles = new ArrayList<>();
+ settingsFiles.add(params.getExtras().getString(TABLE_GLOBAL, ""));
+ settingsFiles.add(params.getExtras().getString(TABLE_SYSTEM, ""));
+ settingsFiles.add(params.getExtras().getString(TABLE_SECURE, ""));
+ settingsFiles.add(params.getExtras().getString(TABLE_SSAID, ""));
+ settingsFiles.add(params.getExtras().getString(TABLE_CONFIG, ""));
+ SettingsProvider.writeFallBackSettingsFiles(settingsFiles);
+ return false;
}
@Override
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index 6914f0a1e33a..e49fd6f92933 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -270,7 +270,6 @@ public class SettingsBackupTest {
Settings.Global.SMART_REPLIES_IN_NOTIFICATIONS_FLAGS,
Settings.Global.SMART_SUGGESTIONS_IN_NOTIFICATIONS_FLAGS,
Settings.Global.ENABLE_ADB_INCREMENTAL_INSTALL_DEFAULT,
- Settings.Global.ENHANCED_CONNECTIVITY_ENABLED,
Settings.Global.ENHANCED_4G_MODE_ENABLED,
Settings.Global.EPHEMERAL_COOKIE_MAX_SIZE_BYTES,
Settings.Global.ERROR_LOGCAT_PREFIX,
@@ -297,6 +296,7 @@ public class SettingsBackupTest {
Settings.Global.HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED,
Settings.Global.HDMI_CONTROL_AUTO_WAKEUP_ENABLED,
Settings.Global.HDMI_CONTROL_ENABLED,
+ Settings.Global.HDMI_CONTROL_SEND_STANDBY_ON_SLEEP,
Settings.Global.HDMI_CONTROL_VOLUME_CONTROL_ENABLED,
Settings.Global.HDMI_SYSTEM_AUDIO_CONTROL_ENABLED,
Settings.Global.HEADS_UP_NOTIFICATIONS_ENABLED,
@@ -507,9 +507,9 @@ public class SettingsBackupTest {
Settings.Global.GAME_DRIVER_OPT_IN_APPS,
Settings.Global.GAME_DRIVER_PRERELEASE_OPT_IN_APPS,
Settings.Global.GAME_DRIVER_OPT_OUT_APPS,
- Settings.Global.GAME_DRIVER_BLACKLISTS,
- Settings.Global.GAME_DRIVER_BLACKLIST,
- Settings.Global.GAME_DRIVER_WHITELIST,
+ Settings.Global.GAME_DRIVER_DENYLISTS,
+ Settings.Global.GAME_DRIVER_DENYLIST,
+ Settings.Global.GAME_DRIVER_ALLOWLIST,
Settings.Global.GAME_DRIVER_SPHAL_LIBRARIES,
Settings.Global.GLOBAL_SETTINGS_SHOW_ANGLE_IN_USE_DIALOG_BOX,
Settings.Global.GPU_DEBUG_LAYER_APP,
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 8253c5e642f3..aa960875ec6f 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -324,6 +324,14 @@
<uses-permission android:name="android.car.permission.CAR_DRIVING_STATE" />
<!-- Permissions required for ATS tests - AtsDeviceInfo, AtsAudioDeviceTestCases -->
<uses-permission android:name="android.car.permission.CAR_CONTROL_AUDIO_VOLUME" />
+ <!-- Permissions required for ATS tests - AtsDeviceInfo -->
+ <uses-permission android:name="android.car.permission.CAR_DIAGNOSTICS" />
+ <!-- Permissions required for ATS tests - AtsDeviceInfo -->
+ <uses-permission android:name="android.car.permission.CLEAR_CAR_DIAGNOSTICS" />
+ <!-- Permissions required for ATS tests - AtsCarHostTestCases -->
+ <uses-permission android:name="android.car.permission.CONTROL_APP_BLOCKING" />
+ <!-- Permissions required for ATS tests - AtsCarHostTestCases -->
+ <uses-permission android:name="android.car.permission.CAR_UX_RESTRICTIONS_CONFIGURATION" />
<application android:label="@string/app_label"
android:theme="@android:style/Theme.DeviceDefault.DayNight"
diff --git a/packages/SimAppDialog/Android.bp b/packages/SimAppDialog/Android.bp
index ff26710fa2e1..176035f73b65 100644
--- a/packages/SimAppDialog/Android.bp
+++ b/packages/SimAppDialog/Android.bp
@@ -4,7 +4,6 @@ android_app {
srcs: ["src/**/*.java"],
platform_apis: true,
- certificate: "platform",
static_libs: [
"androidx.legacy_legacy-support-v4",
diff --git a/packages/SystemUI/docs/dagger.md b/packages/SystemUI/docs/dagger.md
index bb68647ceb00..89170139e21c 100644
--- a/packages/SystemUI/docs/dagger.md
+++ b/packages/SystemUI/docs/dagger.md
@@ -41,8 +41,6 @@ public interface SystemUIRootComponent {
The root component is composed of root modules, which in turn provide the global singleton
dependencies across all of SystemUI.
-- `ContextHolder` is just a wrapper that provides a context.
-
- `SystemUIFactory` `@Provides` dependencies that need to be overridden by SystemUI
variants (like other form factors e.g. Car).
@@ -52,41 +50,8 @@ variants (like other form factors e.g. Car).
### Adding injection to a new SystemUI object
-Anything that depends on any `@Singleton` provider from SystemUIRootComponent
-should be declared as a `@Subcomponent` of the root component. This requires
-declaring your own interface for generating your own modules or just the
-object you need injected. The subcomponent also needs to be added to
-SystemUIRootComponent in SystemUIFactory so it can be acquired.
-
-```java
-public interface SystemUIRootComponent {
-+ @Singleton
-+ Dependency.DependencyInjector createDependency();
-}
-
-public class Dependency extends SystemUI {
- //...
-+ @Subcomponent
-+ public interface DependencyInjector {
-+ Dependency createSystemUI();
-+ }
-}
-```
-
-For objects which extend SystemUI and require injection, you can define an
-injector that creates the injected object for you. This other class should
-be referenced in [@string/config_systemUIServiceComponents](packages/SystemUI/res/values/config.xml).
-
-```java
-public static class DependencyCreator implements Injector {
- @Override
- public SystemUI apply(Context context) {
- return SystemUIFactory.getInstance().getRootComponent()
- .createDependency()
- .createSystemUI();
- }
-}
-```
+SystemUI object are made injectable by adding an entry in `SystemUIBinder`. SystemUIApplication uses
+information in that file to locate and construct an instance of the requested SystemUI class.
### Adding a new injectable object
@@ -147,7 +112,7 @@ whenever your fragment needs to be created.
```java
public interface FragmentCreator {
-+ NavigationBarFragment createNavigationBar();
+ NavigationBarFragment createNavigationBar();
}
```
@@ -160,49 +125,17 @@ FragmentHostManager.get(view).create(NavigationBarFragment.class);
### Using injection with Views
-Generally, you shouldn't need to inject for a view, as the view should
-be relatively self contained and logic that requires injection should be
-moved to a higher level construct such as a Fragment or a top-level SystemUI
-component, see above for how to do injection for both of which.
+DO NOT ADD NEW VIEW INJECTION. VIEW INJECTION IS BEING ACTIVELY DEPRECATED.
-Still here? Yeah, ok, sysui has a lot of pre-existing views that contain a
-lot of code that could benefit from injection and will need to be migrated
-off from Dependency#get uses. Similar to how fragments are injected, the view
-needs to be added to the interface
-com.android.systemui.util.InjectionInflationController$ViewInstanceCreator.
+Needing to inject objects into your View's constructor generally implies you
+are doing more work in your presentation layer than is advisable.
+Instead, create an injected controller for you view, inject into the
+controller, and then attach the view to the controller after inflation.
-```java
-public interface ViewInstanceCreator {
-+ QuickStatusBarHeader createQsHeader();
-}
-```
-
-Presumably you need to inflate that view from XML (otherwise why do you
-need anything special? see earlier sections about generic injection). To obtain
-an inflater that supports injected objects, call InjectionInflationController#injectable,
-which will wrap the inflater it is passed in one that can create injected
-objects when needed.
-
-```java
-@Override
-public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
- Bundle savedInstanceState) {
- return mInjectionInflater.injectable(inflater).inflate(R.layout.my_layout, container, false);
-}
-```
-
-There is one other important thing to note about injecting with views. SysUI
-already has a Context in its global dagger component, so if you simply inject
-a Context, you will not get the one that the view should have with proper
-theming. Because of this, always ensure to tag views that have @Inject with
-the @Named view context.
-
-```java
-public CustomView(@Named(VIEW_CONTEXT) Context themedViewContext, AttributeSet attrs,
- OtherCustomDependency something) {
- //...
-}
-```
+View injection generally causes headaches while testing, as inflating a view
+(which may in turn inflate other views) implicitly causes a Dagger graph to
+be stood up, which may or may not contain the appropriately
+faked/mocked/stubbed objects. It is a hard to control process.
## Updating Dagger2
diff --git a/packages/SystemUI/res/drawable-hdpi/one_handed_tutorial.png b/packages/SystemUI/res/drawable-hdpi/one_handed_tutorial.png
new file mode 100644
index 000000000000..6c1f1cfdea7c
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/one_handed_tutorial.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/one_handed_tutorial.png b/packages/SystemUI/res/drawable-mdpi/one_handed_tutorial.png
new file mode 100644
index 000000000000..6983c3b880c9
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/one_handed_tutorial.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/one_handed_tutorial.png b/packages/SystemUI/res/drawable-xhdpi/one_handed_tutorial.png
new file mode 100644
index 000000000000..3ff692f0c6fc
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/one_handed_tutorial.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/one_handed_tutorial.png b/packages/SystemUI/res/drawable-xxhdpi/one_handed_tutorial.png
new file mode 100644
index 000000000000..75723fb2ea5a
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/one_handed_tutorial.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxxhdpi/one_handed_tutorial.png b/packages/SystemUI/res/drawable-xxxhdpi/one_handed_tutorial.png
new file mode 100644
index 000000000000..173abedae48a
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxxhdpi/one_handed_tutorial.png
Binary files differ
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index e48fe656d187..308fd88ee6cd 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"Instellings"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"Het dit"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Stort SysUI-hoop"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> gebruik tans jou <xliff:g id="TYPES_LIST">%2$s</xliff:g>."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Programme gebruik tans jou <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" en "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"kamera"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"ligging"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofoon"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Sensors is af"</string>
<string name="device_services" msgid="1549944177856658705">"Toesteldienste"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Titelloos"</string>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 300ca0e5b141..f2bf5778b42f 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"ቅንብሮች"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"ገባኝ"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"SysUI Heap አራግፍ"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> የእርስዎን <xliff:g id="TYPES_LIST">%2$s</xliff:g> እየተጠቀመ ነው።"</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"መተግበሪያዎች የእርስዎን <xliff:g id="TYPES_LIST">%s</xliff:g> እየተጠቀሙ ነው።"</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">"፣ "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" እና "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"ካሜራ"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"አካባቢ"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"ማይክሮፎን"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"ዳሳሾች ጠፍተዋል"</string>
<string name="device_services" msgid="1549944177856658705">"የመሣሪያ አገልግሎቶች"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"ርዕስ የለም"</string>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 7f2a405efed2..36280e716c4e 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -1005,6 +1005,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"الإعدادات"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"حسنًا"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"‏تفريغ ذاكرة SysUI"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"التطبيق <xliff:g id="APP">%1$s</xliff:g> يستخدم <xliff:g id="TYPES_LIST">%2$s</xliff:g>."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"تستخدم التطبيقات <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">"، "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" و "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"الكاميرا"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"الموقع"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"الميكروفون"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"إيقاف أجهزة الاستشعار"</string>
<string name="device_services" msgid="1549944177856658705">"خدمات الأجهزة"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"بلا عنوان"</string>
diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml
index 0345af07cd91..a4cc17b822d5 100644
--- a/packages/SystemUI/res/values-as/strings.xml
+++ b/packages/SystemUI/res/values-as/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"ছেটিংবোৰ"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"বুজি পালোঁ"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"SysUI হীপ ডাম্প কৰক"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g>এ আপোনাৰ <xliff:g id="TYPES_LIST">%2$s</xliff:g> ব্যৱহাৰ কৰি আছে।"</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"এপ্লিকেশ্বনসমূহে আপোনাৰ <xliff:g id="TYPES_LIST">%s</xliff:g> ব্যৱহাৰ কৰি আছে।"</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" আৰু "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"কেমেৰা"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"অৱস্থান"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"মাইক্ৰ\'ফ\'ন"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"ছেন্সৰ অফ হৈ আছে"</string>
<string name="device_services" msgid="1549944177856658705">"ডিভাইচ সেৱা"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"কোনো শিৰোনাম নাই"</string>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index d0025306d203..9443ba8ac22c 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"Ayarlar"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"Anladım"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="TYPES_LIST">%2$s</xliff:g> tətbiqlərindən istifadə edir."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Tətbiqlər <xliff:g id="TYPES_LIST">%s</xliff:g> istifadə edir."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" və "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"kamera"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"məkan"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofon"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Sensorlar deaktivdir"</string>
<string name="device_services" msgid="1549944177856658705">"Cihaz Xidmətləri"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Başlıq yoxdur"</string>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index 5cca958bbe96..5b8c44599eed 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -990,6 +990,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"Podešavanja"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"Važi"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Izdvoji SysUI mem."</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> koristi <xliff:g id="TYPES_LIST">%2$s</xliff:g>."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Aplikacije koriste <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" i "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"kameru"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"lokaciju"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofon"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Senzori su isključeni"</string>
<string name="device_services" msgid="1549944177856658705">"Usluge za uređaje"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Bez naslova"</string>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index 956ef477c927..6ee51682fe85 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -919,7 +919,7 @@
<string name="accessibility_quick_settings_collapse" msgid="4674876336725041982">"Закрыць хуткія налады."</string>
<string name="accessibility_quick_settings_alarm_set" msgid="7237918261045099853">"Будзільнік пастаўлены."</string>
<string name="accessibility_quick_settings_user" msgid="505821942882668619">"Вы ўвайшлі як <xliff:g id="ID_1">%s</xliff:g>"</string>
- <string name="data_connection_no_internet" msgid="691058178914184544">"Не падключана да інтэрнэту"</string>
+ <string name="data_connection_no_internet" msgid="691058178914184544">"Няма падключэння да інтэрнэту"</string>
<string name="accessibility_quick_settings_open_details" msgid="4879279912389052142">"Паказаць падрабязную інфармацыю."</string>
<string name="accessibility_quick_settings_not_available" msgid="6860875849497473854">"Прычына недаступнасці: <xliff:g id="REASON">%s</xliff:g>"</string>
<string name="accessibility_quick_settings_open_settings" msgid="536838345505030893">"Адкрыць налады <xliff:g id="ID_1">%s</xliff:g>."</string>
@@ -995,6 +995,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"Налады"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"Зразумела"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"Праграма \"<xliff:g id="APP">%1$s</xliff:g>\" выкарыстоўвае: <xliff:g id="TYPES_LIST">%2$s</xliff:g>."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Праграмы выкарыстоўваюць: <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" і "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"камера"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"геалакацыя"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"мікрафон"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Датчыкі выкл."</string>
<string name="device_services" msgid="1549944177856658705">"Сэрвісы прылады"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Без назвы"</string>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index d0836e4509fe..c7bb3d08579c 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"Настройки"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"Разбрах"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> използва <xliff:g id="TYPES_LIST">%2$s</xliff:g>."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Някои приложения използват <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" и "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"камерата"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"местополож."</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"микрофона"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Сензорите са изключени"</string>
<string name="device_services" msgid="1549944177856658705">"Услуги за устройството"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Няма заглавие"</string>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index a584955b534d..42e7523aef81 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"সেটিংস"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"বুঝেছি"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> আপনার <xliff:g id="TYPES_LIST">%2$s</xliff:g> ব্যবহার করছে।"</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"অ্যাপ্লিকেশনগুলি আপনার <xliff:g id="TYPES_LIST">%s</xliff:g> ব্যবহার করছে।"</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" এবং "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"ক্যামেরা"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"লোকেশন"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"মাইক্রোফোন"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"সেন্সর বন্ধ"</string>
<string name="device_services" msgid="1549944177856658705">"ডিভাইস সংক্রান্ত পরিষেবা"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"কোনও শীর্ষক নেই"</string>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index 4c872d22054f..16a1aa615c9b 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -990,6 +990,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"Postavke"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"Razumijem"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Izdvoji SysUI mem."</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> koristi <xliff:g id="TYPES_LIST">%2$s</xliff:g>."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Aplikacije koriste <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" i "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"kameru"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"lokaciju"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofon"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Senzori su isključeni"</string>
<string name="device_services" msgid="1549944177856658705">"Usluge uređaja"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Bez naslova"</string>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 7267c31b1f36..fdcec987f438 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"Configuració"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"Entesos"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Aboca espai de SysUI"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> està fent servir el següent: <xliff:g id="TYPES_LIST">%2$s</xliff:g>."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Algunes aplicacions estan fent servir el següent: <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" i "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"càmera"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"ubicació"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"micròfon"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Sensors desactivats"</string>
<string name="device_services" msgid="1549944177856658705">"Serveis per a dispositius"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Sense títol"</string>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 29b5281f689f..ab3b4fb2659c 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -995,6 +995,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"Nastavení"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"Rozumím"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Výpis haldy SysUI"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"Aplikace <xliff:g id="APP">%1$s</xliff:g> využívá tato oprávnění: <xliff:g id="TYPES_LIST">%2$s</xliff:g>."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Aplikace využívají tato oprávnění: <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" a "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"fotoaparát"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"poloha"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofon"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Senzory jsou vypnuty"</string>
<string name="device_services" msgid="1549944177856658705">"Služby zařízení"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Bez názvu"</string>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index dff770d49e28..0fc9b9495388 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"Indstillinger"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"OK"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Gem SysUI-heap"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> anvender enhedens <xliff:g id="TYPES_LIST">%2$s</xliff:g>."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Apps anvender enhedens <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" og "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"kamera"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"placering"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofon"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Deaktiver sensorer"</string>
<string name="device_services" msgid="1549944177856658705">"Enhedstjenester"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Ingen titel"</string>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 52275fcd637e..a6b137a8e9e5 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"Einstellungen"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"Ok"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> verwendet gerade Folgendes: <xliff:g id="TYPES_LIST">%2$s</xliff:g>."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Apps verwenden gerade Folgendes: <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" und "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"Kamera"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"Standort"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"Mikrofon"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Sensoren aus"</string>
<string name="device_services" msgid="1549944177856658705">"Gerätedienste"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Kein Titel"</string>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index bf4c61994c29..bdd19a18b2dd 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"Ρυθμίσεις"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"Το κατάλαβα"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Στιγμ. μνήμης SysUI"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"Η εφαρμογή <xliff:g id="APP">%1$s</xliff:g> χρησιμοποιεί τις λειτουργίες <xliff:g id="TYPES_LIST">%2$s</xliff:g>."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Οι εφαρμογές χρησιμοποιούν τις λειτουργίες <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" και "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"κάμερα"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"τοποθεσία"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"μικρόφωνο"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Αισθητήρες ανενεργοί"</string>
<string name="device_services" msgid="1549944177856658705">"Υπηρεσίες συσκευής"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Χωρίς τίτλο"</string>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index acb811107463..68a8d30477f6 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"Settings"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"OK"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> is using your <xliff:g id="TYPES_LIST">%2$s</xliff:g>."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Applications are using your <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" and "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"camera"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"location"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"microphone"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Sensors off"</string>
<string name="device_services" msgid="1549944177856658705">"Device Services"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"No title"</string>
diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml
index e3bad1f83a90..e9856af6cb1e 100644
--- a/packages/SystemUI/res/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"Settings"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"OK"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> is using your <xliff:g id="TYPES_LIST">%2$s</xliff:g>."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Applications are using your <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" and "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"camera"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"location"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"microphone"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Sensors off"</string>
<string name="device_services" msgid="1549944177856658705">"Device Services"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"No title"</string>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index acb811107463..68a8d30477f6 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"Settings"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"OK"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> is using your <xliff:g id="TYPES_LIST">%2$s</xliff:g>."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Applications are using your <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" and "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"camera"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"location"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"microphone"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Sensors off"</string>
<string name="device_services" msgid="1549944177856658705">"Device Services"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"No title"</string>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index acb811107463..68a8d30477f6 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"Settings"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"OK"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> is using your <xliff:g id="TYPES_LIST">%2$s</xliff:g>."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Applications are using your <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" and "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"camera"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"location"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"microphone"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Sensors off"</string>
<string name="device_services" msgid="1549944177856658705">"Device Services"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"No title"</string>
diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml
index 25ec6c384157..eacef2624b05 100644
--- a/packages/SystemUI/res/values-en-rXC/strings.xml
+++ b/packages/SystemUI/res/values-en-rXC/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‎‏‎‏‎‎‏‏‎‏‎‏‏‎‏‎‏‏‎‏‏‎‏‎‏‏‏‎‎‎‎‎‎‏‎‏‏‎‎‎‎‏‎‎‏‏‎‏‏‎‏‎‎‏‎‏‏‎‎Settings‎‏‎‎‏‎"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‎‎‎‏‏‏‎‏‏‏‏‎‏‏‏‏‏‏‎‎‎‎‏‏‏‏‎‏‎‎‏‎‏‏‏‏‎‎‏‏‎‏‎‎‏‎‎‏‎‏‎‎‎‏‏‎‏‎‎Got it‎‏‎‎‏‎"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‏‎‎‎‏‏‎‎‏‎‏‎‎‎‏‏‏‏‏‎‎‏‏‏‏‎‎‏‎‏‏‏‏‎‏‎‎‎‏‎‏‎‏‎‎‎‎‎‏‎‏‎‎‎‎‏‏‎‎Dump SysUI Heap‎‏‎‎‏‎"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‎‏‎‎‏‏‎‏‏‎‏‎‏‎‏‏‎‎‎‏‏‏‎‎‎‎‎‎‎‏‏‏‎‎‏‎‏‏‎‎‏‏‎‎‎‎‎‏‏‏‏‎‏‏‎‎‎‏‎‎‏‎‎‏‏‎<xliff:g id="APP">%1$s</xliff:g>‎‏‎‎‏‏‏‎ is using your ‎‏‎‎‏‏‎<xliff:g id="TYPES_LIST">%2$s</xliff:g>‎‏‎‎‏‏‏‎.‎‏‎‎‏‎"</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‏‏‏‏‎‎‎‎‎‏‏‏‏‏‎‎‏‏‏‏‎‎‎‏‏‏‎‏‎‏‏‏‎‎‎‏‏‏‏‎‎‏‏‎‎‏‏‎‏‎‎‏‎‏‎‎‏‎‎Applications are using your ‎‏‎‎‏‏‎<xliff:g id="TYPES_LIST">%s</xliff:g>‎‏‎‎‏‏‏‎.‎‏‎‎‏‎"</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‎‏‏‏‏‎‎‏‏‎‎‎‏‎‎‏‏‏‎‏‏‏‏‎‎‏‏‏‎‏‎‎‎‎‎‎‎‏‏‏‎‎‏‎‎‎‏‎‎‎‎‏‎‎‏‎‏‏‎, ‎‏‎‎‏‎ "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" ‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‏‎‏‏‏‏‎‏‏‏‏‏‎‎‏‏‎‎‏‏‎‎‏‎‎‏‎‎‏‎‏‏‏‎‏‏‎‎‎‏‎‏‏‏‎‏‏‎‏‎‏‎‎‏‎‎‏‏‏‎ and ‎‏‎‎‏‎ "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‏‎‏‎‏‎‏‎‎‏‏‎‎‎‎‏‎‏‎‏‏‏‏‎‏‏‏‏‎‏‎‏‏‎‏‏‎‎‏‎‎‎‎‎‎‎‎‏‎‏‏‎‏‏‏‏‎‎‎camera‎‏‎‎‏‎"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‏‎‏‏‏‎‎‏‏‏‎‏‏‏‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‎‎‏‎‎‎‏‏‏‏‏‏‎‎‏‎‏‏‏‎‎‎‏‏‏‏‎location‎‏‎‎‏‎"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‎‎‏‏‎‎‎‏‎‎‏‏‏‎‎‏‎‏‏‏‎‏‎‏‎‏‎‏‎‏‎‏‎‎‏‎‏‎‎‎‎‎‎‎‏‎‎‏‎‎‏‏‎‎‎microphone‎‏‎‎‏‎"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‎‏‏‏‏‎‏‏‏‏‎‏‎‎‏‎‎‏‏‏‎‏‎‎‎‏‎‏‎‎‏‏‎‎‎‏‏‎‏‎‏‎‏‏‎‏‎‏‏‏‎‎‎‏‏‏‎‎‎Sensors off‎‏‎‎‏‎"</string>
<string name="device_services" msgid="1549944177856658705">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‎‏‏‎‎‎‎‎‏‎‏‎‎‎‎‎‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‏‏‎‏‏‎‏‎‏‎‎‏‎‏‏‏‏‎‏‎‎‎‏‎‎‎‏‎Device Services‎‏‎‎‏‎"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‎‏‏‏‎‏‎‎‏‎‎‏‎‏‏‏‏‏‎‎‎‎‎‎‎‏‏‏‎‎‏‎‎‏‏‎‎‎‏‏‏‎‎‏‏‎‏‏‏‎‎‏‏‏‏‎‏‎‎No title‎‏‎‎‏‎"</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 01bed104a951..94a464bb6afa 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"Configuración"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"Entendido"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Volcar pila de SysUI"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> está usando tu <xliff:g id="TYPES_LIST">%2$s</xliff:g>."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Hay aplicaciones que están usando tu <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" y "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"cámara"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"ubicación"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"micrófono"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Se desactivaron los sensores"</string>
<string name="device_services" msgid="1549944177856658705">"Servicios del dispositivo"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Sin título"</string>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index 67678d24a0a6..0e7d376e5884 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"Ajustes"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"Entendido"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Volcar pila de SysUI"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> está usando tu <xliff:g id="TYPES_LIST">%2$s</xliff:g>."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Hay aplicaciones que usan tu <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" y "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"cámara"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"ubicación"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"micrófono"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Sensores desactivados"</string>
<string name="device_services" msgid="1549944177856658705">"Servicios del dispositivo"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Sin título"</string>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index a46fa490b4a8..fc9c73bb10bf 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"Seaded"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"Selge"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> kasutab järgmisi: <xliff:g id="TYPES_LIST">%2$s</xliff:g>."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Rakendused kasutavad järgmisi: <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" ja "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"kaamera"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"asukoht"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofon"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Andurid on välja lülitatud"</string>
<string name="device_services" msgid="1549944177856658705">"Seadme teenused"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Pealkiri puudub"</string>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index 19fc4f50d0d3..041beab2e74c 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"Ezarpenak"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"Ados"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> <xliff:g id="TYPES_LIST">%2$s</xliff:g> erabiltzen ari da."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Aplikazio batzuk <xliff:g id="TYPES_LIST">%s</xliff:g> erabiltzen ari dira."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" eta "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"kamera"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"kokapena"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofonoa"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Sentsoreak desaktibatuta daude"</string>
<string name="device_services" msgid="1549944177856658705">"Gailuetarako zerbitzuak"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Ez du izenik"</string>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index b8c87938d423..05e076f55a12 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"تنظیمات"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"متوجه شدم"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> از <xliff:g id="TYPES_LIST">%2$s</xliff:g> شما استفاده می‌کند."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"برنامه‌ها از <xliff:g id="TYPES_LIST">%s</xliff:g> شما استفاده می‌‌کنند."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">"، "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" و "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"دوربین"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"مکان"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"میکروفون"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"حسگرها خاموش است"</string>
<string name="device_services" msgid="1549944177856658705">"سرویس‌های دستگاه"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"بدون عنوان"</string>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 44a66c31b954..4fccaaca57f2 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"Asetukset"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"Selvä"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Luo SysUI-keon vedos"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> käyttää ominaisuuksia (<xliff:g id="TYPES_LIST">%2$s</xliff:g>)."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"<xliff:g id="TYPES_LIST">%s</xliff:g> ovat sovellusten käytössä."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" ja "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"kamera"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"sijainti"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofoni"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Anturit pois päältä"</string>
<string name="device_services" msgid="1549944177856658705">"Laitepalvelut"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Ei nimeä"</string>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 15cf6eb40658..4e2074c34a88 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"Paramètres"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"OK"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Copier mémoire SysUI"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> utilise votre <xliff:g id="TYPES_LIST">%2$s</xliff:g>."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Des applications utilisent votre <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" et "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"appareil photo"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"position"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"microphone"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Capteurs désactivés"</string>
<string name="device_services" msgid="1549944177856658705">"Services de l\'appareil"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Sans titre"</string>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 784186b013a9..fedec563edcf 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"Paramètres"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"OK"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Copier mémoire SysUI"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> utilise votre <xliff:g id="TYPES_LIST">%2$s</xliff:g>."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Des applications utilisent votre <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" et "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"appareil photo"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"position"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"micro"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Capteurs désactivés"</string>
<string name="device_services" msgid="1549944177856658705">"Services pour l\'appareil"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Sans titre"</string>
@@ -1021,9 +1028,9 @@
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Paramètres"</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>
- <string name="quick_controls_title" msgid="6839108006171302273">"Commandes de contrôle des appareils"</string>
+ <string name="quick_controls_title" msgid="6839108006171302273">"Commandes des appareils"</string>
<string name="quick_controls_subtitle" msgid="1667408093326318053">"Ajouter des commandes pour vos appareils connectés"</string>
- <string name="quick_controls_setup_title" msgid="8901436655997849822">"Configurer les commandes de contrôle des appareils"</string>
+ <string name="quick_controls_setup_title" msgid="8901436655997849822">"Configurer les commandes des appareils"</string>
<string name="quick_controls_setup_subtitle" msgid="1681506617879773824">"Appuyez de manière prolongée sur le bouton Marche/Arrêt pour accéder aux commandes"</string>
<string name="controls_providers_title" msgid="6879775889857085056">"Sélectionnez l\'appli pour laquelle ajouter des commandes"</string>
<plurals name="controls_number_of_favorites" formatted="false" msgid="1057347832073807380">
@@ -1046,7 +1053,7 @@
<string name="controls_favorite_load_error" msgid="5126216176144877419">"Impossible de charger les commandes. Vérifiez l\'application <xliff:g id="APP">%s</xliff:g> pour vous assurer que les paramètres n\'ont pas changé."</string>
<string name="controls_favorite_load_none" msgid="7687593026725357775">"Commandes compatibles indisponibles"</string>
<string name="controls_favorite_other_zone_header" msgid="9089613266575525252">"Autre"</string>
- <string name="controls_dialog_title" msgid="2343565267424406202">"Ajouter aux commandes de contrôle des appareils"</string>
+ <string name="controls_dialog_title" msgid="2343565267424406202">"Ajouter aux commandes des appareils"</string>
<string name="controls_dialog_ok" msgid="2770230012857881822">"Ajouter"</string>
<string name="controls_dialog_message" msgid="342066938390663844">"Suggérée par <xliff:g id="APP">%s</xliff:g>"</string>
<string name="controls_dialog_confirmation" msgid="586517302736263447">"Commandes mises à jour"</string>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index c732c7bbff1f..c1b9024e8b44 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"Configuración"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"De acordo"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Baleirado mem. SysUI"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> está utilizando <xliff:g id="TYPES_LIST">%2$s</xliff:g>."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Hai aplicacións que están utilizando <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" e "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"a cámara"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"a localiz."</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"o micrófono"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Desactivar sensores"</string>
<string name="device_services" msgid="1549944177856658705">"Servizos do dispositivo"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Sen título"</string>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index 5d3d3af8f917..9c2f71790fb0 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"સેટિંગ"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"સમજાઈ ગયું"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> ઍપ તમારા <xliff:g id="TYPES_LIST">%2$s</xliff:g>નો ઉપયોગ કરી રહી છે."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"ઍપ્લિકેશન તમારા <xliff:g id="TYPES_LIST">%s</xliff:g>નો ઉપયોગ કરી રહી છે."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" અને "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"કૅમેરા"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"સ્થાન"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"માઇક્રોફોન"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"સેન્સર બંધ છે"</string>
<string name="device_services" msgid="1549944177856658705">"ડિવાઇસ સેવાઓ"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"કોઈ શીર્ષક નથી"</string>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index f6bc4cdab087..cc2faa2a598c 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -987,6 +987,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"सेटिंग"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"ठीक है"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> आपकी <xliff:g id="TYPES_LIST">%2$s</xliff:g> का इस्तेमाल कर रहा है."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"ऐप्लिकेशन आपकी <xliff:g id="TYPES_LIST">%s</xliff:g> का इस्तेमाल कर रहे हैं."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" और "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"कैमरा"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"जगह"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"माइक्रोफ़ोन"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"सेंसर बंद हैं"</string>
<string name="device_services" msgid="1549944177856658705">"डिवाइस सेवाएं"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"कोई शीर्षक नहीं"</string>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index bfd5aa001c24..90251995002d 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -990,6 +990,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"Postavke"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"Shvaćam"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Izdvoji mem. SysUI-a"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"Aplikacija <xliff:g id="APP">%1$s</xliff:g> upotrebljava <xliff:g id="TYPES_LIST">%2$s</xliff:g>."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Aplikacije upotrebljavaju <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" i "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"fotoaparat"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"lokaciju"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofon"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Senzori su isključeni"</string>
<string name="device_services" msgid="1549944177856658705">"Usluge uređaja"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Bez naslova"</string>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index c8f4a467f94b..689d86960c88 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"Beállítások"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"Értem"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"SysUI-memória-kiírás"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"A(z) <xliff:g id="APP">%1$s</xliff:g> használja a következőket: <xliff:g id="TYPES_LIST">%2$s</xliff:g>."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Több alkalmazás használja a következőket: <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" és "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"kamera"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"helyadatok"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofon"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Érzékelők kikapcsolva"</string>
<string name="device_services" msgid="1549944177856658705">"Eszközszolgáltatások"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Nincs cím"</string>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index 53286188af47..a574f26a514d 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -916,7 +916,7 @@
<string name="accessibility_quick_settings_edit" msgid="1523745183383815910">"Խմբագրել կարգավորումների հերթականությունը:"</string>
<string name="accessibility_quick_settings_page" msgid="7506322631645550961">"Էջ <xliff:g id="ID_1">%1$d</xliff:g> / <xliff:g id="ID_2">%2$d</xliff:g>"</string>
<string name="tuner_lock_screen" msgid="2267383813241144544">"Կողպէկրան"</string>
- <string name="thermal_shutdown_title" msgid="2702966892682930264">"Հեռախոսն անջատվել է տաքանալու պատճառով"</string>
+ <string name="thermal_shutdown_title" msgid="2702966892682930264">"Հեռախոսն անջատվել էր տաքանալու պատճառով"</string>
<string name="thermal_shutdown_message" msgid="6142269839066172984">"Հեռախոսն այժմ նորմալ է աշխատում։\nՀպեք՝ ավելին իմանալու համար։"</string>
<string name="thermal_shutdown_dialog_message" msgid="6745684238183492031">"Ձեր հեռախոսը չափազանց տաք էր, այդ պատճառով այն անջատվել է՝ հովանալու համար: Հեռախոսն այժմ նորմալ աշխատում է:\n\nՀեռախոսը կարող է տաքանալ, եթե՝\n • Օգտագործում եք ռեսուրսատար հավելվածներ (օրինակ՝ խաղեր, տեսանյութեր կամ նավարկման հավելվածներ)\n • Ներբեռնում կամ վերբեռնում եք ծանր ֆայլեր\n • Օգտագործում եք ձեր հեռախոսը բարձր ջերմային պայմաններում"</string>
<string name="thermal_shutdown_dialog_help_text" msgid="6413474593462902901">"Քայլեր գերտաքացման ահազանգի դեպքում"</string>
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"Կարգավորումներ"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"Եղավ"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> հավելվածն օգտագործում է ձեր <xliff:g id="TYPES_LIST">%2$s</xliff:g>:"</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Հավելվածներն օգտագործում են ձեր <xliff:g id="TYPES_LIST">%s</xliff:g>:"</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" և "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"տեսախցիկը"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"վայրը"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"խոսափողը"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Տվիչներն անջատած են"</string>
<string name="device_services" msgid="1549944177856658705">"Սարքի ծառայություններ"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Անանուն"</string>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index dfed57b94c51..7cc1b898dedb 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"Setelan"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"Oke"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Hapus Heap SysUI"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> menggunakan <xliff:g id="TYPES_LIST">%2$s</xliff:g>."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Aplikasi menggunakan <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" dan "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"kamera"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"lokasi"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofon"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Sensor nonaktif"</string>
<string name="device_services" msgid="1549944177856658705">"Layanan Perangkat"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Tanpa judul"</string>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index 57cdb272f176..8b686b8deb96 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"Stillingar"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"Ég skil"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Vista SysUI-gögn"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> er að nota <xliff:g id="TYPES_LIST">%2$s</xliff:g>."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Forrit eru að nota <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" og "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"myndavél"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"staðsetning"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"hljóðnemi"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Slökkt á skynjurum"</string>
<string name="device_services" msgid="1549944177856658705">"Tækjaþjónusta"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Enginn titill"</string>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 679eb551e7f0..35742fd4d4db 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"Impostazioni"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"OK"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Esegui dump heap SysUI"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"L\'app <xliff:g id="APP">%1$s</xliff:g> sta usando <xliff:g id="TYPES_LIST">%2$s</xliff:g>."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Le app stanno usando <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" e "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"Fotocamera"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"luogo"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"un microfono"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Sensori disattivati"</string>
<string name="device_services" msgid="1549944177856658705">"Servizi del dispositivo"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Senza titolo"</string>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index b6a723f00024..1029bb2042db 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -995,6 +995,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"הגדרות"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"הבנתי"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"‏ערימת Dump SysUI"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> משתמשת ב<xliff:g id="TYPES_LIST">%2$s</xliff:g>."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"אפליקציות משתמשות ב<xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" וגם "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"מצלמה"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"מיקום"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"מיקרופון"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"החיישנים כבויים"</string>
<string name="device_services" msgid="1549944177856658705">"שירותים למכשיר"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"ללא שם"</string>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index b70e2e2bc14f..fedd9bb7ffc0 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"設定"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"OK"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"SysUI ヒープのダンプ"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g>は<xliff:g id="TYPES_LIST">%2$s</xliff:g>を使用しています。"</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"アプリは<xliff:g id="TYPES_LIST">%s</xliff:g>を使用しています。"</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">"、 "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" 、 "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"カメラ"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"現在地情報"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"マイク"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"センサー OFF"</string>
<string name="device_services" msgid="1549944177856658705">"デバイス サービス"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"タイトルなし"</string>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index 0dda483b9d16..5c55112ea1fd 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"პარამეტრები"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"გასაგებია"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"SysUI გროვის გამოტანა"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g>-ის მიერ გამოიყენება თქვენი <xliff:g id="TYPES_LIST">%2$s</xliff:g>."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"აპლიკაციების მიერ გამოიყენება თქვენი <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" და "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"კამერა"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"მდებარეობა"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"მიკროფონი"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"სენსორების გამორთვა"</string>
<string name="device_services" msgid="1549944177856658705">"მოწყობილობის სერვისები"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"უსათაურო"</string>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index 27bc3ab4aab0..94c8ea33a461 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"Параметрлер"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"Түсінікті"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> қолданбасында <xliff:g id="TYPES_LIST">%2$s</xliff:g> пайдалануда."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Қолданбаларда <xliff:g id="TYPES_LIST">%s</xliff:g> пайдаланылуда."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" және "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"камера"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"геодерек"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"микрофон"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Датчиктер өшірулі"</string>
<string name="device_services" msgid="1549944177856658705">"Құрылғы қызметтері"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Атауы жоқ"</string>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index 36d5aa8ab45b..5ba460adebf3 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"ការកំណត់"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"យល់ហើយ"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"ចម្លង SysUI Heap"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> កំពុងប្រើ <xliff:g id="TYPES_LIST">%2$s</xliff:g> របស់អ្នក។"</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"កម្មវិធី​កំពុងប្រើ <xliff:g id="TYPES_LIST">%s</xliff:g> របស់អ្នក។"</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" និង "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"កាមេរ៉ា"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"ទីតាំង"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"មីក្រូហ្វូន"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"បិទឧបករណ៍​ចាប់សញ្ញា"</string>
<string name="device_services" msgid="1549944177856658705">"សេវាកម្មឧបករណ៍"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"គ្មាន​ចំណងជើង"</string>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index 2034472d18cd..7b8ed88bfd19 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"ಸೆಟ್ಟಿಂಗ್‌ಗಳು"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"ಅರ್ಥವಾಯಿತು"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"ನಿಮ್ಮ <xliff:g id="TYPES_LIST">%2$s</xliff:g> ಅನ್ನು <xliff:g id="APP">%1$s</xliff:g> ಬಳಸುತ್ತಿದೆ."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"ನಿಮ್ಮ <xliff:g id="TYPES_LIST">%s</xliff:g> ಅನ್ನು ಆ್ಯಪ್‌ಗಳು ಬಳಸುತ್ತಿವೆ."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" ಮತ್ತು "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"ಕ್ಯಾಮರಾ"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"ಸ್ಥಳ"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"ಮೈಕ್ರೋಫೋನ್‌"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"ಸೆನ್ಸರ್‌ಗಳು ಆಫ್"</string>
<string name="device_services" msgid="1549944177856658705">"ಸಾಧನ ಸೇವೆಗಳು"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"ಯಾವುದೇ ಶೀರ್ಷಿಕೆಯಿಲ್ಲ"</string>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index ef4a5f63d0d3..8d1177bec0ea 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"설정"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"확인"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g>이(가) <xliff:g id="TYPES_LIST">%2$s</xliff:g>을(를) 사용 중입니다."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"애플리케이션이 <xliff:g id="TYPES_LIST">%s</xliff:g>을(를) 사용 중입니다."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" 및 "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"카메라"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"위치"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"마이크"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"센서 사용 안함"</string>
<string name="device_services" msgid="1549944177856658705">"기기 서비스"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"제목 없음"</string>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index cfd91b56ddf5..794de98420d1 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"Жөндөөлөр"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"Түшүндүм"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> төмөнкүлөрдү колдонуп жатат: <xliff:g id="TYPES_LIST">%2$s</xliff:g>."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Колдонмолор төмөнкүлөрдү пайдаланып жатышат: <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" жана "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"камера"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"жайгашкан жер"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"микрофон"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Сенсорлорду өчүрүү"</string>
<string name="device_services" msgid="1549944177856658705">"Түзмөк кызматтары"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Аталышы жок"</string>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index 90b5ad2267ac..2fe3f8075dbb 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"ການຕັ້ງຄ່າ"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"ເຂົ້າໃຈແລ້ວ"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> ກຳລັງໃຊ້ <xliff:g id="TYPES_LIST">%2$s</xliff:g> ຂອງທ່ານ."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"ແອັບພລິເຄຊັນກຳລັງໃຊ້ <xliff:g id="TYPES_LIST">%s</xliff:g> ຂອງທ່ານ."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" ແລະ "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"ກ້ອງຖ່າຍຮູບ"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"ສະຖານທີ່"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"ໄມໂຄຣໂຟນ"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"ປິດການຮັບຮູ້ຢູ່"</string>
<string name="device_services" msgid="1549944177856658705">"ບໍລິການອຸປະກອນ"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"ບໍ່ມີຊື່"</string>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 5c8e8d9ac8fb..4489b7dd62ee 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -995,6 +995,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"Nustatymai"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"Supratau"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Pat. „SysUI“ krūvą"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"Programa „<xliff:g id="APP">%1$s</xliff:g>“ naudoja: <xliff:g id="TYPES_LIST">%2$s</xliff:g>."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Programos naudoja: <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" ir "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"fotoaparatą"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"vietovę"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofoną"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Jutikliai išjungti"</string>
<string name="device_services" msgid="1549944177856658705">"Įrenginio paslaugos"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Nėra pavadinimo"</string>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index cbe076896d9f..d4826e42f17c 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -28,15 +28,15 @@
<string name="battery_low_percent_format" msgid="4276661262843170964">"Atlikuši <xliff:g id="PERCENTAGE">%s</xliff:g>"</string>
<string name="battery_low_percent_format_hybrid" msgid="3985614339605686167">"Atlikušais laiks: <xliff:g id="PERCENTAGE">%1$s</xliff:g> — aptuveni <xliff:g id="TIME">%2$s</xliff:g> (ņemot vērā lietojumu)"</string>
<string name="battery_low_percent_format_hybrid_short" msgid="5917433188456218857">"Atlikušais laiks: <xliff:g id="PERCENTAGE">%1$s</xliff:g> — aptuveni <xliff:g id="TIME">%2$s</xliff:g>"</string>
- <string name="battery_low_percent_format_saver_started" msgid="4968468824040940688">"Atlikuši <xliff:g id="PERCENTAGE">%s</xliff:g>. Ir ieslēgts akumulatora jaudas taupīšanas režīms."</string>
+ <string name="battery_low_percent_format_saver_started" msgid="4968468824040940688">"Atlikuši <xliff:g id="PERCENTAGE">%s</xliff:g>. Ir ieslēgts akumulatora enerģijas taupīšanas režīms."</string>
<string name="invalid_charger" msgid="4370074072117767416">"Nevar veikt uzlādi, izmantojot USB. Izmantojiet ierīces komplektācijā iekļauto uzlādes ierīci."</string>
<string name="invalid_charger_title" msgid="938685362320735167">"Nevar veikt uzlādi, izmantojot USB"</string>
<string name="invalid_charger_text" msgid="2339310107232691577">"Izmantojiet ierīces komplektācijā iekļauto uzlādes ierīci"</string>
<string name="battery_low_why" msgid="2056750982959359863">"Iestatījumi"</string>
- <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Vai ieslēgt akumulatora jaudas taupīšanas režīmu?"</string>
- <string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"Par akumulatora jaudas taupīšanas režīmu"</string>
+ <string name="battery_saver_confirmation_title" msgid="1234998463717398453">"Vai ieslēgt akumulatora enerģijas taupīšanas režīmu?"</string>
+ <string name="battery_saver_confirmation_title_generic" msgid="2299231884234959849">"Par akumulatora enerģijas taupīšanas režīmu"</string>
<string name="battery_saver_confirmation_ok" msgid="5042136476802816494">"Ieslēgt"</string>
- <string name="battery_saver_start_action" msgid="4553256017945469937">"Ieslēgt akumulatora jaudas taupīšanas režīmu"</string>
+ <string name="battery_saver_start_action" msgid="4553256017945469937">"Ieslēgt akumulatora enerģijas taupīšanas režīmu"</string>
<string name="status_bar_settings_settings_button" msgid="534331565185171556">"Iestatījumi"</string>
<string name="status_bar_settings_wifi_button" msgid="7243072479837270946">"Wi-Fi"</string>
<string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"Automātiska ekrāna pagriešana"</string>
@@ -423,7 +423,7 @@
<string name="quick_settings_night_secondary_label_on_at" msgid="3584738542293528235">"Plkst. <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_secondary_label_until" msgid="1883981263191927372">"Līdz <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="quick_settings_ui_mode_night_label" msgid="1398928270610780470">"Tumšais motīvs"</string>
- <string name="quick_settings_dark_mode_secondary_label_battery_saver" msgid="4990712734503013251">"Jaudas taupīšana"</string>
+ <string name="quick_settings_dark_mode_secondary_label_battery_saver" msgid="4990712734503013251">"Enerģijas taupīšana"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at_sunset" msgid="6017379738102015710">"Saulrietā"</string>
<string name="quick_settings_dark_mode_secondary_label_until_sunrise" msgid="4404885070316716472">"Līdz saullēktam"</string>
<string name="quick_settings_dark_mode_secondary_label_on_at" msgid="5128758823486361279">"Plkst. <xliff:g id="TIME">%s</xliff:g>"</string>
@@ -502,9 +502,9 @@
<string name="user_remove_user_title" msgid="9124124694835811874">"Vai noņemt lietotāju?"</string>
<string name="user_remove_user_message" msgid="6702834122128031833">"Tiks dzēstas visas šī lietotāja lietotnes un dati."</string>
<string name="user_remove_user_remove" msgid="8387386066949061256">"Noņemt"</string>
- <string name="battery_saver_notification_title" msgid="8419266546034372562">"Akumulatora jaudas taupīšanas režīms ir ieslēgts"</string>
+ <string name="battery_saver_notification_title" msgid="8419266546034372562">"Akumulatora enerģijas taupīšanas režīms ir ieslēgts"</string>
<string name="battery_saver_notification_text" msgid="2617841636449016951">"Samazina veiktspēju un fona datus"</string>
- <string name="battery_saver_notification_action_text" msgid="6022091913807026887">"Izslēgt akumulatora jaudas taupīšanas režīmu"</string>
+ <string name="battery_saver_notification_action_text" msgid="6022091913807026887">"Izslēgt akumulatora enerģijas taupīšanas režīmu"</string>
<string name="media_projection_dialog_text" msgid="1755705274910034772">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> iegūs piekļuvi visai informācijai, kas ierakstīšanas vai apraides laikā tiks rādīta jūsu ekrānā vai atskaņota jūsu ierīcē. Atļauja attiecas uz tādu informāciju kā paroles, maksājumu informācija, fotoattēli, ziņojumi un jūsu atskaņotais audio saturs."</string>
<string name="media_projection_dialog_service_text" msgid="958000992162214611">"Pakalpojums, kas nodrošina šo funkciju, iegūs piekļuvi visai informācijai, kas ierakstīšanas vai apraides laikā tiks rādīta jūsu ekrānā vai atskaņota jūsu ierīcē. Atļauja attiecas uz tādu informāciju kā paroles, maksājumu informācija, fotoattēli, ziņojumi un jūsu atskaņotais audio saturs."</string>
<string name="media_projection_dialog_service_title" msgid="2888507074107884040">"Vai vēlaties sākt ierakstīšanu/apraidi?"</string>
@@ -780,8 +780,8 @@
<item quantity="other">%d minūtes</item>
</plurals>
<string name="battery_panel_title" msgid="5931157246673665963">"Akumulatora lietojums"</string>
- <string name="battery_detail_charging_summary" msgid="8821202155297559706">"Akumulatora jaudas taupīšanas režīms uzlādes laikā nav pieejams."</string>
- <string name="battery_detail_switch_title" msgid="6940976502957380405">"Akumulatora jaudas taupīšanas režīms"</string>
+ <string name="battery_detail_charging_summary" msgid="8821202155297559706">"Akumulatora enerģijas taupīšanas režīms uzlādes laikā nav pieejams."</string>
+ <string name="battery_detail_switch_title" msgid="6940976502957380405">"Akumulatora enerģijas taupīšanas režīms"</string>
<string name="battery_detail_switch_summary" msgid="3668748557848025990">"Samazina veiktspēju un fona datus."</string>
<string name="keyboard_key_button_template" msgid="8005673627272051429">"Poga <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_key_home" msgid="3734400625170020657">"Sākumvietas taustiņš"</string>
@@ -982,14 +982,21 @@
<string name="slice_permission_checkbox" msgid="4242888137592298523">"Atļaut lietotnei <xliff:g id="APP">%1$s</xliff:g> rādīt sadaļas no jebkuras lietotnes"</string>
<string name="slice_permission_allow" msgid="6340449521277951123">"Atļaut"</string>
<string name="slice_permission_deny" msgid="6870256451658176895">"Neatļaut"</string>
- <string name="auto_saver_title" msgid="6873691178754086596">"Pieskarieties, lai iestatītu akumulatora jaudas taupīšanas režīma grafiku"</string>
+ <string name="auto_saver_title" msgid="6873691178754086596">"Pieskarieties, lai iestatītu akumulatora enerģijas taupīšanas režīma grafiku"</string>
<string name="auto_saver_text" msgid="3214960308353838764">"Ieslēgt, ja akumulators var izlādēties"</string>
<string name="no_auto_saver_action" msgid="7467924389609773835">"Nē, paldies"</string>
<string name="auto_saver_enabled_title" msgid="4294726198280286333">"Ieslēgts akumulatora enerģijas taupīšanas režīma grafiks"</string>
- <string name="auto_saver_enabled_text" msgid="7889491183116752719">"Tiklīdz akumulatora uzlādes līmenis būs zemāks nekā <xliff:g id="PERCENTAGE">%d</xliff:g>%%, tiks automātiski ieslēgts akumulatora jaudas taupīšanas režīms."</string>
+ <string name="auto_saver_enabled_text" msgid="7889491183116752719">"Tiklīdz akumulatora uzlādes līmenis būs zemāks nekā <xliff:g id="PERCENTAGE">%d</xliff:g>%%, tiks automātiski ieslēgts akumulatora enerģijas taupīšanas režīms."</string>
<string name="open_saver_setting_action" msgid="2111461909782935190">"Iestatījumi"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"Labi"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"Lietotne <xliff:g id="APP">%1$s</xliff:g> izmanto funkcijas <xliff:g id="TYPES_LIST">%2$s</xliff:g>."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Lietojumprogrammas izmanto šādas funkcijas: <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" un "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"kamera"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"atrašanās vieta"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofons"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Sensori izslēgti"</string>
<string name="device_services" msgid="1549944177856658705">"Ierīces pakalpojumi"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Nav nosaukuma"</string>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index 5a000de3e843..4836ecf1574a 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"Поставки"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"Сфатив"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Извади SysUI-слика"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> користи <xliff:g id="TYPES_LIST">%2$s</xliff:g>."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Апликациите користат <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" и "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"камера"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"локација"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"микрофон"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Сензорите се исклучени"</string>
<string name="device_services" msgid="1549944177856658705">"Услуги за уредот"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Без наслов"</string>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index 22392279a919..863ce1152752 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"ക്രമീകരണം"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"മനസ്സിലായി"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"SysUI ഹീപ്പ് ഡമ്പ് ചെയ്യുക"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> നിങ്ങളുടെ <xliff:g id="TYPES_LIST">%2$s</xliff:g> ഉപയോഗിക്കുന്നു."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"ആപ്പുകൾ നിങ്ങളുടെ <xliff:g id="TYPES_LIST">%s</xliff:g> ഉപയോഗിക്കുന്നു."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" കൂടാതെ "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"ക്യാമറ"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"ലൊക്കേഷന്‍"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"മൈക്രോഫോൺ"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"സെൻസറുകൾ ഓഫാണ്"</string>
<string name="device_services" msgid="1549944177856658705">"ഉപകരണ സേവനങ്ങള്‍"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"പേരില്ല"</string>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index 8141ef3a1fc6..107c3101a221 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"Тохиргоо"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"Ойлголоо"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> таны <xliff:g id="TYPES_LIST">%2$s</xliff:g>-г ашиглаж байна."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Аппууд таны <xliff:g id="TYPES_LIST">%s</xliff:g>-г ашиглаж байна."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" болон "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"камер"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"байршил"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"микрофон"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Мэдрэгчийг унтраах"</string>
<string name="device_services" msgid="1549944177856658705">"Төхөөрөмжийн үйлчилгээ"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Гарчиггүй"</string>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index 79b7ae8b12a5..bd2c3a5d09e9 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"सेटिंग्ज"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"समजले"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"SysUI हीप डंप करा"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> तुमचे <xliff:g id="TYPES_LIST">%2$s</xliff:g> वापरत आहे."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"ॲप्लिकेशन्स तुमचे <xliff:g id="TYPES_LIST">%s</xliff:g> वापरत आहे."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" आणि "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"कॅमेरा"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"स्थान"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"मायक्रोफोन"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"सेन्सर बंद आहेत"</string>
<string name="device_services" msgid="1549944177856658705">"डिव्हाइस सेवा"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"शीर्षक नाही"</string>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index 37cbb7edf753..029571b656ea 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"Tetapan"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"OK"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Longgok Tmbunn SysUI"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> sedang menggunakan <xliff:g id="TYPES_LIST">%2$s</xliff:g> anda."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Aplikasi sedang menggunakan <xliff:g id="TYPES_LIST">%s</xliff:g> anda."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" dan "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"kamera"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"lokasi"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofon"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Penderia dimatikan"</string>
<string name="device_services" msgid="1549944177856658705">"Perkhidmatan Peranti"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Tiada tajuk"</string>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index 376ed2fd2d9a..6e632af3c5f4 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"ဆက်တင်များ"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"ရပါပြီ"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> က သင်၏ <xliff:g id="TYPES_LIST">%2$s</xliff:g> ကို အသုံးပြုနေသည်။"</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"အပလီကေးရှင်းများက သင်၏ <xliff:g id="TYPES_LIST">%s</xliff:g> ကို အသုံးပြုနေသည်။"</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">"၊ "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" နှင့် "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"ကင်မရာ"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"တည်နေရာ"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"မိုက်ခရိုဖုန်း"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"အာရုံခံကိရိယာများ ပိတ်ထားသည်"</string>
<string name="device_services" msgid="1549944177856658705">"စက်ပစ္စည်းဝန်ဆောင်မှုများ"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"ခေါင်းစဉ် မရှိပါ"</string>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 26268301333c..5e29ca48bf7b 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"Innstillinger"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"Greit"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI-heap"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> bruker <xliff:g id="TYPES_LIST">%2$s</xliff:g>."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Apper bruker <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" og "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"kamera"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"posisjon"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofon"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Sensorer er av"</string>
<string name="device_services" msgid="1549944177856658705">"Enhetstjenester"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Ingen tittel"</string>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index d962af76ec41..098e0b1911d1 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"सेटिङहरू"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"बुझेँ"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> ले तपाईंको <xliff:g id="TYPES_LIST">%2$s</xliff:g> प्रयोग गर्दै छ।"</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"एपहरूले तपाईंको <xliff:g id="TYPES_LIST">%s</xliff:g> प्रयोग गर्दै छन्‌।"</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" र "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"क्यामेरा"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"स्थान"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"माइक्रोफोन"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"सेन्सरहरू निष्क्रिय छन्"</string>
<string name="device_services" msgid="1549944177856658705">"यन्त्रका सेवाहरू"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"शीर्षक छैन"</string>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 7a4de7516e05..e5012182eadc 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -433,7 +433,7 @@
<string name="quick_settings_screen_record_start" msgid="1574725369331638985">"Starten"</string>
<string name="quick_settings_screen_record_stop" msgid="8087348522976412119">"Stoppen"</string>
<string name="media_seamless_remote_device" msgid="177033467332920464">"Apparaat"</string>
- <string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Veeg omhoog om te schakelen tussen apps"</string>
+ <string name="recents_swipe_up_onboarding" msgid="2820265886420993995">"Swipe omhoog om te schakelen tussen apps"</string>
<string name="recents_quick_scrub_onboarding" msgid="765934300283514912">"Sleep naar rechts om snel tussen apps te schakelen"</string>
<string name="quick_step_accessibility_toggle_overview" msgid="7908949976727578403">"Overzicht in-/uitschakelen"</string>
<string name="expanded_header_battery_charged" msgid="5307907517976548448">"Opgeladen"</string>
@@ -452,12 +452,12 @@
<string name="keyguard_more_overflow_text" msgid="5819512373606638727">"+<xliff:g id="NUMBER_OF_NOTIFICATIONS">%d</xliff:g>"</string>
<string name="speed_bump_explanation" msgid="7248696377626341060">"Minder urgente meldingen onderaan"</string>
<string name="notification_tap_again" msgid="4477318164947497249">"Tik nog eens om te openen"</string>
- <string name="keyguard_unlock" msgid="8031975796351361601">"Veeg omhoog om te openen"</string>
- <string name="keyguard_retry" msgid="886802522584053523">"Veeg omhoog om het opnieuw te proberen"</string>
+ <string name="keyguard_unlock" msgid="8031975796351361601">"Swipe omhoog om te openen"</string>
+ <string name="keyguard_retry" msgid="886802522584053523">"Swipe omhoog om het opnieuw te proberen"</string>
<string name="do_disclosure_generic" msgid="4896482821974707167">"Dit apparaat is eigendom van je organisatie"</string>
<string name="do_disclosure_with_name" msgid="2091641464065004091">"Dit apparaat is eigendom van <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
- <string name="phone_hint" msgid="6682125338461375925">"Vegen voor telefoon"</string>
- <string name="voice_hint" msgid="7476017460191291417">"Vegen vanaf pictogram voor spraakassistent"</string>
+ <string name="phone_hint" msgid="6682125338461375925">"Swipen voor telefoon"</string>
+ <string name="voice_hint" msgid="7476017460191291417">"Swipen vanaf icoon voor spraakassistent"</string>
<string name="camera_hint" msgid="4519495795000658637">"Vegen voor camera"</string>
<string name="interruption_level_none_with_warning" msgid="8394434073508145437">"Helemaal stil. Hiermee worden schermlezers ook op stil gezet."</string>
<string name="interruption_level_none" msgid="219484038314193379">"Helemaal stil"</string>
@@ -566,7 +566,7 @@
<string name="monitoring_description_ca_cert_settings_separator" msgid="7107390013344435439">" "</string>
<string name="monitoring_description_ca_cert_settings" msgid="8329781950135541003">"Vertrouwde gegevens openen"</string>
<string name="monitoring_description_network_logging" msgid="577305979174002252">"Je beheerder heeft netwerkregistratie ingeschakeld, waarmee verkeer op je apparaat wordt bijgehouden.\n\nNeem contact op met je beheerder voor meer informatie."</string>
- <string name="monitoring_description_vpn" msgid="1685428000684586870">"Je hebt een app toestemming gegeven voor het instellen van een VPN-verbinding.\n\nMet deze app kan je apparaat- en netwerkactiviteit worden gecontroleerd, inclusief e-mails, apps en websites."</string>
+ <string name="monitoring_description_vpn" msgid="1685428000684586870">"Je hebt een app rechten gegeven voor het instellen van een VPN-verbinding.\n\nMet deze app kan je apparaat- en netwerkactiviteit worden gecontroleerd, inclusief e-mails, apps en websites."</string>
<string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"Je werkprofiel wordt beheerd door <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nJe beheerder kan je netwerkactiviteit controleren, inclusief e-mails, apps en websites.\n\nNeem contact op met je beheerder voor meer informatie.\n\nJe bent ook verbonden met een VPN, waarmee je netwerkactiviteit kan worden gecontroleerd."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
<string name="monitoring_description_app" msgid="376868879287922929">"Je bent verbonden met <xliff:g id="APPLICATION">%1$s</xliff:g>, waarmee je netwerkactiviteit (waaronder e-mails, apps en websites) kan worden bijgehouden."</string>
@@ -644,7 +644,7 @@
<string name="output_service_bt_wifi" msgid="7186882540475524124">"Bluetooth en wifi"</string>
<string name="system_ui_tuner" msgid="1471348823289954729">"Systeem-UI-tuner"</string>
<string name="show_battery_percentage" msgid="6235377891802910455">"Percentage ingebouwde batterij weergeven"</string>
- <string name="show_battery_percentage_summary" msgid="9053024758304102915">"Accupercentage weergeven in het pictogram op de statusbalk wanneer er niet wordt opgeladen"</string>
+ <string name="show_battery_percentage_summary" msgid="9053024758304102915">"Accupercentage weergeven in het icoon op de statusbalk wanneer er niet wordt opgeladen"</string>
<string name="quick_settings" msgid="6211774484997470203">"Snelle instellingen"</string>
<string name="status_bar" msgid="4357390266055077437">"Statusbalk"</string>
<string name="overview" msgid="3522318590458536816">"Overzicht"</string>
@@ -861,8 +861,8 @@
<string name="accessibility_key" msgid="3471162841552818281">"Aangepaste navigatieknop"</string>
<string name="left_keycode" msgid="8211040899126637342">"Toetscode links"</string>
<string name="right_keycode" msgid="2480715509844798438">"Toetscode rechts"</string>
- <string name="left_icon" msgid="5036278531966897006">"Pictogram links"</string>
- <string name="right_icon" msgid="1103955040645237425">"Pictogram rechts"</string>
+ <string name="left_icon" msgid="5036278531966897006">"Icoon links"</string>
+ <string name="right_icon" msgid="1103955040645237425">"Icoon rechts"</string>
<string name="drag_to_add_tiles" msgid="8933270127508303672">"Houd vast en sleep om tegels toe te voegen"</string>
<string name="drag_to_rearrange_tiles" msgid="2143204300089638620">"Houd vast en sleep om tegels opnieuw in te delen"</string>
<string name="drag_to_remove_tiles" msgid="4682194717573850385">"Sleep hier naartoe om te verwijderen"</string>
@@ -872,12 +872,12 @@
<string-array name="clock_options">
<item msgid="3986445361435142273">"Uren, minuten en seconden weergeven"</item>
<item msgid="1271006222031257266">"Uren en minuten weergeven (standaard)"</item>
- <item msgid="6135970080453877218">"Dit pictogram niet weergeven"</item>
+ <item msgid="6135970080453877218">"Dit icoon niet weergeven"</item>
</string-array>
<string-array name="battery_options">
<item msgid="7714004721411852551">"Percentage altijd weergeven"</item>
<item msgid="3805744470661798712">"Percentage weergeven tijdens opladen (standaard)"</item>
- <item msgid="8619482474544321778">"Dit pictogram niet weergeven"</item>
+ <item msgid="8619482474544321778">"Dit icoon niet weergeven"</item>
</string-array>
<string name="tuner_low_priority" msgid="8412666814123009820">"Pictogrammen voor meldingen met lage prioriteit weergeven"</string>
<string name="other" msgid="429768510980739978">"Overig"</string>
@@ -970,7 +970,7 @@
<string name="mobile_data_disable_title" msgid="5366476131671617790">"Mobiele data uitzetten?"</string>
<string name="mobile_data_disable_message" msgid="8604966027899770415">"Je hebt dan geen toegang meer tot data of internet via <xliff:g id="CARRIER">%s</xliff:g>. Internet is alleen nog beschikbaar via wifi."</string>
<string name="mobile_data_disable_message_default_carrier" msgid="6496033312431658238">"je provider"</string>
- <string name="touch_filtered_warning" msgid="8119511393338714836">"Aangezien een app een toestemmingsverzoek afdekt, kan Instellingen je reactie niet verifiëren."</string>
+ <string name="touch_filtered_warning" msgid="8119511393338714836">"Aangezien een app een rechtenverzoek afdekt, kan Instellingen je reactie niet verifiëren."</string>
<string name="slice_permission_title" msgid="3262615140094151017">"<xliff:g id="APP_0">%1$s</xliff:g> toestaan om segmenten van <xliff:g id="APP_2">%2$s</xliff:g> weer te geven?"</string>
<string name="slice_permission_text_1" msgid="6675965177075443714">"- Deze kan informatie lezen van <xliff:g id="APP">%1$s</xliff:g>"</string>
<string name="slice_permission_text_2" msgid="6758906940360746983">"- Deze kan acties uitvoeren in <xliff:g id="APP">%1$s</xliff:g>"</string>
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"Instellingen"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"OK"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> gebruikt je <xliff:g id="TYPES_LIST">%2$s</xliff:g>."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Apps gebruiken je <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" en "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"camera"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"locatie"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"microfoon"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Sensoren uit"</string>
<string name="device_services" msgid="1549944177856658705">"Apparaatservices"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Geen titel"</string>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index e112f446acb1..bfd4bd77df31 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"ସେଟିଂସ୍"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"ବୁଝିଗଲି"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"SysUI ହିପ୍ ଡମ୍ପ୍ କରନ୍ତୁ"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> ଆପଣଙ୍କ <xliff:g id="TYPES_LIST">%2$s</xliff:g> ବ୍ୟବହାର କରୁଛନ୍ତି।"</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"ଆପ୍ଲିକେସନ୍‍ଗୁଡିକ ଆପଣଙ୍କ <xliff:g id="TYPES_LIST">%s</xliff:g> ବ୍ୟବହାର କରୁଛନ୍ତି।"</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" ଏବଂ "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"କ୍ୟାମେରା"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"ଲୋକେସନ୍‍"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"ମାଇକ୍ରୋଫୋନ୍"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"ସେନ୍ସର୍‍ଗୁଡ଼ିକ ବନ୍ଦ ଅଛି"</string>
<string name="device_services" msgid="1549944177856658705">"ଡିଭାଇସ୍‍ ସେବାଗୁଡିକ"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"କୌଣସି ଶୀର୍ଷକ ନାହିଁ"</string>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index 6ac824b59e6b..1df919286a95 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"ਸੈਟਿੰਗਾਂ"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"ਸਮਝ ਲਿਆ"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"SysUI ਹੀਪ ਡੰਪ ਕਰੋ"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> ਤੁਹਾਡੇ <xliff:g id="TYPES_LIST">%2$s</xliff:g> ਦੀ ਵਰਤੋਂ ਕਰ ਰਹੀ ਹੈ।"</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"ਐਪਲੀਕੇਸ਼ਨਾਂ ਤੁਹਾਡੇ <xliff:g id="TYPES_LIST">%s</xliff:g> ਦੀ ਵਰਤੋਂ ਕਰ ਰਹੀਆਂ ਹਨ।"</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" ਅਤੇ "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"ਕੈਮਰਾ"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"ਟਿਕਾਣਾ"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"ਮਾਈਕ੍ਰੋਫ਼ੋਨ"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"ਸੈਂਸਰ ਬੰਦ ਕਰੋ"</string>
<string name="device_services" msgid="1549944177856658705">"ਡੀਵਾਈਸ ਸੇਵਾਵਾਂ"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"ਕੋਈ ਸਿਰਲੇਖ ਨਹੀਂ"</string>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index f5ef1a045bdd..56fcbb20f5b5 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -995,6 +995,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"Ustawienia"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"OK"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Zrzut stosu SysUI"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"Aplikacja <xliff:g id="APP">%1$s</xliff:g> używa: <xliff:g id="TYPES_LIST">%2$s</xliff:g>."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Aplikacje używają: <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" i "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"aparat"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"lokalizacja"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofon"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Wyłącz czujniki"</string>
<string name="device_services" msgid="1549944177856658705">"Usługi urządzenia"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Bez tytułu"</string>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index c8eaa0ddc4fb..88f603200dc5 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"Configurações"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"Ok"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Despejar heap SysUI"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"O app <xliff:g id="APP">%1$s</xliff:g> está usando <xliff:g id="TYPES_LIST">%2$s</xliff:g>."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Aplicativos estão usando <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" e "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"câmera"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"localização"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"microfone"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Sensores desativados"</string>
<string name="device_services" msgid="1549944177856658705">"Serviços do dispositivo"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Sem título"</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 341efff0e4cd..5fdb2853551d 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"Definições"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"OK"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Despejar pilha SysUI"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"A app <xliff:g id="APP">%1$s</xliff:g> está a utilizar o(a) <xliff:g id="TYPES_LIST">%2$s</xliff:g>."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"As aplicações estão a utilizar o(a) <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" e "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"câmara"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"localização"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"microfone"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Sensores desativados"</string>
<string name="device_services" msgid="1549944177856658705">"Serviços do dispositivo"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Sem título"</string>
@@ -1015,7 +1022,7 @@
<string name="priority_onboarding_behavior" msgid="5342816047020432929">"As conversas prioritárias irão:"</string>
<string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"Aparecer na parte superior da secção de conversas."</string>
<string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"Mostrar a imagem do perfil no ecrã de bloqueio."</string>
- <string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"Aparecem como balões flutuantes por cima de apps."</string>
+ <string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"Aparecer como balões flutuantes por cima de apps."</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"Interrompem o modo Não incomodar."</string>
<string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"OK"</string>
<string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Definições"</string>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index c8eaa0ddc4fb..88f603200dc5 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"Configurações"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"Ok"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Despejar heap SysUI"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"O app <xliff:g id="APP">%1$s</xliff:g> está usando <xliff:g id="TYPES_LIST">%2$s</xliff:g>."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Aplicativos estão usando <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" e "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"câmera"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"localização"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"microfone"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Sensores desativados"</string>
<string name="device_services" msgid="1549944177856658705">"Serviços do dispositivo"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Sem título"</string>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 08542c02c2e0..d5eecc76144c 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -990,6 +990,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"Setări"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"OK"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Extrageți memoria SysUI"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> folosește <xliff:g id="TYPES_LIST">%2$s</xliff:g>."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Aplicațiile folosesc <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" și "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"cameră foto"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"locație"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"microfon"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Senzori dezactivați"</string>
<string name="device_services" msgid="1549944177856658705">"Servicii pentru dispozitiv"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Fără titlu"</string>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 12c489e08e41..50850225c891 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -995,6 +995,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"Открыть настройки"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"ОК"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Передача SysUI"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"В приложении \"<xliff:g id="APP">%1$s</xliff:g>\" используется <xliff:g id="TYPES_LIST">%2$s</xliff:g>."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"В приложениях используется <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" и "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"камера"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"местоположение"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"микрофон"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Датчики отключены"</string>
<string name="device_services" msgid="1549944177856658705">"Сервисы устройства"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Без названия"</string>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index 412050f4bb7f..ff7e816f8336 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"සැකසීම්"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"තේරුණා"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> ඔබේ <xliff:g id="TYPES_LIST">%2$s</xliff:g> භාවිත කරමින් සිටී."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"යෙදුම් ඔබේ <xliff:g id="TYPES_LIST">%s</xliff:g> භාවිත කරමින් සිටී."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" සහ "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"කැමරාව"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"ස්ථානය"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"මයික්‍රෝෆෝනය"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"සංවේදක ක්‍රියාවිරහිතයි"</string>
<string name="device_services" msgid="1549944177856658705">"උපාංග සේවා"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"මාතෘකාවක් නැත"</string>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index f657d4fe71e7..a86da967ab62 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -995,6 +995,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"Nastavenia"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"Dobre"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> používa zoznam <xliff:g id="TYPES_LIST">%2$s</xliff:g>."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Aplikácie používajú zoznam <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" a "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"fotoaparát"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"poloha"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofón"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Senzory sú vypnuté"</string>
<string name="device_services" msgid="1549944177856658705">"Služby zariadenia"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Bez názvu"</string>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index e1e5852098b9..b9039d8c3cb9 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -995,6 +995,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"Nastavitve"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"V redu"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Izvoz kopice SysUI"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"Aplikacija <xliff:g id="APP">%1$s</xliff:g> uporablja <xliff:g id="TYPES_LIST">%2$s</xliff:g>."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Aplikacije uporabljajo <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" in "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"fotoaparat"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"lokacijo"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofon"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Izklop za tipala"</string>
<string name="device_services" msgid="1549944177856658705">"Storitve naprave"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Brez naslova"</string>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index 64d7a2ecac52..2972c5383bee 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"Cilësimet"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"E kuptova"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Hidh grumbullin SysUI"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> po përdor <xliff:g id="TYPES_LIST">%2$s</xliff:g>."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Aplikacionet po përdorin <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" dhe "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"kamerën"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"vendndodhjen"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofonin"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Sensorët joaktivë"</string>
<string name="device_services" msgid="1549944177856658705">"Shërbimet e pajisjes"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Pa titull"</string>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index fd6f57e64113..77cbb96b3691 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -990,6 +990,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"Подешавања"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"Важи"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Издвоји SysUI мем."</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> користи <xliff:g id="TYPES_LIST">%2$s</xliff:g>."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Апликације користе <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" и "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"камеру"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"локацију"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"микрофон"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Сензори су искључени"</string>
<string name="device_services" msgid="1549944177856658705">"Услуге за уређаје"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Без наслова"</string>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index f96dd27aba6d..c7eda4567a68 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"Inställningar"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"OK"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI-heap"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="TYPES_LIST">%2$s</xliff:g> används av <xliff:g id="APP">%1$s</xliff:g>."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"<xliff:g id="TYPES_LIST">%s</xliff:g> används av appar."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" och "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"kamera"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"plats"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofon"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Sensorer har inaktiverats"</string>
<string name="device_services" msgid="1549944177856658705">"Enhetstjänster"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Ingen titel"</string>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 8b8c24983e98..2804f2f1e106 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"Mipangilio"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"Nimeelewa"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> inatumia <xliff:g id="TYPES_LIST">%2$s</xliff:g> yako."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Programu zinatumia <xliff:g id="TYPES_LIST">%s</xliff:g> yako."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" na "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"kamera"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"mahali"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"maikrofoni"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Umezima vitambuzi"</string>
<string name="device_services" msgid="1549944177856658705">"Huduma za Kifaa"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Wimbo hauna jina"</string>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index b97e266850c6..ee176fa3c57d 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"அமைப்புகள்"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"சரி"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"உங்கள் <xliff:g id="TYPES_LIST">%2$s</xliff:g>ஐ <xliff:g id="APP">%1$s</xliff:g> ஆப்ஸ் பயன்படுத்துகிறது."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"உங்கள் <xliff:g id="TYPES_LIST">%s</xliff:g> ஆகியவற்றை ஆப்ஸ் பயன்படுத்துகின்றன."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" மற்றும் "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"கேமரா"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"இருப்பிடம்"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"மைக்ரோஃபோன்"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"சென்சார்களை ஆஃப் செய்தல்"</string>
<string name="device_services" msgid="1549944177856658705">"சாதன சேவைகள்"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"தலைப்பு இல்லை"</string>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index 13319d9719b8..dc5ea1f29fb5 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"సెట్టింగ్‌లు"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"అర్థమైంది"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"డంప్ SysUI హీప్"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> మీ <xliff:g id="TYPES_LIST">%2$s</xliff:g>ని ఉపయోగిస్తోంది."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"అప్లికేషన్‌లు మీ <xliff:g id="TYPES_LIST">%s</xliff:g>ని ఉపయోగిస్తున్నాయి."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" మరియు "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"కెమెరా"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"లొకేషన్"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"మైక్రోఫోన్"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"సెన్సార్‌లు ఆఫ్"</string>
<string name="device_services" msgid="1549944177856658705">"పరికర సేవలు"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"శీర్షిక లేదు"</string>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index e1c0e7e7a614..ba9fd296f607 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"การตั้งค่า"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"รับทราบ"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> ใช้<xliff:g id="TYPES_LIST">%2$s</xliff:g>ของคุณอยู่"</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"หลายแอปพลิเคชันใช้<xliff:g id="TYPES_LIST">%s</xliff:g>ของคุณอยู่"</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" และ "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"กล้องถ่ายรูป"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"ตำแหน่ง"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"ไมโครโฟน"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"ปิดเซ็นเซอร์"</string>
<string name="device_services" msgid="1549944177856658705">"บริการของอุปกรณ์"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"ไม่มีชื่อ"</string>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 20a34e1ded0d..069438f2caed 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"Mga Setting"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"OK"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"Ginagamit ng <xliff:g id="APP">%1$s</xliff:g> ang iyong <xliff:g id="TYPES_LIST">%2$s</xliff:g>."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Ginagamit ng mga application ang iyong <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" at "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"camera"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"lokasyon"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"mikropono"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Naka-off ang mga sensor"</string>
<string name="device_services" msgid="1549944177856658705">"Mga Serbisyo ng Device"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Walang pamagat"</string>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 4146f307ac18..649b9af53ff6 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"Ayarlar"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"Anladım"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"SysUI Yığın Dökümü"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> şunları kullanıyor: <xliff:g id="TYPES_LIST">%2$s</xliff:g>."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Uygulamalar şunları kullanıyor: <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" ve "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"kamera"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"konum"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofon"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Sensörler kapalı"</string>
<string name="device_services" msgid="1549944177856658705">"Cihaz Hizmetleri"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Başlıksız"</string>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 11eb18cc48d2..6cb3ac8ce915 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -995,6 +995,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"Налаштування"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"OK"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"Додаток <xliff:g id="APP">%1$s</xliff:g> використовує <xliff:g id="TYPES_LIST">%2$s</xliff:g>."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Додатки використовують <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" і "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"камеру"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"місце"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"мікрофон"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Датчики вимкнено"</string>
<string name="device_services" msgid="1549944177856658705">"Сервіси на пристрої"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Без назви"</string>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index d7645e9bcb5b..804c33436ea6 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"ترتیبات"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"سمجھ آ گئی"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> آپ کی <xliff:g id="TYPES_LIST">%2$s</xliff:g> کا استعمال کر رہی ہے۔"</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"ایپلیکیشنز آپ کی <xliff:g id="TYPES_LIST">%s</xliff:g> کا استعمال کر رہی ہیں۔"</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">"، "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" اور "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"کیمرا"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"مقام"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"مائیکروفون"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"سینسرز آف ہیں"</string>
<string name="device_services" msgid="1549944177856658705">"آلہ کی سروس"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"کوئی عنوان نہیں ہے"</string>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index 1fc4f9bea270..6193d33961e6 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"Sozlamalar"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"OK"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Dump SysUI Heap"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> ishlatmoqda: <xliff:g id="TYPES_LIST">%2$s</xliff:g>."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Ilovalarda ishlatilmoqda: <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" va "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"kamera"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"joylashuv"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"mikrofon"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Sensorlar nofaol"</string>
<string name="device_services" msgid="1549944177856658705">"Qurilma xizmatlari"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Nomsiz"</string>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index 8df5ee530210..97ffbc623e02 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"Cài đặt"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"OK"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"Trích xuất bộ nhớ SysUI"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g> đang dùng <xliff:g id="TYPES_LIST">%2$s</xliff:g> của bạn."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Các ứng dụng đang dùng <xliff:g id="TYPES_LIST">%s</xliff:g> của bạn."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" và "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"máy ảnh"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"vị trí"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"micrô"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Tắt cảm biến"</string>
<string name="device_services" msgid="1549944177856658705">"Dịch vụ cho thiết bị"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Không có tiêu đề"</string>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index c51982cddac3..b9b146c9fb4b 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"设置"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"知道了"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"转储 SysUI 堆"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"<xliff:g id="APP">%1$s</xliff:g>正在使用您的<xliff:g id="TYPES_LIST">%2$s</xliff:g>。"</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"有多个应用正在使用您的<xliff:g id="TYPES_LIST">%s</xliff:g>。"</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">"、 "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" 和 "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"相机"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"位置信息"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"麦克风"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"已关闭传感器"</string>
<string name="device_services" msgid="1549944177856658705">"设备服务"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"无标题"</string>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index aa9945fbd956..f2cb185078b5 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"設定"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"知道了"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"轉儲 SysUI 堆"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"「<xliff:g id="APP">%1$s</xliff:g>」正在使用<xliff:g id="TYPES_LIST">%2$s</xliff:g>。"</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"有多個應用程式正在使用<xliff:g id="TYPES_LIST">%s</xliff:g>。"</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">"、 "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" 和 "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"相機"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"位置"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"麥克風"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"感應器已關閉"</string>
<string name="device_services" msgid="1549944177856658705">"裝置服務"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"無標題"</string>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 92bdfc3f1219..69b52946d698 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"設定"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"我知道了"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"傾印 SysUI 記憶體快照"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"「<xliff:g id="APP">%1$s</xliff:g>」正在使用<xliff:g id="TYPES_LIST">%2$s</xliff:g>。"</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"有多個應用程式正在使用<xliff:g id="TYPES_LIST">%s</xliff:g>。"</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">"、 "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" 和 "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"相機"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"位置"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"麥克風"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"已關閉感應器"</string>
<string name="device_services" msgid="1549944177856658705">"裝置服務"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"無標題"</string>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 4ae126799141..5b899f93e5f9 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -985,6 +985,13 @@
<string name="open_saver_setting_action" msgid="2111461909782935190">"Izilungiselelo"</string>
<string name="auto_saver_okay_action" msgid="7815925750741935386">"Ngiyezwa"</string>
<string name="heap_dump_tile_name" msgid="2464189856478823046">"I-Dump SysUI Heap"</string>
+ <string name="ongoing_privacy_chip_content_single_app" msgid="2969750601815230385">"I-<xliff:g id="APP">%1$s</xliff:g> isebenzisa i-<xliff:g id="TYPES_LIST">%2$s</xliff:g> yakho."</string>
+ <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Izinhlelo zokusebenza zisebenzisa i-<xliff:g id="TYPES_LIST">%s</xliff:g> yakho."</string>
+ <string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
+ <string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" kanye "</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"ikhamera"</string>
+ <string name="privacy_type_location" msgid="7991481648444066703">"indawo"</string>
+ <string name="privacy_type_microphone" msgid="9136763906797732428">"imakrofoni"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"Izinzwa zivaliwe"</string>
<string name="device_services" msgid="1549944177856658705">"Amasevisi edivayisi"</string>
<string name="music_controls_no_title" msgid="4166497066552290938">"Asikho isihloko"</string>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index f407a8dcc57f..fa620df12b87 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -161,10 +161,6 @@
<!-- The number of milliseconds to extend ambient pulse by when prompted (e.g. on touch) -->
<integer name="ambient_notification_extension_time">10000</integer>
- <!-- In multi-window, determines whether the stack where recents lives should grow from
- the smallest position when being launched. -->
- <bool name="recents_grow_in_multiwindow">true</bool>
-
<!-- Animation duration when using long press on recents to dock -->
<integer name="long_press_dock_anim_duration">250</integer>
@@ -522,6 +518,8 @@
<!-- Defines the blacklist for system icons. That is to say, the icons in the status bar that
are part of the blacklist are never displayed. Each item in the blacklist must be a string
defined in core/res/res/config.xml to properly blacklist the icon.
+
+ TODO: See if we can rename this config variable.
-->
<string-array name="config_statusBarIconBlackList" translatable="false">
<item>@*android:string/status_bar_rotate</item>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 8b6543ac73bd..77d3f4513957 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -2838,4 +2838,9 @@
<string name="udfps_hbm_enable_command" translatable="false"></string>
<!-- Device-specific payload for disabling the high-brightness mode -->
<string name="udfps_hbm_disable_command" translatable="false"></string>
+
+ <!-- One-Handed Tutorial title [CHAR LIMIT=60] -->
+ <string name="one_handed_tutorial_title">Using one-handed mode</string>
+ <!-- One-Handed Tutorial description [CHAR LIMIT=NONE] -->
+ <string name="one_handed_tutorial_description">To exit, swipe up from the bottom of the screen or tap anywhere above the app</string>
</resources>
diff --git a/packages/SystemUI/res/xml/one_handed_tutorial.xml b/packages/SystemUI/res/xml/one_handed_tutorial.xml
new file mode 100644
index 000000000000..dc54caf0f14a
--- /dev/null
+++ b/packages/SystemUI/res/xml/one_handed_tutorial.xml
@@ -0,0 +1,67 @@
+<?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
+ -->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/one_handed_tutorial_layout"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:gravity="center_horizontal | center_vertical"
+ android:background="@android:color/transparent">
+
+ <ImageView
+ android:id="@+id/one_handed_tutorial_image"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="6dp"
+ android:layout_marginBottom="0dp"
+ android:gravity="center_horizontal"
+ android:src="@drawable/one_handed_tutorial"
+ android:scaleType="centerInside" />
+
+ <TextView
+ android:id="@+id/one_handed_tutorial_title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="6dp"
+ android:layout_marginBottom="0dp"
+ android:gravity="center_horizontal"
+ android:textAlignment="center"
+ android:fontFamily="google-sans-medium"
+ android:text="@string/one_handed_tutorial_title"
+ android:textSize="16sp"
+ android:textStyle="bold"
+ android:textColor="@android:color/white"/>
+
+ <TextView
+ android:id="@+id/one_handed_tutorial_description"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="6dp"
+ android:layout_marginBottom="0dp"
+ android:layout_marginStart="86dp"
+ android:layout_marginEnd="86dp"
+ android:gravity="center_horizontal"
+ android:fontFamily="roboto-regular"
+ android:text="@string/one_handed_tutorial_description"
+ android:textAlignment="center"
+ android:textSize="14sp"
+ android:textStyle="normal"
+ android:alpha="0.7"
+ android:textColor="@android:color/white"/>
+</LinearLayout>
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
index 158763a9ddab..ecf1c2c91770 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
@@ -1,10 +1,7 @@
package com.android.keyguard;
-import static com.android.systemui.util.InjectionInflationController.VIEW_CONTEXT;
-
import android.animation.Animator;
import android.animation.ValueAnimator;
-import android.app.WallpaperManager;
import android.content.Context;
import android.graphics.Paint;
import android.graphics.Paint.Style;
@@ -24,16 +21,10 @@ import android.widget.FrameLayout;
import android.widget.RelativeLayout;
import android.widget.TextClock;
-import androidx.annotation.VisibleForTesting;
-
import com.android.internal.colorextraction.ColorExtractor;
-import com.android.internal.colorextraction.ColorExtractor.OnColorsChangedListener;
-import com.android.keyguard.clock.ClockManager;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
-import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.plugins.ClockPlugin;
-import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.util.wakelock.KeepAwakeAnimationListener;
@@ -42,16 +33,12 @@ import java.io.PrintWriter;
import java.util.Arrays;
import java.util.TimeZone;
-import javax.inject.Inject;
-import javax.inject.Named;
-
/**
* Switch to show plugin clock when plugin is connected, otherwise it will show default clock.
*/
public class KeyguardClockSwitch extends RelativeLayout {
private static final String TAG = "KeyguardClockSwitch";
- private static final boolean CUSTOM_CLOCKS_ENABLED = true;
/**
* Animation fraction when text is transitioned to/from bold.
@@ -59,21 +46,6 @@ public class KeyguardClockSwitch extends RelativeLayout {
private static final float TO_BOLD_TRANSITION_FRACTION = 0.7f;
/**
- * Controller used to track StatusBar state to know when to show the big_clock_container.
- */
- private final StatusBarStateController mStatusBarStateController;
-
- /**
- * Color extractor used to apply colors from wallpaper to custom clock faces.
- */
- private final SysuiColorExtractor mSysuiColorExtractor;
-
- /**
- * Manager used to know when to show a custom clock face.
- */
- private final ClockManager mClockManager;
-
- /**
* Layout transition that scales the default clock face.
*/
private final Transition mTransition;
@@ -130,42 +102,8 @@ public class KeyguardClockSwitch extends RelativeLayout {
private boolean mSupportsDarkText;
private int[] mColorPalette;
- /**
- * Track the state of the status bar to know when to hide the big_clock_container.
- */
- private int mStatusBarState;
-
- private final StatusBarStateController.StateListener mStateListener =
- new StatusBarStateController.StateListener() {
- @Override
- public void onStateChanged(int newState) {
- mStatusBarState = newState;
- updateBigClockVisibility();
- }
- };
-
- private ClockManager.ClockChangedListener mClockChangedListener = this::setClockPlugin;
-
- /**
- * Listener for changes to the color palette.
- *
- * The color palette changes when the wallpaper is changed.
- */
- private final OnColorsChangedListener mColorsListener = (extractor, which) -> {
- if ((which & WallpaperManager.FLAG_LOCK) != 0) {
- updateColors();
- }
- };
-
- @Inject
- public KeyguardClockSwitch(@Named(VIEW_CONTEXT) Context context, AttributeSet attrs,
- StatusBarStateController statusBarStateController, SysuiColorExtractor colorExtractor,
- ClockManager clockManager) {
+ public KeyguardClockSwitch(Context context, AttributeSet attrs) {
super(context, attrs);
- mStatusBarStateController = statusBarStateController;
- mStatusBarState = mStatusBarStateController.getState();
- mSysuiColorExtractor = colorExtractor;
- mClockManager = clockManager;
mClockTransition = new ClockVisibilityTransition().setCutoff(
1 - TO_BOLD_TRANSITION_FRACTION);
@@ -197,29 +135,7 @@ public class KeyguardClockSwitch extends RelativeLayout {
mKeyguardStatusArea = findViewById(R.id.keyguard_status_area);
}
- @Override
- protected void onAttachedToWindow() {
- super.onAttachedToWindow();
- if (CUSTOM_CLOCKS_ENABLED) {
- mClockManager.addOnClockChangedListener(mClockChangedListener);
- }
- mStatusBarStateController.addCallback(mStateListener);
- mSysuiColorExtractor.addOnColorsChangedListener(mColorsListener);
- updateColors();
- }
-
- @Override
- protected void onDetachedFromWindow() {
- super.onDetachedFromWindow();
- if (CUSTOM_CLOCKS_ENABLED) {
- mClockManager.removeOnClockChangedListener(mClockChangedListener);
- }
- mStatusBarStateController.removeCallback(mStateListener);
- mSysuiColorExtractor.removeOnColorsChangedListener(mColorsListener);
- setClockPlugin(null);
- }
-
- private void setClockPlugin(ClockPlugin plugin) {
+ void setClockPlugin(ClockPlugin plugin, int statusBarState) {
// Disconnect from existing plugin.
if (mClockPlugin != null) {
View smallClockView = mClockPlugin.getView();
@@ -228,7 +144,7 @@ public class KeyguardClockSwitch extends RelativeLayout {
}
if (mBigClockContainer != null) {
mBigClockContainer.removeAllViews();
- updateBigClockVisibility();
+ updateBigClockVisibility(statusBarState);
}
mClockPlugin.onDestroyView();
mClockPlugin = null;
@@ -256,7 +172,7 @@ public class KeyguardClockSwitch extends RelativeLayout {
View bigClockView = plugin.getBigClockView();
if (bigClockView != null && mBigClockContainer != null) {
mBigClockContainer.addView(bigClockView);
- updateBigClockVisibility();
+ updateBigClockVisibility(statusBarState);
}
// Hide default clock.
if (!plugin.shouldShowStatusArea()) {
@@ -275,7 +191,7 @@ public class KeyguardClockSwitch extends RelativeLayout {
/**
* Set container for big clock face appearing behind NSSL and KeyguardStatusView.
*/
- public void setBigClockContainer(ViewGroup container) {
+ public void setBigClockContainer(ViewGroup container, int statusBarState) {
if (mClockPlugin != null && container != null) {
View bigClockView = mClockPlugin.getBigClockView();
if (bigClockView != null) {
@@ -283,7 +199,7 @@ public class KeyguardClockSwitch extends RelativeLayout {
}
}
mBigClockContainer = container;
- updateBigClockVisibility();
+ updateBigClockVisibility(statusBarState);
}
/**
@@ -407,9 +323,7 @@ public class KeyguardClockSwitch extends RelativeLayout {
}
}
- private void updateColors() {
- ColorExtractor.GradientColors colors = mSysuiColorExtractor.getColors(
- WallpaperManager.FLAG_LOCK);
+ void updateColors(ColorExtractor.GradientColors colors) {
mSupportsDarkText = colors.supportsDarkText();
mColorPalette = colors.getColorPalette();
if (mClockPlugin != null) {
@@ -417,12 +331,12 @@ public class KeyguardClockSwitch extends RelativeLayout {
}
}
- private void updateBigClockVisibility() {
+ void updateBigClockVisibility(int statusBarState) {
if (mBigClockContainer == null) {
return;
}
- final boolean inDisplayState = mStatusBarState == StatusBarState.KEYGUARD
- || mStatusBarState == StatusBarState.SHADE_LOCKED;
+ final boolean inDisplayState = statusBarState == StatusBarState.KEYGUARD
+ || statusBarState == StatusBarState.SHADE_LOCKED;
final int visibility = !mShowingHeader && inDisplayState
&& mBigClockContainer.getChildCount() != 0 ? View.VISIBLE : View.GONE;
if (mBigClockContainer.getVisibility() != visibility) {
@@ -506,16 +420,6 @@ public class KeyguardClockSwitch extends RelativeLayout {
}
}
- @VisibleForTesting(otherwise = VisibleForTesting.NONE)
- ClockManager.ClockChangedListener getClockChangedListener() {
- return mClockChangedListener;
- }
-
- @VisibleForTesting(otherwise = VisibleForTesting.NONE)
- StatusBarStateController.StateListener getStateListener() {
- return mStateListener;
- }
-
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
pw.println("KeyguardClockSwitch:");
pw.println(" mClockPlugin: " + mClockPlugin);
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
new file mode 100644
index 000000000000..f17f1ca797e0
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
@@ -0,0 +1,119 @@
+/*
+ * 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.keyguard;
+
+import android.app.WallpaperManager;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.android.internal.colorextraction.ColorExtractor;
+import com.android.keyguard.clock.ClockManager;
+import com.android.systemui.colorextraction.SysuiColorExtractor;
+import com.android.systemui.plugins.ClockPlugin;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+
+import javax.inject.Inject;
+
+/**
+ * Injectable controller for {@link KeyguardClockSwitch}.
+ */
+public class KeyguardClockSwitchController {
+ private static final boolean CUSTOM_CLOCKS_ENABLED = true;
+
+ private final StatusBarStateController mStatusBarStateController;
+ private final SysuiColorExtractor mColorExtractor;
+ private final ClockManager mClockManager;
+ private KeyguardClockSwitch mView;
+
+ private final StatusBarStateController.StateListener mStateListener =
+ new StatusBarStateController.StateListener() {
+ @Override
+ public void onStateChanged(int newState) {
+ mView.updateBigClockVisibility(newState);
+ }
+ };
+
+ /**
+ * Listener for changes to the color palette.
+ *
+ * The color palette changes when the wallpaper is changed.
+ */
+ private final ColorExtractor.OnColorsChangedListener mColorsListener = (extractor, which) -> {
+ if ((which & WallpaperManager.FLAG_LOCK) != 0) {
+ mView.updateColors(getGradientColors());
+ }
+ };
+
+ private ClockManager.ClockChangedListener mClockChangedListener = this::setClockPlugin;
+
+ private final View.OnAttachStateChangeListener mOnAttachStateChangeListener =
+ new View.OnAttachStateChangeListener() {
+ @Override
+ public void onViewAttachedToWindow(View v) {
+ if (CUSTOM_CLOCKS_ENABLED) {
+ mClockManager.addOnClockChangedListener(mClockChangedListener);
+ }
+ mStatusBarStateController.addCallback(mStateListener);
+ mColorExtractor.addOnColorsChangedListener(mColorsListener);
+ mView.updateColors(getGradientColors());
+ }
+
+ @Override
+ public void onViewDetachedFromWindow(View v) {
+ if (CUSTOM_CLOCKS_ENABLED) {
+ mClockManager.removeOnClockChangedListener(mClockChangedListener);
+ }
+ mStatusBarStateController.removeCallback(mStateListener);
+ mColorExtractor.removeOnColorsChangedListener(mColorsListener);
+ mView.setClockPlugin(null, mStatusBarStateController.getState());
+ }
+ };
+
+ @Inject
+ public KeyguardClockSwitchController(StatusBarStateController statusBarStateController,
+ SysuiColorExtractor colorExtractor, ClockManager clockManager) {
+ mStatusBarStateController = statusBarStateController;
+ mColorExtractor = colorExtractor;
+ mClockManager = clockManager;
+ }
+
+ /**
+ * Attach the controller to the view it relates to.
+ */
+ public void attach(KeyguardClockSwitch view) {
+ mView = view;
+ if (mView.isAttachedToWindow()) {
+ mOnAttachStateChangeListener.onViewAttachedToWindow(mView);
+ }
+ mView.addOnAttachStateChangeListener(mOnAttachStateChangeListener);
+ }
+
+ /**
+ * Set container for big clock face appearing behind NSSL and KeyguardStatusView.
+ */
+ public void setBigClockContainer(ViewGroup bigClockContainer) {
+ mView.setBigClockContainer(bigClockContainer, mStatusBarStateController.getState());
+ }
+
+ private void setClockPlugin(ClockPlugin plugin) {
+ mView.setClockPlugin(plugin, mStatusBarStateController.getState());
+ }
+
+ private ColorExtractor.GradientColors getGradientColors() {
+ return mColorExtractor.getColors(WallpaperManager.FLAG_LOCK);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java
index 76adf04b21e7..1c47aa0151f0 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java
@@ -141,7 +141,7 @@ public class KeyguardSimPinView extends KeyguardPinBasedInputView {
// Sending empty PIN here to query the number of remaining PIN attempts
new CheckSimPin("", mSubId) {
void onSimCheckResponse(final PinResult result) {
- Log.d(LOG_TAG, "onSimCheckResponse " + " dummy One result "
+ Log.d(LOG_TAG, "onSimCheckResponse " + " empty One result "
+ result.toString());
if (result.getAttemptsRemaining() >= 0) {
mRemainingAttempts = result.getAttemptsRemaining();
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukView.java
index a84664ceee3d..5148dd709026 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukView.java
@@ -195,7 +195,7 @@ public class KeyguardSimPukView extends KeyguardPinBasedInputView {
void onSimLockChangedResponse(final PinResult result) {
if (result == null) Log.e(LOG_TAG, "onSimCheckResponse, pin result is NULL");
else {
- Log.d(LOG_TAG, "onSimCheckResponse " + " dummy One result "
+ Log.d(LOG_TAG, "onSimCheckResponse " + " empty One result "
+ result.toString());
if (result.getAttemptsRemaining() >= 0) {
mRemainingAttempts = result.getAttemptsRemaining();
diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
index 58698151b655..521bb8d58c2b 100644
--- a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
+++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
@@ -225,7 +225,7 @@ public class BatteryMeterView extends LinearLayout implements
}
Dependency.get(TunerService.class)
- .addTunable(this, StatusBarIconController.ICON_BLACKLIST);
+ .addTunable(this, StatusBarIconController.ICON_HIDE_LIST);
mIsSubscribedForTunerUpdates = true;
}
@@ -278,8 +278,8 @@ public class BatteryMeterView extends LinearLayout implements
@Override
public void onTuningChanged(String key, String newValue) {
- if (StatusBarIconController.ICON_BLACKLIST.equals(key)) {
- ArraySet<String> icons = StatusBarIconController.getIconBlacklist(
+ if (StatusBarIconController.ICON_HIDE_LIST.equals(key)) {
+ ArraySet<String> icons = StatusBarIconController.getIconHideList(
getContext(), newValue);
setVisibility(icons.contains(mSlotBattery) ? View.GONE : View.VISIBLE);
}
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index 4dbb92e1e37f..58f8c07ad7c9 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -131,9 +131,9 @@ import java.util.function.Consumer;
import javax.inject.Inject;
import javax.inject.Named;
+import javax.inject.Singleton;
import dagger.Lazy;
-import dagger.Subcomponent;
/**
* Class to handle ugly dependencies throughout sysui until we determine the
@@ -150,6 +150,7 @@ import dagger.Subcomponent;
* they have no clients they should not have any registered resources like bound
* services, registered receivers, etc.
*/
+@Singleton
public class Dependency {
/**
* Key for getting a the main looper.
@@ -522,7 +523,12 @@ public class Dependency {
mProviders.put(RecordingController.class, mRecordingController::get);
mProviders.put(Divider.class, mDivider::get);
- sDependency = this;
+ Dependency.setInstance(this);
+ }
+
+ @VisibleForTesting
+ public static void setInstance(Dependency dependency) {
+ sDependency = dependency;
}
protected final <T> T getDependency(Class<T> cls) {
@@ -549,7 +555,7 @@ public class Dependency {
}
@VisibleForTesting
- protected <T> T createDependency(Object cls) {
+ public <T> T createDependency(Object cls) {
Preconditions.checkArgument(cls instanceof DependencyKey<?> || cls instanceof Class<?>);
@SuppressWarnings("unchecked")
@@ -638,9 +644,4 @@ public class Dependency {
return mDisplayName;
}
}
-
- @Subcomponent
- public interface DependencyInjector {
- void createSystemUI(Dependency dependency);
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
index 5674fdd3bb36..1a15c0aae8c1 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
@@ -16,7 +16,6 @@
package com.android.systemui;
-import android.annotation.NonNull;
import android.content.Context;
import android.content.res.Resources;
import android.os.Handler;
@@ -30,7 +29,6 @@ import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.ViewMediatorCallback;
import com.android.systemui.bubbles.BubbleController;
import com.android.systemui.dagger.DaggerSystemUIRootComponent;
-import com.android.systemui.dagger.DependencyProvider;
import com.android.systemui.dagger.SystemUIRootComponent;
import com.android.systemui.keyguard.DismissCallbackRegistry;
import com.android.systemui.plugins.FalsingManager;
@@ -48,9 +46,6 @@ import com.android.systemui.statusbar.policy.KeyguardStateController;
import java.util.concurrent.Executor;
-import dagger.Module;
-import dagger.Provides;
-
/**
* Class factory to provide customizable SystemUI components.
*/
@@ -97,24 +92,13 @@ public class SystemUIFactory {
// Every other part of our codebase currently relies on Dependency, so we
// really need to ensure the Dependency gets initialized early on.
-
- Dependency dependency = new Dependency();
- mRootComponent.createDependency().createSystemUI(dependency);
+ Dependency dependency = mRootComponent.createDependency();
dependency.start();
}
- protected void initWithRootComponent(@NonNull SystemUIRootComponent rootComponent) {
- if (mRootComponent != null) {
- throw new RuntimeException("Root component can be set only once.");
- }
-
- mRootComponent = rootComponent;
- }
-
protected SystemUIRootComponent buildSystemUIRootComponent(Context context) {
return DaggerSystemUIRootComponent.builder()
- .dependencyProvider(new DependencyProvider())
- .contextHolder(new ContextHolder(context))
+ .context(context)
.build();
}
@@ -168,18 +152,4 @@ public class SystemUIFactory {
Dependency.get(DozeParameters.class),
Dependency.get(BubbleController.class));
}
-
- @Module
- public static class ContextHolder {
- private Context mContext;
-
- public ContextHolder(Context context) {
- mContext = context;
- }
-
- @Provides
- public Context provideContext() {
- return mContext;
- }
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/DisplayIdIndexSupplier.java b/packages/SystemUI/src/com/android/systemui/accessibility/DisplayIdIndexSupplier.java
index 769a344eedac..d5aac1a95847 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/DisplayIdIndexSupplier.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/DisplayIdIndexSupplier.java
@@ -60,6 +60,20 @@ abstract class DisplayIdIndexSupplier<T> {
return instance;
}
+ /**
+ * Gets the object by the element index.
+ *
+ * <p> If the index is bigger than the array size, an {@link ArrayIndexOutOfBoundsException} is
+ * thrown for apps targeting {@link android.os.Build.VERSION_CODES#Q} and later </p>
+ *
+ * @param index the element index
+ * @return T
+ * @see SparseArray#valueAt(int)
+ */
+ public T valueAt(int index) {
+ return mSparseArray.valueAt(index);
+ }
+
@NonNull
protected abstract T createInstance(Display display);
@@ -78,4 +92,13 @@ abstract class DisplayIdIndexSupplier<T> {
public void clear() {
mSparseArray.clear();
}
+
+ /**
+ * Gets the element size.
+ *
+ * @return size of all elements
+ */
+ public int getSize() {
+ return mSparseArray.size();
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationModeSwitch.java b/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationModeSwitch.java
index 68a0a65ef50f..34f721c94ed2 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationModeSwitch.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationModeSwitch.java
@@ -18,6 +18,7 @@ package com.android.systemui.accessibility;
import android.annotation.NonNull;
import android.content.Context;
+import android.content.pm.ActivityInfo;
import android.graphics.PixelFormat;
import android.provider.Settings;
import android.view.Gravity;
@@ -102,6 +103,14 @@ class MagnificationModeSwitch {
.start();
}
+ void onConfigurationChanged(int configDiff) {
+ if ((configDiff & ActivityInfo.CONFIG_DENSITY) == 0) {
+ return;
+ }
+ applyResourcesValues();
+ mImageView.setImageResource(getIconResId(mMagnificationMode));
+ }
+
private void toggleMagnificationMode() {
final int newMode =
mMagnificationMode ^ Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_ALL;
@@ -112,7 +121,7 @@ class MagnificationModeSwitch {
}
private static ImageView createView(Context context) {
- ImageView imageView = new ImageView(context);
+ ImageView imageView = new ImageView(context);
imageView.setClickable(true);
imageView.setFocusable(true);
imageView.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/ModeSwitchesController.java b/packages/SystemUI/src/com/android/systemui/accessibility/ModeSwitchesController.java
index ffc70bcf63d0..fe07ab67c707 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/ModeSwitchesController.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/ModeSwitchesController.java
@@ -36,7 +36,7 @@ import javax.inject.Singleton;
@Singleton
public class ModeSwitchesController {
- private final SwitchSupplier mSwitchSupplier;
+ private final DisplayIdIndexSupplier<MagnificationModeSwitch> mSwitchSupplier;
public ModeSwitchesController(Context context) {
mSwitchSupplier = new SwitchSupplier(context,
@@ -44,7 +44,7 @@ public class ModeSwitchesController {
}
@VisibleForTesting
- ModeSwitchesController(SwitchSupplier switchSupplier) {
+ ModeSwitchesController(DisplayIdIndexSupplier<MagnificationModeSwitch> switchSupplier) {
mSwitchSupplier = switchSupplier;
}
@@ -81,8 +81,22 @@ public class ModeSwitchesController {
magnificationModeSwitch.removeButton();
}
- @VisibleForTesting
- static class SwitchSupplier extends DisplayIdIndexSupplier<MagnificationModeSwitch> {
+ /**
+ * Called when the configuration has changed, and it updates magnification button UI.
+ *
+ * @param configDiff a bit mask of the differences between the configurations
+ */
+ @MainThread
+ void onConfigurationChanged(int configDiff) {
+ for (int i = 0; i < mSwitchSupplier.getSize(); i++) {
+ final MagnificationModeSwitch magnificationModeSwitch = mSwitchSupplier.valueAt(i);
+ if (magnificationModeSwitch != null) {
+ magnificationModeSwitch.onConfigurationChanged(configDiff);
+ }
+ }
+ }
+
+ private static class SwitchSupplier extends DisplayIdIndexSupplier<MagnificationModeSwitch> {
private final Context mContext;
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java
index 426e400c9fb9..816bcf8f274b 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java
@@ -25,6 +25,7 @@ import android.graphics.Rect;
import android.os.Handler;
import android.os.RemoteException;
import android.util.Log;
+import android.view.SurfaceControl;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.IWindowMagnificationConnection;
import android.view.accessibility.IWindowMagnificationConnectionCallback;
@@ -83,6 +84,9 @@ public class WindowMagnification extends SystemUI implements WindowMagnifierCall
if (mWindowMagnificationController != null) {
mWindowMagnificationController.onConfigurationChanged(configDiff);
}
+ if (mModeSwitchesController != null) {
+ mModeSwitchesController.onConfigurationChanged(configDiff);
+ }
}
@Override
@@ -97,7 +101,7 @@ public class WindowMagnification extends SystemUI implements WindowMagnifierCall
mWindowMagnificationController = new WindowMagnificationController(mContext,
mHandler,
new SfVsyncFrameCallbackProvider(),
- null,
+ null, new SurfaceControl.Transaction(),
this);
}
mWindowMagnificationController.enableWindowMagnification(scale, centerX, centerY);
@@ -136,6 +140,13 @@ public class WindowMagnification extends SystemUI implements WindowMagnifierCall
}
@Override
+ public void onSourceBoundsChanged(int displayId, Rect sourceBounds) {
+ if (mWindowMagnificationConnectionImpl != null) {
+ mWindowMagnificationConnectionImpl.onSourceBoundsChanged(displayId, sourceBounds);
+ }
+ }
+
+ @Override
public void requestWindowMagnificationConnection(boolean connect) {
if (connect) {
setWindowMagnificationConnection();
@@ -225,5 +236,15 @@ public class WindowMagnification extends SystemUI implements WindowMagnifierCall
}
}
}
+
+ void onSourceBoundsChanged(int displayId, Rect sourceBounds) {
+ if (mConnectionCallback != null) {
+ try {
+ mConnectionCallback.onSourceBoundsChanged(displayId, sourceBounds);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to inform source bounds changed", e);
+ }
+ }
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
index 8b6581ff1856..798b751c03ee 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
@@ -67,7 +67,7 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
@Surface.Rotation
private int mRotation;
private final Rect mMagnificationFrame = new Rect();
- private final SurfaceControl.Transaction mTransaction = new SurfaceControl.Transaction();
+ private final SurfaceControl.Transaction mTransaction;
private final WindowManager mWm;
@@ -75,6 +75,7 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
private final Rect mTmpRect = new Rect();
private final Rect mMirrorViewBounds = new Rect();
+ private final Rect mSourceBounds = new Rect();
// The root of the mirrored content
private SurfaceControl mMirrorSurface;
@@ -101,22 +102,14 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
private final Rect mMagnificationFrameBoundary = new Rect();
private final SfVsyncFrameCallbackProvider mSfVsyncFrameProvider;
- private final Choreographer.FrameCallback mMirrorViewGeometryVsyncCallback =
- l -> {
- if (mMirrorView != null) {
- final Rect sourceBounds = getSourceBounds(mMagnificationFrame, mScale);
- mTransaction.setGeometry(mMirrorSurface, sourceBounds, mTmpRect,
- Surface.ROTATION_0).apply();
- }
- };
+ private Choreographer.FrameCallback mMirrorViewGeometryVsyncCallback;
@Nullable
private MirrorWindowControl mMirrorWindowControl;
- WindowMagnificationController(Context context,
- @NonNull Handler handler,
+ WindowMagnificationController(Context context, @NonNull Handler handler,
SfVsyncFrameCallbackProvider sfVsyncFrameProvider,
- MirrorWindowControl mirrorWindowControl,
+ MirrorWindowControl mirrorWindowControl, SurfaceControl.Transaction transaction,
@NonNull WindowMagnifierCallback callback) {
mContext = context;
mHandler = handler;
@@ -137,6 +130,7 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
if (mMirrorWindowControl != null) {
mMirrorWindowControl.setWindowDelegate(this);
}
+ mTransaction = transaction;
setInitialStartBounds();
// Initialize listeners.
@@ -153,6 +147,20 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
mMirrorSurfaceViewLayoutChangeListener =
(v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom)
-> applyTapExcludeRegion();
+
+ mMirrorViewGeometryVsyncCallback =
+ l -> {
+ if (mMirrorView != null && mMirrorSurface != null) {
+ calculateSourceBounds(mMagnificationFrame, mScale);
+ // The final destination for the magnification surface should be at 0,0
+ // since the ViewRootImpl's position will change
+ mTmpRect.set(0, 0, mMagnificationFrame.width(),
+ mMagnificationFrame.height());
+ mTransaction.setGeometry(mMirrorSurface, mSourceBounds, mTmpRect,
+ Surface.ROTATION_0).apply();
+ mWindowMagnifierCallback.onSourceBoundsChanged(mDisplayId, mSourceBounds);
+ }
+ };
}
private void updateDimensions() {
@@ -350,13 +358,9 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
* Modifies the placement of the mirrored content when the position of mMirrorView is updated.
*/
private void modifyWindowMagnification(SurfaceControl.Transaction t) {
- // The final destination for the magnification surface should be at 0,0 since the
- // ViewRootImpl's position will change
- mTmpRect.set(0, 0, mMagnificationFrame.width(), mMagnificationFrame.height());
-
+ mSfVsyncFrameProvider.postFrameCallback(mMirrorViewGeometryVsyncCallback);
updateMirrorViewLayout();
- mSfVsyncFrameProvider.postFrameCallback(mMirrorViewGeometryVsyncCallback);
}
/**
@@ -420,14 +424,14 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
* Calculates the desired source bounds. This will be the area under from the center of the
* displayFrame, factoring in scale.
*/
- private Rect getSourceBounds(Rect displayFrame, float scale) {
+ private void calculateSourceBounds(Rect displayFrame, float scale) {
int halfWidth = displayFrame.width() / 2;
int halfHeight = displayFrame.height() / 2;
int left = displayFrame.left + (halfWidth - (int) (halfWidth / scale));
int right = displayFrame.right - (halfWidth - (int) (halfWidth / scale));
int top = displayFrame.top + (halfHeight - (int) (halfHeight / scale));
int bottom = displayFrame.bottom - (halfHeight - (int) (halfHeight / scale));
- return new Rect(left, top, right, bottom);
+ mSourceBounds.set(left, top, right, bottom);
}
private void setMagnificationFrameBoundary() {
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnifierCallback.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnifierCallback.java
index 2adb3ebb7bce..e405a89766e2 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnifierCallback.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnifierCallback.java
@@ -29,4 +29,12 @@ interface WindowMagnifierCallback {
* @param bounds The bounds of window magnifier on the screen.
*/
void onWindowMagnifierBoundsChanged(int displayId, Rect bounds);
+
+ /**
+ * Called when the magnified bounds is changed.
+ *
+ * @param displayId The logical display id.
+ * @param sourceBounds The magnified bounds in screen coordinates.
+ */
+ void onSourceBoundsChanged(int displayId, Rect sourceBounds);
}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
index 434bf49ac878..bb572191fe3c 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
@@ -25,6 +25,8 @@ import static android.service.notification.NotificationListenerService.REASON_CA
import static android.service.notification.NotificationListenerService.REASON_CANCEL_ALL;
import static android.service.notification.NotificationListenerService.REASON_CLICK;
import static android.service.notification.NotificationListenerService.REASON_GROUP_SUMMARY_CANCELED;
+import static android.service.notification.NotificationStats.DISMISSAL_BUBBLE;
+import static android.service.notification.NotificationStats.DISMISS_SENTIMENT_NEUTRAL;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.INVALID_DISPLAY;
import static android.view.View.INVISIBLE;
@@ -100,8 +102,11 @@ import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.collection.NotifCollection;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.coordinator.BubbleCoordinator;
+import com.android.systemui.statusbar.notification.collection.notifcollection.DismissedByUserStats;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
+import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.phone.NotificationShadeWindowController;
import com.android.systemui.statusbar.phone.ScrimController;
@@ -277,7 +282,10 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
* This can happen when an app cancels a bubbled notification or when the user dismisses a
* bubble.
*/
- void removeNotification(@NonNull NotificationEntry entry, int reason);
+ void removeNotification(
+ @NonNull NotificationEntry entry,
+ @NonNull DismissedByUserStats stats,
+ int reason);
/**
* Called when a bubbled notification has changed whether it should be
@@ -543,6 +551,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
}
});
+ // The new pipeline takes care of this as a NotifDismissInterceptor BubbleCoordinator
mNotificationEntryManager.addNotificationRemoveInterceptor(
new NotificationRemoveInterceptor() {
@Override
@@ -551,7 +560,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
NotificationEntry entry,
int dismissReason) {
final boolean isClearAll = dismissReason == REASON_CANCEL_ALL;
- final boolean isUserDimiss = dismissReason == REASON_CANCEL
+ final boolean isUserDismiss = dismissReason == REASON_CANCEL
|| dismissReason == REASON_CLICK;
final boolean isAppCancel = dismissReason == REASON_APP_CANCEL
|| dismissReason == REASON_APP_CANCEL_ALL;
@@ -562,7 +571,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
// previously been dismissed & entry.isRowDismissed would still be true
boolean userRemovedNotif =
(entry != null && entry.isRowDismissed() && !isAppCancel)
- || isClearAll || isUserDimiss || isSummaryCancel;
+ || isClearAll || isUserDismiss || isSummaryCancel;
if (userRemovedNotif) {
return handleDismissalInterception(entry);
@@ -591,8 +600,13 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
addNotifCallback(new NotifCallback() {
@Override
- public void removeNotification(NotificationEntry entry, int reason) {
- mNotificationEntryManager.performRemoveNotification(entry.getSbn(), reason);
+ public void removeNotification(
+ NotificationEntry entry,
+ DismissedByUserStats dismissedByUserStats,
+ int reason
+ ) {
+ mNotificationEntryManager.performRemoveNotification(entry.getSbn(),
+ dismissedByUserStats, reason);
}
@Override
@@ -612,7 +626,9 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
mNotificationEntryManager.getActiveNotificationUnfiltered(
mBubbleData.getSummaryKey(groupKey));
if (summary != null) {
- mNotificationEntryManager.performRemoveNotification(summary.getSbn(),
+ mNotificationEntryManager.performRemoveNotification(
+ summary.getSbn(),
+ getDismissedByUserStats(summary, false),
UNDEFINED_DISMISS_REASON);
}
}
@@ -634,7 +650,9 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
boolean isSummaryThisNotif = summary.getKey().equals(entry.getKey());
if (!isSummaryThisNotif && (summaryChildren == null
|| summaryChildren.isEmpty())) {
- mNotificationEntryManager.performRemoveNotification(summary.getSbn(),
+ mNotificationEntryManager.performRemoveNotification(
+ summary.getSbn(),
+ getDismissedByUserStats(summary, false),
UNDEFINED_DISMISS_REASON);
}
}
@@ -1331,7 +1349,10 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
// time to actually remove it
for (NotifCallback cb : mCallbacks) {
if (entry != null) {
- cb.removeNotification(entry, REASON_CANCEL);
+ cb.removeNotification(
+ entry,
+ getDismissedByUserStats(entry, true),
+ REASON_CANCEL);
}
}
} else {
@@ -1487,7 +1508,10 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
} else {
// non-bubbled children can be removed
for (NotifCallback cb : mCallbacks) {
- cb.removeNotification(child, REASON_GROUP_SUMMARY_CANCELED);
+ cb.removeNotification(
+ child,
+ getDismissedByUserStats(child, true),
+ REASON_GROUP_SUMMARY_CANCELED);
}
}
}
@@ -1502,6 +1526,25 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
}
/**
+ * Gets the DismissedByUserStats used by {@link NotificationEntryManager}.
+ * Will not be necessary when using the new notification pipeline's {@link NotifCollection}.
+ * Instead, this is taken care of by {@link BubbleCoordinator}.
+ */
+ private DismissedByUserStats getDismissedByUserStats(
+ NotificationEntry entry,
+ boolean isVisible) {
+ return new DismissedByUserStats(
+ DISMISSAL_BUBBLE,
+ DISMISS_SENTIMENT_NEUTRAL,
+ NotificationVisibility.obtain(
+ entry.getKey(),
+ entry.getRanking().getRank(),
+ mNotificationEntryManager.getActiveNotificationsCount(),
+ isVisible,
+ NotificationLogger.getNotificationLocation(entry)));
+ }
+
+ /**
* Updates the visibility of the bubbles based on current state.
* Does not un-bubble, just hides or un-hides.
* Updates stack description for TalkBack focus.
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIRootComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIRootComponent.java
index e5cc1384efa4..900c11f0830e 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIRootComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIRootComponent.java
@@ -19,12 +19,12 @@ package com.android.systemui.dagger;
import static com.android.systemui.Dependency.ALLOW_NOTIFICATION_LONG_PRESS_NAME;
import android.content.ContentProvider;
+import android.content.Context;
import com.android.systemui.BootCompleteCacheImpl;
import com.android.systemui.Dependency;
import com.android.systemui.InitController;
import com.android.systemui.SystemUIAppComponentFactory;
-import com.android.systemui.SystemUIFactory;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.fragments.FragmentService;
import com.android.systemui.keyguard.KeyguardSliceProvider;
@@ -37,6 +37,7 @@ import com.android.systemui.util.InjectionInflationController;
import javax.inject.Named;
import javax.inject.Singleton;
+import dagger.BindsInstance;
import dagger.Component;
/**
@@ -50,13 +51,23 @@ import dagger.Component;
OneHandedModule.class,
PipModule.class,
SystemServicesModule.class,
- SystemUIFactory.ContextHolder.class,
SystemUIBinder.class,
SystemUIModule.class,
SystemUIDefaultModule.class})
public interface SystemUIRootComponent {
/**
+ * Builder for a SystemUIRootComponent.
+ */
+ @Component.Builder
+ interface Builder {
+ @BindsInstance
+ Builder context(Context context);
+
+ SystemUIRootComponent build();
+ }
+
+ /**
* Provides a BootCompleteCache.
*/
@Singleton
@@ -78,7 +89,7 @@ public interface SystemUIRootComponent {
* Main dependency providing module.
*/
@Singleton
- Dependency.DependencyInjector createDependency();
+ Dependency createDependency();
/** */
@Singleton
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
index 075318b3f1f7..de5316885b94 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
@@ -135,6 +135,7 @@ class MediaCarouselController @Inject constructor(
}
override fun onOverlayChanged() {
+ recreatePlayers()
inflateSettingsButton()
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/SeekBarObserver.kt b/packages/SystemUI/src/com/android/systemui/media/SeekBarObserver.kt
index c2631c923e45..1ae54d60d3fa 100644
--- a/packages/SystemUI/src/com/android/systemui/media/SeekBarObserver.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/SeekBarObserver.kt
@@ -55,16 +55,16 @@ class SeekBarObserver(private val holder: PlayerViewHolder) : Observer<SeekBarVi
holder.seekBar.maxHeight = seekBarDefaultMaxHeight
}
- data.elapsedTime?.let {
- holder.seekBar.setProgress(it)
- holder.elapsedTimeView.setText(DateUtils.formatElapsedTime(
- it / DateUtils.SECOND_IN_MILLIS))
- }
-
data.duration?.let {
holder.seekBar.setMax(it)
holder.totalTimeView.setText(DateUtils.formatElapsedTime(
it / DateUtils.SECOND_IN_MILLIS))
}
+
+ data.elapsedTime?.let {
+ holder.seekBar.setProgress(it)
+ holder.elapsedTimeView.setText(DateUtils.formatElapsedTime(
+ it / DateUtils.SECOND_IN_MILLIS))
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedAnimationCallback.java b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedAnimationCallback.java
index c581ac677532..264ace749383 100644
--- a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedAnimationCallback.java
+++ b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedAnimationCallback.java
@@ -42,4 +42,10 @@ public interface OneHandedAnimationCallback {
default void onOneHandedAnimationCancel(
OneHandedAnimationController.OneHandedTransitionAnimator animator) {
}
+
+ /**
+ * Called when OneHanded animator is updating offset
+ */
+ default void onTutorialAnimationUpdate(int offset) {}
+
}
diff --git a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedAnimationController.java b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedAnimationController.java
index 1926c44abcba..2b07ac3f4d8a 100644
--- a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedAnimationController.java
+++ b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedAnimationController.java
@@ -28,7 +28,9 @@ import androidx.annotation.VisibleForTesting;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
import java.util.HashMap;
+import java.util.List;
import javax.inject.Inject;
@@ -121,7 +123,8 @@ public class OneHandedAnimationController {
private T mEndValue;
private T mCurrentValue;
- private OneHandedAnimationCallback mOneHandedAnimationCallback;
+ private final List<OneHandedAnimationCallback> mOneHandedAnimationCallbacks =
+ new ArrayList<>();
private OneHandedSurfaceTransactionHelper mSurfaceTransactionHelper;
private OneHandedSurfaceTransactionHelper.SurfaceControlTransactionFactory
mSurfaceControlTransactionFactory;
@@ -142,9 +145,11 @@ public class OneHandedAnimationController {
@Override
public void onAnimationStart(Animator animation) {
mCurrentValue = mStartValue;
- if (mOneHandedAnimationCallback != null) {
- mOneHandedAnimationCallback.onOneHandedAnimationStart(this);
- }
+ mOneHandedAnimationCallbacks.forEach(
+ (callback) -> {
+ callback.onOneHandedAnimationStart(this);
+ }
+ );
}
@Override
@@ -152,17 +157,21 @@ public class OneHandedAnimationController {
mCurrentValue = mEndValue;
final SurfaceControl.Transaction tx = newSurfaceControlTransaction();
onEndTransaction(mLeash, tx);
- if (mOneHandedAnimationCallback != null) {
- mOneHandedAnimationCallback.onOneHandedAnimationEnd(tx, this);
- }
+ mOneHandedAnimationCallbacks.forEach(
+ (callback) -> {
+ callback.onOneHandedAnimationEnd(tx, this);
+ }
+ );
}
@Override
public void onAnimationCancel(Animator animation) {
mCurrentValue = mEndValue;
- if (mOneHandedAnimationCallback != null) {
- mOneHandedAnimationCallback.onOneHandedAnimationCancel(this);
- }
+ mOneHandedAnimationCallbacks.forEach(
+ (callback) -> {
+ callback.onOneHandedAnimationCancel(this);
+ }
+ );
}
@Override
@@ -173,6 +182,11 @@ public class OneHandedAnimationController {
public void onAnimationUpdate(ValueAnimator animation) {
applySurfaceControlTransaction(mLeash, newSurfaceControlTransaction(),
animation.getAnimatedFraction());
+ mOneHandedAnimationCallbacks.forEach(
+ (callback) -> {
+ callback.onTutorialAnimationUpdate(((Rect) mCurrentValue).top);
+ }
+ );
}
void onStartTransaction(SurfaceControl leash, SurfaceControl.Transaction tx) {
@@ -192,9 +206,9 @@ public class OneHandedAnimationController {
mSurfaceTransactionHelper = helper;
}
- OneHandedTransitionAnimator<T> setOneHandedAnimationCallback(
+ OneHandedTransitionAnimator<T> setOneHandedAnimationCallbacks(
OneHandedAnimationCallback callback) {
- mOneHandedAnimationCallback = callback;
+ mOneHandedAnimationCallbacks.add(callback);
return this;
}
diff --git a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedDisplayAreaOrganizer.java b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedDisplayAreaOrganizer.java
index c0b9258f39fd..8550959aa2c4 100644
--- a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedDisplayAreaOrganizer.java
+++ b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedDisplayAreaOrganizer.java
@@ -82,6 +82,7 @@ public class OneHandedDisplayAreaOrganizer extends DisplayAreaOrganizer implemen
private OneHandedAnimationController mAnimationController;
private OneHandedSurfaceTransactionHelper.SurfaceControlTransactionFactory
mSurfaceControlTransactionFactory;
+ private OneHandedTutorialHandler mTutorialHandler;
private List<OneHandedTransitionCallback> mTransitionCallbacks = new ArrayList<>();
@VisibleForTesting
@@ -148,7 +149,8 @@ public class OneHandedDisplayAreaOrganizer extends DisplayAreaOrganizer implemen
@Inject
public OneHandedDisplayAreaOrganizer(Context context,
DisplayController displayController,
- OneHandedAnimationController animationController) {
+ OneHandedAnimationController animationController,
+ OneHandedTutorialHandler tutorialHandler) {
mUpdateHandler = new Handler(OneHandedThread.get().getLooper(), mUpdateCallback);
mAnimationController = animationController;
mDisplayController = displayController;
@@ -157,6 +159,7 @@ public class OneHandedDisplayAreaOrganizer extends DisplayAreaOrganizer implemen
mEnterExitAnimationDurationMs = context.getResources().getInteger(
com.android.systemui.R.integer.config_one_handed_translate_animation_duration);
mSurfaceControlTransactionFactory = SurfaceControl.Transaction::new;
+ mTutorialHandler = tutorialHandler;
}
@Override
@@ -272,7 +275,8 @@ public class OneHandedDisplayAreaOrganizer extends DisplayAreaOrganizer implemen
mAnimationController.getAnimator(leash, fromBounds, toBounds);
if (animator != null) {
animator.setTransitionDirection(direction)
- .setOneHandedAnimationCallback(mOneHandedAnimationCallback)
+ .setOneHandedAnimationCallbacks(mOneHandedAnimationCallback)
+ .setOneHandedAnimationCallbacks(mTutorialHandler.getAnimationCallback())
.setDuration(durationMs)
.start();
}
diff --git a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedGestureHandler.java b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedGestureHandler.java
index 71c5f8020330..ded386159dca 100644
--- a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedGestureHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedGestureHandler.java
@@ -53,8 +53,8 @@ import javax.inject.Singleton;
*/
@Singleton
public class OneHandedGestureHandler implements OneHandedTransitionCallback,
- NavigationModeController.ModeChangedListener,
- DisplayChangeController.OnDisplayChangingListener {
+ NavigationModeController.ModeChangedListener,
+ DisplayChangeController.OnDisplayChangingListener {
private static final String TAG = "OneHandedGestureHandler";
private static final boolean DEBUG_GESTURE = false;
@@ -87,8 +87,8 @@ public class OneHandedGestureHandler implements OneHandedTransitionCallback,
* Constructor of OneHandedGestureHandler, we only handle the gesture of
* {@link Display#DEFAULT_DISPLAY}
*
- * @param context {@link Context}
- * @param displayController {@link DisplayController}
+ * @param context {@link Context}
+ * @param displayController {@link DisplayController}
* @param navigationModeController {@link NavigationModeController}
*/
@Inject
@@ -103,7 +103,7 @@ public class OneHandedGestureHandler implements OneHandedTransitionCallback,
mDragDistThreshold = context.getResources().getDimensionPixelSize(
R.dimen.gestures_onehanded_drag_threshold);
final float slop = ViewConfiguration.get(context).getScaledTouchSlop();
- mSquaredSlop = slop * slop;
+ mSquaredSlop = slop * slop;
updateIsEnabled();
}
diff --git a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedManagerImpl.java b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedManagerImpl.java
index 70a81aaed249..51e587586852 100644
--- a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedManagerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedManagerImpl.java
@@ -57,6 +57,7 @@ public class OneHandedManagerImpl implements OneHandedManager, Dumpable {
private final OneHandedGestureHandler mGestureHandler;
private final OneHandedTimeoutHandler mTimeoutHandler;
private final OneHandedTouchHandler mTouchHandler;
+ private final OneHandedTutorialHandler mTutorialHandler;
private final SysUiState mSysUiFlagContainer;
private Context mContext;
@@ -107,6 +108,7 @@ public class OneHandedManagerImpl implements OneHandedManager, Dumpable {
DisplayController displayController,
OneHandedDisplayAreaOrganizer displayAreaOrganizer,
OneHandedTouchHandler touchHandler,
+ OneHandedTutorialHandler tutorialHandler,
OneHandedGestureHandler gestureHandler,
SysUiState sysUiState) {
mContext = context;
@@ -120,6 +122,7 @@ public class OneHandedManagerImpl implements OneHandedManager, Dumpable {
context.getContentResolver());
mTimeoutHandler = OneHandedTimeoutHandler.get();
mTouchHandler = touchHandler;
+ mTutorialHandler = tutorialHandler;
mGestureHandler = gestureHandler;
updateOneHandedEnabled();
setupGestures();
@@ -230,6 +233,7 @@ public class OneHandedManagerImpl implements OneHandedManager, Dumpable {
mDisplayAreaOrganizer.registerTransitionCallback(mTransitionCallback);
mDisplayAreaOrganizer.registerTransitionCallback(mTouchHandler);
mDisplayAreaOrganizer.registerTransitionCallback(mGestureHandler);
+ mDisplayAreaOrganizer.registerTransitionCallback(mTutorialHandler);
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedTouchHandler.java b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedTouchHandler.java
index 3d4338c1e220..d616a3a45b90 100644
--- a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedTouchHandler.java
@@ -58,6 +58,7 @@ public class OneHandedTouchHandler implements OneHandedTransitionCallback, Dumpa
OneHandedTouchEventCallback mTouchEventCallback;
private boolean mIsEnabled;
+ private boolean mIsOnStopTransitioning;
private boolean mIsInOutsideRegion;
@Inject
@@ -96,8 +97,9 @@ public class OneHandedTouchHandler implements OneHandedTransitionCallback, Dumpa
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL: {
mTimeoutHandler.resetTimer();
- if (mIsInOutsideRegion) {
+ if (mIsInOutsideRegion && !mIsOnStopTransitioning) {
mTouchEventCallback.onStop();
+ mIsOnStopTransitioning = true;
}
// Reset flag for next operation
mIsInOutsideRegion = false;
@@ -146,6 +148,7 @@ public class OneHandedTouchHandler implements OneHandedTransitionCallback, Dumpa
@Override
public void onStopFinished(Rect bounds) {
mLastUpdatedBounds.set(bounds);
+ mIsOnStopTransitioning = false;
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedTutorialHandler.java b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedTutorialHandler.java
new file mode 100644
index 000000000000..8a67da53e6a2
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedTutorialHandler.java
@@ -0,0 +1,161 @@
+/*
+ * 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.onehanded;
+
+import android.content.Context;
+import android.graphics.PixelFormat;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.os.Handler;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.widget.FrameLayout;
+
+import androidx.annotation.NonNull;
+
+import com.android.systemui.Dumpable;
+import com.android.systemui.R;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+/**
+ * Manages the user tutorial handling for One Handed operations, including animations synchronized
+ * with one-handed translation.
+ * Refer {@link OneHandedGestureHandler} and {@link OneHandedTouchHandler} to see start and stop
+ * one handed gesture
+ */
+@Singleton
+public class OneHandedTutorialHandler implements OneHandedTransitionCallback, Dumpable {
+ private static final String TAG = "OneHandedTutorialHandler";
+ private final Rect mLastUpdatedBounds = new Rect();
+ private final WindowManager mWindowManager;
+
+ private View mTutorialView;
+ private Point mDisplaySize = new Point();
+ private Handler mUpdateHandler;
+
+ /**
+ * Container of the tutorial panel showing at outside region when one handed starting
+ */
+ private ViewGroup mTargetViewContainer;
+ private int mTutorialAreaHeight;
+
+ private final OneHandedAnimationCallback mAnimationCallback = new OneHandedAnimationCallback() {
+ @Override
+ public void onTutorialAnimationUpdate(int offset) {
+ mUpdateHandler.post(() -> onAnimationUpdate(offset));
+ }
+ };
+
+ @Inject
+ public OneHandedTutorialHandler(Context context) {
+ context.getDisplay().getRealSize(mDisplaySize);
+ mUpdateHandler = new Handler();
+ mWindowManager = context.getSystemService(WindowManager.class);
+ mTargetViewContainer = new FrameLayout(context);
+ mTargetViewContainer.setClipChildren(false);
+ mTutorialAreaHeight = Math.round(mDisplaySize.y * context.getResources().getFraction(
+ R.fraction.config_one_handed_offset, 1, 1));
+ mTutorialView = LayoutInflater.from(context).inflate(R.xml.one_handed_tutorial, null);
+ mTargetViewContainer.addView(mTutorialView);
+ createOrUpdateTutorialTarget();
+ }
+
+ @Override
+ public void onStartFinished(Rect bounds) {
+ mUpdateHandler.post(() -> updateFinished(View.VISIBLE, 0f));
+ }
+
+ @Override
+ public void onStopFinished(Rect bounds) {
+ mUpdateHandler.post(() -> updateFinished(
+ View.INVISIBLE, -mTargetViewContainer.getHeight()));
+ }
+
+ private void updateFinished(int visible, float finalPosition) {
+ mTargetViewContainer.setVisibility(visible);
+ mTargetViewContainer.setTranslationY(finalPosition);
+ }
+
+ /**
+ * Adds the tutorial target view to the WindowManager and update its layout, so it's ready
+ * to be animated in.
+ */
+ private void createOrUpdateTutorialTarget() {
+ mUpdateHandler.post(() -> {
+ if (!mTargetViewContainer.isAttachedToWindow()) {
+ mTargetViewContainer.setVisibility(View.INVISIBLE);
+
+ try {
+ mWindowManager.addView(mTargetViewContainer, getTutorialTargetLayoutParams());
+ } catch (IllegalStateException e) {
+ // This shouldn't happen, but if the target is already added, just update its
+ // layout params.
+ mWindowManager.updateViewLayout(
+ mTargetViewContainer, getTutorialTargetLayoutParams());
+ }
+ } else {
+ mWindowManager.updateViewLayout(mTargetViewContainer,
+ getTutorialTargetLayoutParams());
+ }
+ });
+ }
+
+ OneHandedAnimationCallback getAnimationCallback() {
+ return mAnimationCallback;
+ }
+
+ /**
+ * Returns layout params for the dismiss target, using the latest display metrics.
+ */
+ private WindowManager.LayoutParams getTutorialTargetLayoutParams() {
+ final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
+ mDisplaySize.x, mTutorialAreaHeight, 0, 0,
+ WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL,
+ WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
+ | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
+ | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
+ PixelFormat.TRANSLUCENT);
+ lp.gravity = Gravity.TOP | Gravity.LEFT;
+ lp.privateFlags |= WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS;
+ lp.setFitInsetsTypes(0 /* types */);
+ lp.setTitle("one-handed-tutorial-overlay");
+
+ return lp;
+ }
+
+ @Override
+ public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) {
+ final String innerPrefix = " ";
+ pw.println(TAG + "states: ");
+ pw.print(innerPrefix + "mLastUpdatedBounds=");
+ pw.println(mLastUpdatedBounds);
+ }
+
+ private void onAnimationUpdate(float value) {
+ mTargetViewContainer.setVisibility(View.VISIBLE);
+ mTargetViewContainer.setTransitionGroup(true);
+ mTargetViewContainer.setTranslationY(value - mTargetViewContainer.getHeight());
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedUI.java b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedUI.java
index 0f4e6be76721..9239435f1622 100644
--- a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedUI.java
+++ b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedUI.java
@@ -29,7 +29,9 @@ import android.os.IBinder;
import android.os.Looper;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.SystemProperties;
import android.provider.Settings;
+import android.util.Log;
import androidx.annotation.VisibleForTesting;
@@ -56,6 +58,7 @@ public class OneHandedUI extends SystemUI implements CommandQueue.Callbacks, Dum
private static final String TAG = "OneHandedUI";
private static final String ONE_HANDED_MODE_GESTURAL_OVERLAY =
"com.android.internal.systemui.onehanded.gestural";
+ private static final String SUPPORT_ONE_HANDED_MODE = "ro.support_one_handed_mode";
private final OneHandedManagerImpl mOneHandedManager;
private final CommandQueue mCommandQueue;
@@ -136,10 +139,18 @@ public class OneHandedUI extends SystemUI implements CommandQueue.Callbacks, Dum
ScreenLifecycle screenLifecycle) {
super(context);
+ if (!SystemProperties.getBoolean(SUPPORT_ONE_HANDED_MODE, false)) {
+ Log.i(TAG, "Device config SUPPORT_ONE_HANDED_MODE off");
+ mCommandQueue = null;
+ mOneHandedManager = null;
+ mOverlayManager = null;
+ mSettingUtil = null;
+ mTimeoutHandler = null;
+ mScreenLifecycle = null;
+ return;
+ }
+
mCommandQueue = commandQueue;
- /* TODO(b/154290458) define a boolean system properties "support_one_handed_mode"
- boolean supportOneHanded = SystemProperties.getBoolean("support_one_handed_mode");
- if (!supportOneHanded) return; */
mOneHandedManager = oneHandedManager;
mSettingUtil = settingsUtil;
mTimeoutHandler = OneHandedTimeoutHandler.get();
@@ -150,9 +161,9 @@ public class OneHandedUI extends SystemUI implements CommandQueue.Callbacks, Dum
@Override
public void start() {
- /* TODO(b/154290458) define a boolean system properties "support_one_handed_mode"
- boolean supportOneHanded = SystemProperties.getBoolean("support_one_handed_mode");
- if (!supportOneHanded) return; */
+ if (!SystemProperties.getBoolean(SUPPORT_ONE_HANDED_MODE, false)) {
+ return;
+ }
mCommandQueue.addCallback(this);
setupKeyguardUpdateMonitor();
setupScreenObserver();
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Recents.java b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
index 5f37cc4520a3..df61fd19ad45 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Recents.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
@@ -65,10 +65,6 @@ public class Recents extends SystemUI implements CommandQueue.Callbacks {
}
}
- public void growRecents() {
- mImpl.growRecents();
- }
-
@Override
public void showRecentApps(boolean triggeredFromAltTab) {
// Ensure the device has been provisioned before allowing the user to interact with
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
index eb7231211ea8..4007abb39903 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
@@ -16,559 +16,127 @@
package com.android.systemui.stackdivider;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
-import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
-import static android.view.Display.DEFAULT_DISPLAY;
-
import static com.android.systemui.shared.system.WindowManagerWrapper.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
import android.app.ActivityManager;
-import android.app.ActivityTaskManager;
import android.content.Context;
-import android.content.res.Configuration;
-import android.graphics.Rect;
-import android.os.Handler;
-import android.provider.Settings;
-import android.util.Slog;
-import android.view.LayoutInflater;
-import android.view.View;
import android.window.WindowContainerToken;
-import android.window.WindowContainerTransaction;
-import android.window.WindowOrganizer;
-import com.android.internal.policy.DividerSnapAlgorithm;
-import com.android.systemui.R;
import com.android.systemui.SystemUI;
-import com.android.systemui.recents.Recents;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.TaskStackChangeListener;
import com.android.systemui.statusbar.policy.KeyguardStateController;
-import com.android.wm.shell.common.DisplayChangeController;
-import com.android.wm.shell.common.DisplayController;
-import com.android.wm.shell.common.DisplayImeController;
-import com.android.wm.shell.common.DisplayLayout;
-import com.android.wm.shell.common.SystemWindows;
-import com.android.wm.shell.common.TransactionPool;
import java.io.FileDescriptor;
import java.io.PrintWriter;
-import java.lang.ref.WeakReference;
-import java.util.ArrayList;
-import java.util.Optional;
import java.util.function.Consumer;
import javax.inject.Singleton;
-import dagger.Lazy;
-
/**
* Controls the docked stack divider.
*/
@Singleton
-public class Divider extends SystemUI implements DividerView.DividerCallbacks,
- DisplayController.OnDisplaysChangedListener {
- private static final String TAG = "Divider";
-
- static final boolean DEBUG = false;
-
- static final int DEFAULT_APP_TRANSITION_DURATION = 336;
-
- private final Optional<Lazy<Recents>> mRecentsOptionalLazy;
-
- private DividerWindowManager mWindowManager;
- private DividerView mView;
- private final DividerState mDividerState = new DividerState();
- private boolean mVisible = false;
- private boolean mMinimized = false;
- private boolean mAdjustedForIme = false;
- private boolean mHomeStackResizable = false;
- private ForcedResizableInfoActivityController mForcedResizableController;
- private SystemWindows mSystemWindows;
- private DisplayController mDisplayController;
- private DisplayImeController mImeController;
- final TransactionPool mTransactionPool;
-
- // Keeps track of real-time split geometry including snap positions and ime adjustments
- private SplitDisplayLayout mSplitLayout;
-
- // Transient: this contains the layout calculated for a new rotation requested by WM. This is
- // kept around so that we can wait for a matching configuration change and then use the exact
- // layout that we sent back to WM.
- private SplitDisplayLayout mRotateSplitLayout;
+public class Divider extends SystemUI {
+ private final KeyguardStateController mKeyguardStateController;
+ private final DividerController mDividerController;
- private Handler mHandler;
- private KeyguardStateController mKeyguardStateController;
-
- private WindowManagerProxy mWindowManagerProxy;
-
- private final ArrayList<WeakReference<Consumer<Boolean>>> mDockedStackExistsListeners =
- new ArrayList<>();
-
- private SplitScreenTaskOrganizer mSplits = new SplitScreenTaskOrganizer(this);
-
- private DisplayChangeController.OnDisplayChangingListener mRotationController =
- (display, fromRotation, toRotation, wct) -> {
- if (!mSplits.isSplitScreenSupported() || mWindowManagerProxy == null) {
- return;
- }
- WindowContainerTransaction t = new WindowContainerTransaction();
- DisplayLayout displayLayout =
- new DisplayLayout(mDisplayController.getDisplayLayout(display));
- SplitDisplayLayout sdl = new SplitDisplayLayout(mContext, displayLayout, mSplits);
- sdl.rotateTo(toRotation);
- mRotateSplitLayout = sdl;
- final int position = isDividerVisible()
- ? (mMinimized ? mView.mSnapTargetBeforeMinimized.position
- : mView.getCurrentPosition())
- // snap resets to middle target when not in split-mode
- : sdl.getSnapAlgorithm().getMiddleTarget().position;
- DividerSnapAlgorithm snap = sdl.getSnapAlgorithm();
- final DividerSnapAlgorithm.SnapTarget target =
- snap.calculateNonDismissingSnapTarget(position);
- sdl.resizeSplits(target.position, t);
-
- if (isSplitActive() && mHomeStackResizable) {
- WindowManagerProxy.applyHomeTasksMinimized(sdl, mSplits.mSecondary.token, t);
- }
- if (mWindowManagerProxy.queueSyncTransactionIfWaiting(t)) {
- // Because sync transactions are serialized, its possible for an "older"
- // bounds-change to get applied after a screen rotation. In that case, we
- // want to actually defer on that rather than apply immediately. Of course,
- // this means that the bounds may not change until after the rotation so
- // the user might see some artifacts. This should be rare.
- Slog.w(TAG, "Screen rotated while other operations were pending, this may"
- + " result in some graphical artifacts.");
- } else {
- wct.merge(t, true /* transfer */);
- }
- };
-
- private final DividerImeController mImePositionProcessor;
-
- private TaskStackChangeListener mActivityRestartListener = new TaskStackChangeListener() {
- @Override
- public void onActivityRestartAttempt(ActivityManager.RunningTaskInfo task,
- boolean homeTaskVisible, boolean clearedTask, boolean wasVisible) {
- if (!wasVisible || task.configuration.windowConfiguration.getWindowingMode()
- != WINDOWING_MODE_SPLIT_SCREEN_PRIMARY || !mSplits.isSplitScreenSupported()) {
- return;
- }
-
- if (isMinimized()) {
- onUndockingTask();
- }
- }
- };
-
- public Divider(Context context, Optional<Lazy<Recents>> recentsOptionalLazy,
- DisplayController displayController, SystemWindows systemWindows,
- DisplayImeController imeController, Handler handler,
- KeyguardStateController keyguardStateController, TransactionPool transactionPool) {
+ Divider(Context context, DividerController dividerController,
+ KeyguardStateController keyguardStateController) {
super(context);
- mDisplayController = displayController;
- mSystemWindows = systemWindows;
- mImeController = imeController;
- mHandler = handler;
+ mDividerController = dividerController;
mKeyguardStateController = keyguardStateController;
- mRecentsOptionalLazy = recentsOptionalLazy;
- mForcedResizableController = new ForcedResizableInfoActivityController(context, this);
- mTransactionPool = transactionPool;
- mWindowManagerProxy = new WindowManagerProxy(mTransactionPool, mHandler);
- mImePositionProcessor = new DividerImeController(mSplits, mTransactionPool, mHandler);
}
@Override
public void start() {
- mWindowManager = new DividerWindowManager(mSystemWindows);
- mDisplayController.addDisplayWindowListener(this);
+ mDividerController.start();
// Hide the divider when keyguard is showing. Even though keyguard/statusbar is above
// everything, it is actually transparent except for notifications, so we still need to
// hide any surfaces that are below it.
// TODO(b/148906453): Figure out keyguard dismiss animation for divider view.
mKeyguardStateController.addCallback(new KeyguardStateController.Callback() {
@Override
- public void onUnlockedChanged() {
-
- }
-
- @Override
public void onKeyguardShowingChanged() {
- if (!isSplitActive() || mView == null) {
- return;
- }
- mView.setHidden(mKeyguardStateController.isShowing());
- if (!mKeyguardStateController.isShowing()) {
- mImePositionProcessor.updateAdjustForIme();
- }
- }
-
- @Override
- public void onKeyguardFadingAwayChanged() {
-
+ mDividerController.onKeyguardShowingChanged(mKeyguardStateController.isShowing());
}
});
// Don't initialize the divider or anything until we get the default display.
- }
- @Override
- public void onDisplayAdded(int displayId) {
- if (displayId != DEFAULT_DISPLAY) {
- return;
- }
- mSplitLayout = new SplitDisplayLayout(mDisplayController.getDisplayContext(displayId),
- mDisplayController.getDisplayLayout(displayId), mSplits);
- mImeController.addPositionProcessor(mImePositionProcessor);
- mDisplayController.addDisplayChangingController(mRotationController);
- if (!ActivityTaskManager.supportsSplitScreenMultiWindow(mContext)) {
- removeDivider();
- return;
- }
- try {
- mSplits.init();
- // Set starting tile bounds based on middle target
- final WindowContainerTransaction tct = new WindowContainerTransaction();
- int midPos = mSplitLayout.getSnapAlgorithm().getMiddleTarget().position;
- mSplitLayout.resizeSplits(midPos, tct);
- WindowOrganizer.applyTransaction(tct);
- } catch (Exception e) {
- Slog.e(TAG, "Failed to register docked stack listener", e);
- removeDivider();
- return;
- }
- ActivityManagerWrapper.getInstance().registerTaskStackListener(mActivityRestartListener);
+ ActivityManagerWrapper.getInstance().registerTaskStackListener(
+ new TaskStackChangeListener() {
+ @Override
+ public void onActivityRestartAttempt(ActivityManager.RunningTaskInfo task,
+ boolean homeTaskVisible, boolean clearedTask, boolean wasVisible) {
+ if (!wasVisible || task.configuration.windowConfiguration.getWindowingMode()
+ != WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
+ || !mDividerController.isSplitScreenSupported()) {
+ return;
+ }
+
+ if (mDividerController.isMinimized()) {
+ onUndockingTask();
+ }
+ }
+ }
+ );
}
@Override
- public void onDisplayConfigurationChanged(int displayId, Configuration newConfig) {
- if (displayId != DEFAULT_DISPLAY || !mSplits.isSplitScreenSupported()) {
- return;
- }
- mSplitLayout = new SplitDisplayLayout(mDisplayController.getDisplayContext(displayId),
- mDisplayController.getDisplayLayout(displayId), mSplits);
- if (mRotateSplitLayout == null) {
- int midPos = mSplitLayout.getSnapAlgorithm().getMiddleTarget().position;
- final WindowContainerTransaction tct = new WindowContainerTransaction();
- mSplitLayout.resizeSplits(midPos, tct);
- WindowOrganizer.applyTransaction(tct);
- } else if (mSplitLayout.mDisplayLayout.rotation()
- == mRotateSplitLayout.mDisplayLayout.rotation()) {
- mSplitLayout.mPrimary = new Rect(mRotateSplitLayout.mPrimary);
- mSplitLayout.mSecondary = new Rect(mRotateSplitLayout.mSecondary);
- mRotateSplitLayout = null;
- }
- if (isSplitActive()) {
- update(newConfig);
- }
- }
-
- Handler getHandler() {
- return mHandler;
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ mDividerController.dump(pw);
}
- public DividerView getView() {
- return mView;
+ /** Switch to minimized state if appropriate. */
+ public void setMinimized(final boolean minimized) {
+ mDividerController.setMinimized(minimized);
}
public boolean isMinimized() {
- return mMinimized;
+ return mDividerController.isMinimized();
}
public boolean isHomeStackResizable() {
- return mHomeStackResizable;
- }
-
- /** {@code true} if this is visible */
- public boolean isDividerVisible() {
- return mView != null && mView.getVisibility() == View.VISIBLE;
- }
-
- /**
- * This indicates that at-least one of the splits has content. This differs from
- * isDividerVisible because the divider is only visible once *everything* is in split mode
- * while this only cares if some things are (eg. while entering/exiting as well).
- */
- private boolean isSplitActive() {
- return mSplits.mPrimary != null && mSplits.mSecondary != null
- && (mSplits.mPrimary.topActivityType != ACTIVITY_TYPE_UNDEFINED
- || mSplits.mSecondary.topActivityType != ACTIVITY_TYPE_UNDEFINED);
- }
-
- private void addDivider(Configuration configuration) {
- Context dctx = mDisplayController.getDisplayContext(mContext.getDisplayId());
- mView = (DividerView)
- LayoutInflater.from(dctx).inflate(R.layout.docked_stack_divider, null);
- DisplayLayout displayLayout = mDisplayController.getDisplayLayout(mContext.getDisplayId());
- mView.injectDependencies(mWindowManager, mDividerState, this, mSplits, mSplitLayout,
- mImePositionProcessor, mWindowManagerProxy);
- mView.setVisibility(mVisible ? View.VISIBLE : View.INVISIBLE);
- mView.setMinimizedDockStack(mMinimized, mHomeStackResizable, null /* transaction */);
- final int size = dctx.getResources().getDimensionPixelSize(
- com.android.internal.R.dimen.docked_stack_divider_thickness);
- final boolean landscape = configuration.orientation == ORIENTATION_LANDSCAPE;
- final int width = landscape ? size : displayLayout.width();
- final int height = landscape ? displayLayout.height() : size;
- mWindowManager.add(mView, width, height, mContext.getDisplayId());
- }
-
- private void removeDivider() {
- if (mView != null) {
- mView.onDividerRemoved();
- }
- mWindowManager.remove();
- }
-
- private void update(Configuration configuration) {
- final boolean isDividerHidden = mView != null && mKeyguardStateController.isShowing();
-
- removeDivider();
- addDivider(configuration);
-
- if (mMinimized) {
- mView.setMinimizedDockStack(true, mHomeStackResizable, null /* transaction */);
- updateTouchable();
- }
- mView.setHidden(isDividerHidden);
- }
-
- void onTaskVanished() {
- mHandler.post(this::removeDivider);
- }
-
- private void updateVisibility(final boolean visible) {
- if (DEBUG) Slog.d(TAG, "Updating visibility " + mVisible + "->" + visible);
- if (mVisible != visible) {
- mVisible = visible;
- mView.setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
-
- if (visible) {
- mView.enterSplitMode(mHomeStackResizable);
- // Update state because animations won't finish.
- mWindowManagerProxy.runInSync(
- t -> mView.setMinimizedDockStack(mMinimized, mHomeStackResizable, t));
-
- } else {
- mView.exitSplitMode();
- mWindowManagerProxy.runInSync(
- t -> mView.setMinimizedDockStack(false, mHomeStackResizable, t));
- }
- // Notify existence listeners
- synchronized (mDockedStackExistsListeners) {
- mDockedStackExistsListeners.removeIf(wf -> {
- Consumer<Boolean> l = wf.get();
- if (l != null) l.accept(visible);
- return l == null;
- });
- }
- }
+ return mDividerController.isHomeStackResizable();
}
- /** Switch to minimized state if appropriate */
- public void setMinimized(final boolean minimized) {
- if (DEBUG) Slog.d(TAG, "posting ext setMinimized " + minimized + " vis:" + mVisible);
- mHandler.post(() -> {
- if (DEBUG) Slog.d(TAG, "run posted ext setMinimized " + minimized + " vis:" + mVisible);
- if (!mVisible) {
- return;
- }
- setHomeMinimized(minimized, mHomeStackResizable);
- });
- }
-
- private void setHomeMinimized(final boolean minimized, boolean homeStackResizable) {
- if (DEBUG) {
- Slog.d(TAG, "setHomeMinimized min:" + mMinimized + "->" + minimized + " hrsz:"
- + mHomeStackResizable + "->" + homeStackResizable
- + " split:" + isDividerVisible());
- }
- WindowContainerTransaction wct = new WindowContainerTransaction();
- final boolean minimizedChanged = mMinimized != minimized;
- // Update minimized state
- if (minimizedChanged) {
- mMinimized = minimized;
- }
- // Always set this because we could be entering split when mMinimized is already true
- wct.setFocusable(mSplits.mPrimary.token, !mMinimized);
- boolean onlyFocusable = true;
-
- // Update home-stack resizability
- final boolean homeResizableChanged = mHomeStackResizable != homeStackResizable;
- if (homeResizableChanged) {
- mHomeStackResizable = homeStackResizable;
- if (isDividerVisible()) {
- WindowManagerProxy.applyHomeTasksMinimized(
- mSplitLayout, mSplits.mSecondary.token, wct);
- onlyFocusable = false;
- }
- }
-
- // Sync state to DividerView if it exists.
- if (mView != null) {
- final int displayId = mView.getDisplay() != null
- ? mView.getDisplay().getDisplayId() : DEFAULT_DISPLAY;
- // pause ime here (before updateMinimizedDockedStack)
- if (mMinimized) {
- mImePositionProcessor.pause(displayId);
- }
- if (minimizedChanged || homeResizableChanged) {
- // This conflicts with IME adjustment, so only call it when things change.
- mView.setMinimizedDockStack(minimized, getAnimDuration(), homeStackResizable);
- }
- if (!mMinimized) {
- // afterwards so it can end any animations started in view
- mImePositionProcessor.resume(displayId);
- }
- }
- updateTouchable();
- if (onlyFocusable) {
- // If we are only setting focusability, a sync transaction isn't necessary (in fact it
- // can interrupt other animations), so see if it can be submitted on pending instead.
- if (!mSplits.mDivider.getWmProxy().queueSyncTransactionIfWaiting(wct)) {
- WindowOrganizer.applyTransaction(wct);
- }
- } else {
- mWindowManagerProxy.applySyncTransaction(wct);
- }
- }
-
- void setAdjustedForIme(boolean adjustedForIme) {
- if (mAdjustedForIme == adjustedForIme) {
- return;
- }
- mAdjustedForIme = adjustedForIme;
- updateTouchable();
- }
-
- private void updateTouchable() {
- mWindowManager.setTouchable(!mAdjustedForIme);
+ /** Callback for undocking task. */
+ public void onUndockingTask() {
+ mDividerController.onUndockingTask();
}
- /**
- * Workaround for b/62528361, at the time recents has drawn, it may happen before a
- * configuration change to the Divider, and internally, the event will be posted to the
- * subscriber, or DividerView, which has been removed and prevented from resizing. Instead,
- * register the event handler here and proxy the event to the current DividerView.
- */
public void onRecentsDrawn() {
- if (mView != null) {
- mView.onRecentsDrawn();
- }
- }
-
- public void onUndockingTask() {
- if (mView != null) {
- mView.onUndockingTask();
- }
+ mDividerController.onRecentsDrawn();
}
public void onDockedFirstAnimationFrame() {
- if (mView != null) {
- mView.onDockedFirstAnimationFrame();
- }
+ mDividerController.onDockedFirstAnimationFrame();
}
public void onDockedTopTask() {
- if (mView != null) {
- mView.onDockedTopTask();
- }
+ mDividerController.onDockedTopTask();
}
public void onAppTransitionFinished() {
- if (mView == null) {
- return;
- }
- mForcedResizableController.onAppTransitionFinished();
+ mDividerController.onAppTransitionFinished();
}
- @Override
- public void onDraggingStart() {
- mForcedResizableController.onDraggingStart();
- }
-
- @Override
- public void onDraggingEnd() {
- mForcedResizableController.onDraggingEnd();
- }
-
- @Override
- public void growRecents() {
- mRecentsOptionalLazy.ifPresent(recentsLazy -> recentsLazy.get().growRecents());
- }
-
- @Override
- public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- pw.print(" mVisible="); pw.println(mVisible);
- pw.print(" mMinimized="); pw.println(mMinimized);
- pw.print(" mAdjustedForIme="); pw.println(mAdjustedForIme);
+ public DividerView getView() {
+ return mDividerController.getDividerView();
}
- long getAnimDuration() {
- float transitionScale = Settings.Global.getFloat(mContext.getContentResolver(),
- Settings.Global.TRANSITION_ANIMATION_SCALE,
- mContext.getResources().getFloat(
- com.android.internal.R.dimen
- .config_appTransitionAnimationDurationScaleDefault));
- final long transitionDuration = DEFAULT_APP_TRANSITION_DURATION;
- return (long) (transitionDuration * transitionScale);
+ /** @return the container token for the secondary split root task. */
+ public WindowContainerToken getSecondaryRoot() {
+ return mDividerController.getSecondaryRoot();
}
/** Register a listener that gets called whenever the existence of the divider changes */
public void registerInSplitScreenListener(Consumer<Boolean> listener) {
- listener.accept(isDividerVisible());
- synchronized (mDockedStackExistsListeners) {
- mDockedStackExistsListeners.add(new WeakReference<>(listener));
- }
- }
-
- void startEnterSplit() {
- update(mDisplayController.getDisplayContext(
- mContext.getDisplayId()).getResources().getConfiguration());
- // Set resizable directly here because applyEnterSplit already resizes home stack.
- mHomeStackResizable = mWindowManagerProxy.applyEnterSplit(mSplits, mSplitLayout);
- }
-
- void startDismissSplit() {
- mWindowManagerProxy.applyDismissSplit(mSplits, mSplitLayout, true /* dismissOrMaximize */);
- updateVisibility(false /* visible */);
- mMinimized = false;
- removeDivider();
- mImePositionProcessor.reset();
+ mDividerController.registerInSplitScreenListener(listener);
}
- void ensureMinimizedSplit() {
- setHomeMinimized(true /* minimized */, mHomeStackResizable);
- if (mView != null && !isDividerVisible()) {
- // Wasn't in split-mode yet, so enter now.
- if (DEBUG) {
- Slog.d(TAG, " entering split mode with minimized=true");
- }
- updateVisibility(true /* visible */);
- }
- }
-
- void ensureNormalSplit() {
- setHomeMinimized(false /* minimized */, mHomeStackResizable);
- if (mView != null && !isDividerVisible()) {
- // Wasn't in split-mode, so enter now.
- if (DEBUG) {
- Slog.d(TAG, " enter split mode unminimized ");
- }
- updateVisibility(true /* visible */);
- }
- }
-
- SplitDisplayLayout getSplitLayout() {
- return mSplitLayout;
- }
-
- WindowManagerProxy getWmProxy() {
- return mWindowManagerProxy;
- }
-
- /** @return the container token for the secondary split root task. */
- public WindowContainerToken getSecondaryRoot() {
- if (mSplits == null || mSplits.mSecondary == null) {
- return null;
- }
- return mSplits.mSecondary.token;
+ /** {@code true} if this is visible */
+ public boolean isDividerVisible() {
+ return mDividerController.isDividerVisible();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerController.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerController.java
new file mode 100644
index 000000000000..81649f608581
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerController.java
@@ -0,0 +1,516 @@
+/*
+ * 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.stackdivider;
+
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
+import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
+import static android.view.Display.DEFAULT_DISPLAY;
+
+import android.app.ActivityTaskManager;
+import android.content.Context;
+import android.content.res.Configuration;
+import android.graphics.Rect;
+import android.os.Handler;
+import android.provider.Settings;
+import android.util.Slog;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.window.WindowContainerToken;
+import android.window.WindowContainerTransaction;
+import android.window.WindowOrganizer;
+
+import com.android.internal.policy.DividerSnapAlgorithm;
+import com.android.systemui.R;
+import com.android.wm.shell.common.DisplayChangeController;
+import com.android.wm.shell.common.DisplayController;
+import com.android.wm.shell.common.DisplayImeController;
+import com.android.wm.shell.common.DisplayLayout;
+import com.android.wm.shell.common.SystemWindows;
+import com.android.wm.shell.common.TransactionPool;
+
+import java.io.PrintWriter;
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.function.Consumer;
+
+/**
+ * Controls the docked stack divider.
+ */
+public class DividerController implements DividerView.DividerCallbacks,
+ DisplayController.OnDisplaysChangedListener {
+ static final boolean DEBUG = false;
+ private static final String TAG = "Divider";
+
+ static final int DEFAULT_APP_TRANSITION_DURATION = 336;
+
+ private DividerWindowManager mWindowManager;
+ private DividerView mView;
+ private final DividerState mDividerState = new DividerState();
+ private boolean mVisible = false;
+ private boolean mMinimized = false;
+ private boolean mAdjustedForIme = false;
+ private boolean mHomeStackResizable = false;
+ private ForcedResizableInfoActivityController mForcedResizableController;
+ private SystemWindows mSystemWindows;
+ private DisplayController mDisplayController;
+ private DisplayImeController mImeController;
+ final TransactionPool mTransactionPool;
+
+ // Keeps track of real-time split geometry including snap positions and ime adjustments
+ private SplitDisplayLayout mSplitLayout;
+
+ // Transient: this contains the layout calculated for a new rotation requested by WM. This is
+ // kept around so that we can wait for a matching configuration change and then use the exact
+ // layout that we sent back to WM.
+ private SplitDisplayLayout mRotateSplitLayout;
+
+ private final Handler mHandler;
+ private final WindowManagerProxy mWindowManagerProxy;
+
+ private final ArrayList<WeakReference<Consumer<Boolean>>> mDockedStackExistsListeners =
+ new ArrayList<>();
+
+ private final SplitScreenTaskOrganizer mSplits;
+ private final DisplayChangeController.OnDisplayChangingListener mRotationController;
+ private final DividerImeController mImePositionProcessor;
+ private final Context mContext;
+ private boolean mIsKeyguardShowing;
+
+ public DividerController(Context context,
+ DisplayController displayController, SystemWindows systemWindows,
+ DisplayImeController imeController, Handler handler, TransactionPool transactionPool) {
+ mContext = context;
+ mDisplayController = displayController;
+ mSystemWindows = systemWindows;
+ mImeController = imeController;
+ mHandler = handler;
+ mForcedResizableController = new ForcedResizableInfoActivityController(context, this);
+ mTransactionPool = transactionPool;
+ mWindowManagerProxy = new WindowManagerProxy(mTransactionPool, mHandler);
+ mSplits = new SplitScreenTaskOrganizer(this);
+ mImePositionProcessor = new DividerImeController(mSplits, mTransactionPool, mHandler);
+ mRotationController =
+ (display, fromRotation, toRotation, wct) -> {
+ if (!mSplits.isSplitScreenSupported() || mWindowManagerProxy == null) {
+ return;
+ }
+ WindowContainerTransaction t = new WindowContainerTransaction();
+ DisplayLayout displayLayout =
+ new DisplayLayout(mDisplayController.getDisplayLayout(display));
+ SplitDisplayLayout sdl =
+ new SplitDisplayLayout(mContext, displayLayout, mSplits);
+ sdl.rotateTo(toRotation);
+ mRotateSplitLayout = sdl;
+ final int position = isDividerVisible()
+ ? (mMinimized ? mView.mSnapTargetBeforeMinimized.position
+ : mView.getCurrentPosition())
+ // snap resets to middle target when not in split-mode
+ : sdl.getSnapAlgorithm().getMiddleTarget().position;
+ DividerSnapAlgorithm snap = sdl.getSnapAlgorithm();
+ final DividerSnapAlgorithm.SnapTarget target =
+ snap.calculateNonDismissingSnapTarget(position);
+ sdl.resizeSplits(target.position, t);
+
+ if (isSplitActive() && mHomeStackResizable) {
+ WindowManagerProxy
+ .applyHomeTasksMinimized(sdl, mSplits.mSecondary.token, t);
+ }
+ if (mWindowManagerProxy.queueSyncTransactionIfWaiting(t)) {
+ // Because sync transactions are serialized, its possible for an "older"
+ // bounds-change to get applied after a screen rotation. In that case, we
+ // want to actually defer on that rather than apply immediately. Of course,
+ // this means that the bounds may not change until after the rotation so
+ // the user might see some artifacts. This should be rare.
+ Slog.w(TAG, "Screen rotated while other operations were pending, this may"
+ + " result in some graphical artifacts.");
+ } else {
+ wct.merge(t, true /* transfer */);
+ }
+ };
+ }
+
+ /** Inits the divider service. */
+ public void start() {
+ mWindowManager = new DividerWindowManager(mSystemWindows);
+ mDisplayController.addDisplayWindowListener(this);
+ // Don't initialize the divider or anything until we get the default display.
+ }
+
+ /** Returns {@code true} if split screen is supported on the device. */
+ public boolean isSplitScreenSupported() {
+ return mSplits.isSplitScreenSupported();
+ }
+
+ /** Called when keyguard showing state changed. */
+ public void onKeyguardShowingChanged(boolean isShowing) {
+ if (!isSplitActive() || mView == null) {
+ return;
+ }
+ mView.setHidden(isShowing);
+ if (!isShowing) {
+ mImePositionProcessor.updateAdjustForIme();
+ }
+ mIsKeyguardShowing = isShowing;
+ }
+
+ @Override
+ public void onDisplayAdded(int displayId) {
+ if (displayId != DEFAULT_DISPLAY) {
+ return;
+ }
+ mSplitLayout = new SplitDisplayLayout(mDisplayController.getDisplayContext(displayId),
+ mDisplayController.getDisplayLayout(displayId), mSplits);
+ mImeController.addPositionProcessor(mImePositionProcessor);
+ mDisplayController.addDisplayChangingController(mRotationController);
+ if (!ActivityTaskManager.supportsSplitScreenMultiWindow(mContext)) {
+ removeDivider();
+ return;
+ }
+ try {
+ mSplits.init();
+ // Set starting tile bounds based on middle target
+ final WindowContainerTransaction tct = new WindowContainerTransaction();
+ int midPos = mSplitLayout.getSnapAlgorithm().getMiddleTarget().position;
+ mSplitLayout.resizeSplits(midPos, tct);
+ WindowOrganizer.applyTransaction(tct);
+ } catch (Exception e) {
+ Slog.e(TAG, "Failed to register docked stack listener", e);
+ removeDivider();
+ return;
+ }
+ }
+
+ @Override
+ public void onDisplayConfigurationChanged(int displayId, Configuration newConfig) {
+ if (displayId != DEFAULT_DISPLAY || !mSplits.isSplitScreenSupported()) {
+ return;
+ }
+ mSplitLayout = new SplitDisplayLayout(mDisplayController.getDisplayContext(displayId),
+ mDisplayController.getDisplayLayout(displayId), mSplits);
+ if (mRotateSplitLayout == null) {
+ int midPos = mSplitLayout.getSnapAlgorithm().getMiddleTarget().position;
+ final WindowContainerTransaction tct = new WindowContainerTransaction();
+ mSplitLayout.resizeSplits(midPos, tct);
+ WindowOrganizer.applyTransaction(tct);
+ } else if (mSplitLayout.mDisplayLayout.rotation()
+ == mRotateSplitLayout.mDisplayLayout.rotation()) {
+ mSplitLayout.mPrimary = new Rect(mRotateSplitLayout.mPrimary);
+ mSplitLayout.mSecondary = new Rect(mRotateSplitLayout.mSecondary);
+ mRotateSplitLayout = null;
+ }
+ if (isSplitActive()) {
+ update(newConfig);
+ }
+ }
+
+ /** Posts task to handler dealing with divider. */
+ void post(Runnable task) {
+ mHandler.post(task);
+ }
+
+ /** Returns {@link DividerView}. */
+ public DividerView getDividerView() {
+ return mView;
+ }
+
+ /** Returns {@code true} if one of the split screen is in minimized mode. */
+ public boolean isMinimized() {
+ return mMinimized;
+ }
+
+ public boolean isHomeStackResizable() {
+ return mHomeStackResizable;
+ }
+
+ /** Returns {@code true} if the divider is visible. */
+ public boolean isDividerVisible() {
+ return mView != null && mView.getVisibility() == View.VISIBLE;
+ }
+
+ /**
+ * This indicates that at-least one of the splits has content. This differs from
+ * isDividerVisible because the divider is only visible once *everything* is in split mode
+ * while this only cares if some things are (eg. while entering/exiting as well).
+ */
+ private boolean isSplitActive() {
+ return mSplits.mPrimary != null && mSplits.mSecondary != null
+ && (mSplits.mPrimary.topActivityType != ACTIVITY_TYPE_UNDEFINED
+ || mSplits.mSecondary.topActivityType != ACTIVITY_TYPE_UNDEFINED);
+ }
+
+ private void addDivider(Configuration configuration) {
+ Context dctx = mDisplayController.getDisplayContext(mContext.getDisplayId());
+ mView = (DividerView)
+ LayoutInflater.from(dctx).inflate(R.layout.docked_stack_divider, null);
+ DisplayLayout displayLayout = mDisplayController.getDisplayLayout(mContext.getDisplayId());
+ mView.injectDependencies(mWindowManager, mDividerState, this, mSplits, mSplitLayout,
+ mImePositionProcessor, mWindowManagerProxy);
+ mView.setVisibility(mVisible ? View.VISIBLE : View.INVISIBLE);
+ mView.setMinimizedDockStack(mMinimized, mHomeStackResizable, null /* transaction */);
+ final int size = dctx.getResources().getDimensionPixelSize(
+ com.android.internal.R.dimen.docked_stack_divider_thickness);
+ final boolean landscape = configuration.orientation == ORIENTATION_LANDSCAPE;
+ final int width = landscape ? size : displayLayout.width();
+ final int height = landscape ? displayLayout.height() : size;
+ mWindowManager.add(mView, width, height, mContext.getDisplayId());
+ }
+
+ private void removeDivider() {
+ if (mView != null) {
+ mView.onDividerRemoved();
+ }
+ mWindowManager.remove();
+ }
+
+ private void update(Configuration configuration) {
+ final boolean isDividerHidden = mView != null && mIsKeyguardShowing;
+
+ removeDivider();
+ addDivider(configuration);
+
+ if (mMinimized) {
+ mView.setMinimizedDockStack(true, mHomeStackResizable, null /* transaction */);
+ updateTouchable();
+ }
+ mView.setHidden(isDividerHidden);
+ }
+
+ void onTaskVanished() {
+ mHandler.post(this::removeDivider);
+ }
+
+ private void updateVisibility(final boolean visible) {
+ if (DEBUG) Slog.d(TAG, "Updating visibility " + mVisible + "->" + visible);
+ if (mVisible != visible) {
+ mVisible = visible;
+ mView.setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
+
+ if (visible) {
+ mView.enterSplitMode(mHomeStackResizable);
+ // Update state because animations won't finish.
+ mWindowManagerProxy.runInSync(
+ t -> mView.setMinimizedDockStack(mMinimized, mHomeStackResizable, t));
+
+ } else {
+ mView.exitSplitMode();
+ mWindowManagerProxy.runInSync(
+ t -> mView.setMinimizedDockStack(false, mHomeStackResizable, t));
+ }
+ // Notify existence listeners
+ synchronized (mDockedStackExistsListeners) {
+ mDockedStackExistsListeners.removeIf(wf -> {
+ Consumer<Boolean> l = wf.get();
+ if (l != null) l.accept(visible);
+ return l == null;
+ });
+ }
+ }
+ }
+
+ /** Switch to minimized state if appropriate. */
+ public void setMinimized(final boolean minimized) {
+ if (DEBUG) Slog.d(TAG, "posting ext setMinimized " + minimized + " vis:" + mVisible);
+ mHandler.post(() -> {
+ if (DEBUG) Slog.d(TAG, "run posted ext setMinimized " + minimized + " vis:" + mVisible);
+ if (!mVisible) {
+ return;
+ }
+ setHomeMinimized(minimized);
+ });
+ }
+
+ private void setHomeMinimized(final boolean minimized) {
+ if (DEBUG) {
+ Slog.d(TAG, "setHomeMinimized min:" + mMinimized + "->" + minimized + " hrsz:"
+ + mHomeStackResizable + " split:" + isDividerVisible());
+ }
+ WindowContainerTransaction wct = new WindowContainerTransaction();
+ final boolean minimizedChanged = mMinimized != minimized;
+ // Update minimized state
+ if (minimizedChanged) {
+ mMinimized = minimized;
+ }
+ // Always set this because we could be entering split when mMinimized is already true
+ wct.setFocusable(mSplits.mPrimary.token, !mMinimized);
+
+ // Sync state to DividerView if it exists.
+ if (mView != null) {
+ final int displayId = mView.getDisplay() != null
+ ? mView.getDisplay().getDisplayId() : DEFAULT_DISPLAY;
+ // pause ime here (before updateMinimizedDockedStack)
+ if (mMinimized) {
+ mImePositionProcessor.pause(displayId);
+ }
+ if (minimizedChanged) {
+ // This conflicts with IME adjustment, so only call it when things change.
+ mView.setMinimizedDockStack(minimized, getAnimDuration(), mHomeStackResizable);
+ }
+ if (!mMinimized) {
+ // afterwards so it can end any animations started in view
+ mImePositionProcessor.resume(displayId);
+ }
+ }
+ updateTouchable();
+
+ // If we are only setting focusability, a sync transaction isn't necessary (in fact it
+ // can interrupt other animations), so see if it can be submitted on pending instead.
+ if (!mWindowManagerProxy.queueSyncTransactionIfWaiting(wct)) {
+ WindowOrganizer.applyTransaction(wct);
+ }
+ }
+
+ void setAdjustedForIme(boolean adjustedForIme) {
+ if (mAdjustedForIme == adjustedForIme) {
+ return;
+ }
+ mAdjustedForIme = adjustedForIme;
+ updateTouchable();
+ }
+
+ private void updateTouchable() {
+ mWindowManager.setTouchable(!mAdjustedForIme);
+ }
+
+ /**
+ * Workaround for b/62528361, at the time recents has drawn, it may happen before a
+ * configuration change to the Divider, and internally, the event will be posted to the
+ * subscriber, or DividerView, which has been removed and prevented from resizing. Instead,
+ * register the event handler here and proxy the event to the current DividerView.
+ */
+ public void onRecentsDrawn() {
+ if (mView != null) {
+ mView.onRecentsDrawn();
+ }
+ }
+
+ /** Called when there's a task undocking. */
+ public void onUndockingTask() {
+ if (mView != null) {
+ mView.onUndockingTask();
+ }
+ }
+
+ /** Called when the first docked animation frame rendered. */
+ public void onDockedFirstAnimationFrame() {
+ if (mView != null) {
+ mView.onDockedFirstAnimationFrame();
+ }
+ }
+
+ /** Called when top task docked. */
+ public void onDockedTopTask() {
+ if (mView != null) {
+ mView.onDockedTopTask();
+ }
+ }
+
+ /** Called when app transition finished. */
+ public void onAppTransitionFinished() {
+ if (mView == null) {
+ return;
+ }
+ mForcedResizableController.onAppTransitionFinished();
+ }
+
+ @Override
+ public void onDraggingStart() {
+ mForcedResizableController.onDraggingStart();
+ }
+
+ @Override
+ public void onDraggingEnd() {
+ mForcedResizableController.onDraggingEnd();
+ }
+
+ /** Dumps current status of Divider.*/
+ public void dump(PrintWriter pw) {
+ pw.print(" mVisible="); pw.println(mVisible);
+ pw.print(" mMinimized="); pw.println(mMinimized);
+ pw.print(" mAdjustedForIme="); pw.println(mAdjustedForIme);
+ }
+
+ long getAnimDuration() {
+ float transitionScale = Settings.Global.getFloat(mContext.getContentResolver(),
+ Settings.Global.TRANSITION_ANIMATION_SCALE,
+ mContext.getResources().getFloat(
+ com.android.internal.R.dimen
+ .config_appTransitionAnimationDurationScaleDefault));
+ final long transitionDuration = DEFAULT_APP_TRANSITION_DURATION;
+ return (long) (transitionDuration * transitionScale);
+ }
+
+ /** Registers listener that gets called whenever the existence of the divider changes. */
+ public void registerInSplitScreenListener(Consumer<Boolean> listener) {
+ listener.accept(isDividerVisible());
+ synchronized (mDockedStackExistsListeners) {
+ mDockedStackExistsListeners.add(new WeakReference<>(listener));
+ }
+ }
+
+ void startEnterSplit() {
+ update(mDisplayController.getDisplayContext(
+ mContext.getDisplayId()).getResources().getConfiguration());
+ // Set resizable directly here because applyEnterSplit already resizes home stack.
+ mHomeStackResizable = mWindowManagerProxy.applyEnterSplit(mSplits, mSplitLayout);
+ }
+
+ void startDismissSplit() {
+ mWindowManagerProxy.applyDismissSplit(mSplits, mSplitLayout, true /* dismissOrMaximize */);
+ updateVisibility(false /* visible */);
+ mMinimized = false;
+ removeDivider();
+ mImePositionProcessor.reset();
+ }
+
+ void ensureMinimizedSplit() {
+ setHomeMinimized(true /* minimized */);
+ if (mView != null && !isDividerVisible()) {
+ // Wasn't in split-mode yet, so enter now.
+ if (DEBUG) {
+ Slog.d(TAG, " entering split mode with minimized=true");
+ }
+ updateVisibility(true /* visible */);
+ }
+ }
+
+ void ensureNormalSplit() {
+ setHomeMinimized(false /* minimized */);
+ if (mView != null && !isDividerVisible()) {
+ // Wasn't in split-mode, so enter now.
+ if (DEBUG) {
+ Slog.d(TAG, " enter split mode unminimized ");
+ }
+ updateVisibility(true /* visible */);
+ }
+ }
+
+ SplitDisplayLayout getSplitLayout() {
+ return mSplitLayout;
+ }
+
+ WindowManagerProxy getWmProxy() {
+ return mWindowManagerProxy;
+ }
+
+ /** @return the container token for the secondary split root task. */
+ public WindowContainerToken getSecondaryRoot() {
+ if (mSplits == null || mSplits.mSecondary == null) {
+ return null;
+ }
+ return mSplits.mSecondary.token;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerHandleView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerHandleView.java
index d5f7b39b8e61..a10242a689a2 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerHandleView.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerHandleView.java
@@ -34,7 +34,7 @@ import com.android.systemui.R;
/**
* View for the handle in the docked stack divider.
*/
-public class DividerHandleView extends View {
+class DividerHandleView extends View {
private final static Property<DividerHandleView, Integer> WIDTH_PROPERTY
= new Property<DividerHandleView, Integer>(Integer.class, "width") {
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerImeController.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerImeController.java
index 84ec38744e98..c915f071297f 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerImeController.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerImeController.java
@@ -38,7 +38,7 @@ import com.android.wm.shell.common.TransactionPool;
class DividerImeController implements DisplayImeController.ImePositionProcessor {
private static final String TAG = "DividerImeController";
- private static final boolean DEBUG = Divider.DEBUG;
+ private static final boolean DEBUG = DividerController.DEBUG;
private static final float ADJUSTED_NONFOCUS_DIM = 0.3f;
@@ -100,15 +100,15 @@ class DividerImeController implements DisplayImeController.ImePositionProcessor
}
private DividerView getView() {
- return mSplits.mDivider.getView();
+ return mSplits.mDividerController.getDividerView();
}
private SplitDisplayLayout getLayout() {
- return mSplits.mDivider.getSplitLayout();
+ return mSplits.mDividerController.getSplitLayout();
}
private boolean isDividerVisible() {
- return mSplits.mDivider.isDividerVisible();
+ return mSplits.mDividerController.isDividerVisible();
}
private boolean getSecondaryHasFocus(int displayId) {
@@ -151,7 +151,7 @@ class DividerImeController implements DisplayImeController.ImePositionProcessor
mSecondaryHasFocus = getSecondaryHasFocus(displayId);
final boolean targetAdjusted = splitIsVisible && imeShouldShow && mSecondaryHasFocus
&& !imeIsFloating && !getLayout().mDisplayLayout.isLandscape()
- && !mSplits.mDivider.isMinimized();
+ && !mSplits.mDividerController.isMinimized();
if (mLastAdjustTop < 0) {
mLastAdjustTop = imeShouldShow ? hiddenTop : shownTop;
} else if (mLastAdjustTop != (imeShouldShow ? mShownTop : mHiddenTop)) {
@@ -236,7 +236,7 @@ class DividerImeController implements DisplayImeController.ImePositionProcessor
SCREEN_WIDTH_DP_UNDEFINED, SCREEN_HEIGHT_DP_UNDEFINED);
}
- if (!mSplits.mDivider.getWmProxy().queueSyncTransactionIfWaiting(wct)) {
+ if (!mSplits.mDividerController.getWmProxy().queueSyncTransactionIfWaiting(wct)) {
WindowOrganizer.applyTransaction(wct);
}
}
@@ -250,7 +250,7 @@ class DividerImeController implements DisplayImeController.ImePositionProcessor
: DisplayImeController.ANIMATION_DURATION_HIDE_MS);
}
}
- mSplits.mDivider.setAdjustedForIme(mTargetShown && !mPaused);
+ mSplits.mDividerController.setAdjustedForIme(mTargetShown && !mPaused);
}
public void updateAdjustForIme() {
@@ -343,10 +343,12 @@ class DividerImeController implements DisplayImeController.ImePositionProcessor
mAnimation.setInterpolator(DisplayImeController.INTERPOLATOR);
mAnimation.addListener(new AnimatorListenerAdapter() {
private boolean mCancel = false;
+
@Override
public void onAnimationCancel(Animator animation) {
mCancel = true;
}
+
@Override
public void onAnimationEnd(Animator animation) {
SurfaceControl.Transaction t = mTransactionPool.acquire();
@@ -400,7 +402,8 @@ class DividerImeController implements DisplayImeController.ImePositionProcessor
mTargetAdjusted = mPausedTargetAdjusted;
updateDimTargets();
final DividerView view = getView();
- if ((mTargetAdjusted != mAdjusted) && !mSplits.mDivider.isMinimized() && view != null) {
+ if ((mTargetAdjusted != mAdjusted) && !mSplits.mDividerController.isMinimized()
+ && view != null) {
// End unminimize animations since they conflict with adjustment animations.
view.finishAnimations();
}
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerModule.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerModule.java
index c24431c22d62..db0aef8a0611 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerModule.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerModule.java
@@ -20,18 +20,14 @@ import android.content.Context;
import android.os.Handler;
import com.android.systemui.dagger.qualifiers.Main;
-import com.android.systemui.recents.Recents;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.DisplayImeController;
import com.android.wm.shell.common.SystemWindows;
import com.android.wm.shell.common.TransactionPool;
-import java.util.Optional;
-
import javax.inject.Singleton;
-import dagger.Lazy;
import dagger.Module;
import dagger.Provides;
@@ -42,11 +38,12 @@ import dagger.Provides;
public class DividerModule {
@Singleton
@Provides
- static Divider provideDivider(Context context, Optional<Lazy<Recents>> recentsOptionalLazy,
- DisplayController displayController, SystemWindows systemWindows,
- DisplayImeController imeController, @Main Handler handler,
+ static Divider provideDivider(Context context, DisplayController displayController,
+ SystemWindows systemWindows, DisplayImeController imeController, @Main Handler handler,
KeyguardStateController keyguardStateController, TransactionPool transactionPool) {
- return new Divider(context, recentsOptionalLazy, displayController, systemWindows,
- imeController, handler, keyguardStateController, transactionPool);
+ // TODO(b/161116823): fetch DividerProxy from WM shell lib.
+ DividerController dividerController = new DividerController(context, displayController,
+ systemWindows, imeController, handler, transactionPool);
+ return new Divider(context, dividerController, keyguardStateController);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerState.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerState.java
index 3a5c61e6d7f0..8e79d51ee209 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerState.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerState.java
@@ -21,6 +21,5 @@ package com.android.systemui.stackdivider;
*/
public class DividerState {
public boolean animateAfterRecentsDrawn;
- public boolean growAfterRecentsDrawn;
public float mRatioPositionBeforeMinimized;
}
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
index b6c6afd523b3..e5c02d6fc454 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
@@ -76,12 +76,11 @@ import java.util.function.Consumer;
public class DividerView extends FrameLayout implements OnTouchListener,
OnComputeInternalInsetsListener {
private static final String TAG = "DividerView";
- private static final boolean DEBUG = Divider.DEBUG;
+ private static final boolean DEBUG = DividerController.DEBUG;
public interface DividerCallbacks {
void onDraggingStart();
void onDraggingEnd();
- void growRecents();
}
static final long TOUCH_ANIMATION_DURATION = 150;
@@ -148,7 +147,6 @@ public class DividerView extends FrameLayout implements OnTouchListener,
private DividerCallbacks mCallback;
private final AnimationHandler mAnimationHandler = new AnimationHandler();
- private boolean mGrowRecents;
private ValueAnimator mCurrentAnimator;
private boolean mEntranceAnimationRunning;
private boolean mExitAnimationRunning;
@@ -304,7 +302,6 @@ public class DividerView extends FrameLayout implements OnTouchListener,
R.dimen.docked_stack_divider_lift_elevation);
mLongPressEntraceAnimDuration = getResources().getInteger(
R.integer.long_press_dock_anim_duration);
- mGrowRecents = getResources().getBoolean(R.bool.recents_grow_in_multiwindow);
mTouchSlop = ViewConfiguration.get(mContext).getScaledTouchSlop();
mFlingAnimationUtils = new FlingAnimationUtils(getResources().getDisplayMetrics(), 0.3f);
boolean landscape = getResources().getConfiguration().orientation
@@ -437,17 +434,17 @@ public class DividerView extends FrameLayout implements OnTouchListener,
releaseBackground();
}
- public void stopDragging(int position, SnapTarget target, long duration,
+ private void stopDragging(int position, SnapTarget target, long duration,
Interpolator interpolator) {
stopDragging(position, target, duration, 0 /* startDelay*/, 0 /* endDelay */, interpolator);
}
- public void stopDragging(int position, SnapTarget target, long duration,
+ private void stopDragging(int position, SnapTarget target, long duration,
Interpolator interpolator, long endDelay) {
stopDragging(position, target, duration, 0 /* startDelay*/, endDelay, interpolator);
}
- public void stopDragging(int position, SnapTarget target, long duration, long startDelay,
+ private void stopDragging(int position, SnapTarget target, long duration, long startDelay,
long endDelay, Interpolator interpolator) {
mHandle.setTouching(false, true /* animate */);
flingTo(position, target, duration, startDelay, endDelay, interpolator);
@@ -1319,39 +1316,11 @@ public class DividerView extends FrameLayout implements OnTouchListener,
mBackground.getRight(), mBackground.getBottom(), Op.UNION);
}
- /**
- * Checks whether recents will grow when invoked. This happens in multi-window when recents is
- * very small. When invoking recents, we shrink the docked stack so recents has more space.
- *
- * @return the position of the divider when recents grows, or
- * {@link #INVALID_RECENTS_GROW_TARGET} if recents won't grow
- */
- public int growsRecents() {
- boolean result = mGrowRecents
- && mDockSide == WindowManager.DOCKED_TOP
- && getCurrentPosition() == getSnapAlgorithm().getLastSplitTarget().position;
- if (result) {
- return getSnapAlgorithm().getMiddleTarget().position;
- } else {
- return INVALID_RECENTS_GROW_TARGET;
- }
- }
-
- void onRecentsActivityStarting() {
- if (mGrowRecents && mDockSide == WindowManager.DOCKED_TOP
- && getSnapAlgorithm().getMiddleTarget() != getSnapAlgorithm().getLastSplitTarget()
- && getCurrentPosition() == getSnapAlgorithm().getLastSplitTarget().position) {
- mState.growAfterRecentsDrawn = true;
- startDragging(false /* animate */, false /* touching */);
- }
- }
-
void onDockedFirstAnimationFrame() {
saveSnapTargetBeforeMinimized(mSplitLayout.getSnapAlgorithm().getMiddleTarget());
}
void onDockedTopTask() {
- mState.growAfterRecentsDrawn = false;
mState.animateAfterRecentsDrawn = true;
startDragging(false /* animate */, false /* touching */);
updateDockSide();
@@ -1377,15 +1346,6 @@ public class DividerView extends FrameLayout implements OnTouchListener,
200 /* endDelay */);
});
}
- if (mState.growAfterRecentsDrawn) {
- mState.growAfterRecentsDrawn = false;
- updateDockSide();
- if (mCallback != null) {
- mCallback.growRecents();
- }
- stopDragging(position, getSnapAlgorithm().getMiddleTarget(), 336,
- Interpolators.FAST_OUT_SLOW_IN);
- }
}
void onUndockingTask() {
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivityController.java b/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivityController.java
index db7996eed7f0..f412cc00981b 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivityController.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivityController.java
@@ -75,7 +75,8 @@ public class ForcedResizableInfoActivityController {
}
}
- public ForcedResizableInfoActivityController(Context context, Divider divider) {
+ public ForcedResizableInfoActivityController(Context context,
+ DividerController dividerController) {
mContext = context;
ActivityManagerWrapper.getInstance().registerTaskStackListener(
new TaskStackChangeListener() {
@@ -95,7 +96,7 @@ public class ForcedResizableInfoActivityController {
activityLaunchOnSecondaryDisplayFailed();
}
});
- divider.registerInSplitScreenListener(mDockedStackExistsListener);
+ dividerController.registerInSplitScreenListener(mDockedStackExistsListener);
}
public void onAppTransitionFinished() {
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreenTaskOrganizer.java b/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreenTaskOrganizer.java
index 7a313dc0622b..ef5e8a15882c 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreenTaskOrganizer.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreenTaskOrganizer.java
@@ -35,7 +35,7 @@ import android.window.TaskOrganizer;
class SplitScreenTaskOrganizer extends TaskOrganizer {
private static final String TAG = "SplitScreenTaskOrg";
- private static final boolean DEBUG = Divider.DEBUG;
+ private static final boolean DEBUG = DividerController.DEBUG;
RunningTaskInfo mPrimary;
RunningTaskInfo mSecondary;
@@ -44,13 +44,13 @@ class SplitScreenTaskOrganizer extends TaskOrganizer {
SurfaceControl mPrimaryDim;
SurfaceControl mSecondaryDim;
Rect mHomeBounds = new Rect();
- final Divider mDivider;
+ final DividerController mDividerController;
private boolean mSplitScreenSupported = false;
final SurfaceSession mSurfaceSession = new SurfaceSession();
- SplitScreenTaskOrganizer(Divider divider) {
- mDivider = divider;
+ SplitScreenTaskOrganizer(DividerController dividerController) {
+ mDividerController = dividerController;
}
void init() throws RemoteException {
@@ -75,11 +75,11 @@ class SplitScreenTaskOrganizer extends TaskOrganizer {
}
SurfaceControl.Transaction getTransaction() {
- return mDivider.mTransactionPool.acquire();
+ return mDividerController.mTransactionPool.acquire();
}
void releaseTransaction(SurfaceControl.Transaction t) {
- mDivider.mTransactionPool.release(t);
+ mDividerController.mTransactionPool.release(t);
}
@Override
@@ -140,7 +140,7 @@ class SplitScreenTaskOrganizer extends TaskOrganizer {
t.apply();
releaseTransaction(t);
- mDivider.onTaskVanished();
+ mDividerController.onTaskVanished();
}
}
}
@@ -150,7 +150,7 @@ class SplitScreenTaskOrganizer extends TaskOrganizer {
if (taskInfo.displayId != DEFAULT_DISPLAY) {
return;
}
- mDivider.getHandler().post(() -> handleTaskInfoChanged(taskInfo));
+ mDividerController.post(() -> handleTaskInfoChanged(taskInfo));
}
/**
@@ -169,7 +169,7 @@ class SplitScreenTaskOrganizer extends TaskOrganizer {
}
final boolean secondaryImpliedMinimize = mSecondary.topActivityType == ACTIVITY_TYPE_HOME
|| (mSecondary.topActivityType == ACTIVITY_TYPE_RECENTS
- && mDivider.isHomeStackResizable());
+ && mDividerController.isHomeStackResizable());
final boolean primaryWasEmpty = mPrimary.topActivityType == ACTIVITY_TYPE_UNDEFINED;
final boolean secondaryWasEmpty = mSecondary.topActivityType == ACTIVITY_TYPE_UNDEFINED;
if (info.token.asBinder() == mPrimary.token.asBinder()) {
@@ -181,7 +181,7 @@ class SplitScreenTaskOrganizer extends TaskOrganizer {
final boolean secondaryIsEmpty = mSecondary.topActivityType == ACTIVITY_TYPE_UNDEFINED;
final boolean secondaryImpliesMinimize = mSecondary.topActivityType == ACTIVITY_TYPE_HOME
|| (mSecondary.topActivityType == ACTIVITY_TYPE_RECENTS
- && mDivider.isHomeStackResizable());
+ && mDividerController.isHomeStackResizable());
if (DEBUG) {
Log.d(TAG, "onTaskInfoChanged " + mPrimary + " " + mSecondary);
}
@@ -197,14 +197,14 @@ class SplitScreenTaskOrganizer extends TaskOrganizer {
Log.d(TAG, " at-least one split empty " + mPrimary.topActivityType
+ " " + mSecondary.topActivityType);
}
- if (mDivider.isDividerVisible()) {
+ if (mDividerController.isDividerVisible()) {
// Was in split-mode, which means we are leaving split, so continue that.
// This happens when the stack in the primary-split is dismissed.
if (DEBUG) {
Log.d(TAG, " was in split, so this means leave it "
+ mPrimary.topActivityType + " " + mSecondary.topActivityType);
}
- mDivider.startDismissSplit();
+ mDividerController.startDismissSplit();
} else if (!primaryIsEmpty && primaryWasEmpty && secondaryWasEmpty) {
// Wasn't in split-mode (both were empty), but now that the primary split is
// populated, we should fully enter split by moving everything else into secondary.
@@ -213,15 +213,15 @@ class SplitScreenTaskOrganizer extends TaskOrganizer {
if (DEBUG) {
Log.d(TAG, " was not in split, but primary is populated, so enter it");
}
- mDivider.startEnterSplit();
+ mDividerController.startEnterSplit();
}
} else if (secondaryImpliesMinimize) {
// Both splits are populated but the secondary split has a home/recents stack on top,
// so enter minimized mode.
- mDivider.ensureMinimizedSplit();
+ mDividerController.ensureMinimizedSplit();
} else {
// Both splits are populated by normal activities, so make sure we aren't minimized.
- mDivider.ensureNormalSplit();
+ mDividerController.ensureNormalSplit();
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/SyncTransactionQueue.java b/packages/SystemUI/src/com/android/systemui/stackdivider/SyncTransactionQueue.java
index 6812f62422a7..f2500e59abab 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/SyncTransactionQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/SyncTransactionQueue.java
@@ -33,7 +33,7 @@ import java.util.ArrayList;
* Helper for serializing sync-transactions and corresponding callbacks.
*/
class SyncTransactionQueue {
- private static final boolean DEBUG = Divider.DEBUG;
+ private static final boolean DEBUG = DividerController.DEBUG;
private static final String TAG = "SyncTransactionQueue";
// Just a little longer than the sync-engine timeout of 5s
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java b/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java
index 2b3681281064..82b10bd40b17 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java
@@ -50,7 +50,7 @@ import java.util.concurrent.Executors;
/**
* Proxy to simplify calls into window manager/activity manager
*/
-public class WindowManagerProxy {
+class WindowManagerProxy {
private static final String TAG = "WindowManagerProxy";
private static final int[] HOME_AND_RECENTS = {ACTIVITY_TYPE_HOME, ACTIVITY_TYPE_RECENTS};
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 aba9e1005559..e1ff872456eb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
@@ -15,7 +15,6 @@
*/
package com.android.systemui.statusbar.notification;
-import static android.service.notification.NotificationListenerService.REASON_CANCEL;
import static android.service.notification.NotificationListenerService.REASON_ERROR;
import static com.android.systemui.statusbar.notification.collection.NotifCollection.REASON_UNKNOWN;
@@ -24,14 +23,11 @@ import static com.android.systemui.statusbar.notification.row.NotificationRowCon
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.Notification;
-import android.content.Context;
import android.os.RemoteException;
-import android.os.ServiceManager;
import android.os.SystemClock;
import android.service.notification.NotificationListenerService;
import android.service.notification.NotificationListenerService.Ranking;
import android.service.notification.NotificationListenerService.RankingMap;
-import android.service.notification.NotificationStats;
import android.service.notification.StatusBarNotification;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -41,7 +37,6 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.statusbar.NotificationVisibility;
import com.android.systemui.Dumpable;
-import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.NotificationLifetimeExtender;
import com.android.systemui.statusbar.NotificationListener;
@@ -54,11 +49,11 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationRankingManager;
import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinder;
import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection;
+import com.android.systemui.statusbar.notification.collection.notifcollection.DismissedByUserStats;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
import com.android.systemui.statusbar.notification.dagger.NotificationsModule;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
-import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.util.Assert;
import com.android.systemui.util.leak.LeakDetector;
@@ -147,8 +142,6 @@ public class NotificationEntryManager implements
private final NotificationRankingManager mRankingManager;
private final FeatureFlags mFeatureFlags;
private final ForegroundServiceDismissalFeatureController mFgsFeatureController;
- private final HeadsUpManager mHeadsUpManager;
- private final StatusBarStateController mStatusBarStateController;
private NotificationPresenter mPresenter;
private RankingMap mLatestRankingMap;
@@ -213,8 +206,7 @@ public class NotificationEntryManager implements
Lazy<NotificationRemoteInputManager> notificationRemoteInputManagerLazy,
LeakDetector leakDetector,
ForegroundServiceDismissalFeatureController fgsFeatureController,
- HeadsUpManager headsUpManager,
- StatusBarStateController statusBarStateController
+ IStatusBarService statusBarService
) {
mLogger = logger;
mGroupManager = groupManager;
@@ -225,11 +217,7 @@ public class NotificationEntryManager implements
mRemoteInputManagerLazy = notificationRemoteInputManagerLazy;
mLeakDetector = leakDetector;
mFgsFeatureController = fgsFeatureController;
- mHeadsUpManager = headsUpManager;
- mStatusBarStateController = statusBarStateController;
-
- mStatusBarService = IStatusBarService.Stub.asInterface(
- ServiceManager.checkService(Context.STATUS_BAR_SERVICE));
+ mStatusBarService = statusBarService;
}
/** Once called, the NEM will start processing notification events from system server. */
@@ -284,16 +272,23 @@ public class NotificationEntryManager implements
}
/**
- * Requests a notification to be removed.
+ * User requests a notification to be removed.
*
* @param n the notification to remove.
* @param reason why it is being removed e.g. {@link NotificationListenerService#REASON_CANCEL},
* or 0 if unknown.
*/
- public void performRemoveNotification(StatusBarNotification n, int reason) {
- final NotificationVisibility nv = obtainVisibility(n.getKey());
+ public void performRemoveNotification(
+ StatusBarNotification n,
+ @NonNull DismissedByUserStats stats,
+ int reason
+ ) {
removeNotificationInternal(
- n.getKey(), null, nv, false /* forceRemove */, true /* removedByUser */,
+ n.getKey(),
+ null,
+ stats.notificationVisibility,
+ false /* forceRemove */,
+ stats,
reason);
}
@@ -337,7 +332,11 @@ public class NotificationEntryManager implements
*/
private void handleInflationException(StatusBarNotification n, Exception e) {
removeNotificationInternal(
- n.getKey(), null, null, true /* forceRemove */, false /* removedByUser */,
+ n.getKey(),
+ null,
+ null,
+ true /* forceRemove */,
+ null /* dismissedByUserStats */,
REASON_ERROR);
for (NotificationEntryListener listener : mNotificationEntryListeners) {
listener.onInflationError(n, e);
@@ -435,19 +434,28 @@ public class NotificationEntryManager implements
reapplyFilterAndSort("addVisibleNotification");
}
-
- public void removeNotification(String key, RankingMap ranking,
- int reason) {
- removeNotificationInternal(key, ranking, obtainVisibility(key), false /* forceRemove */,
- false /* removedByUser */, reason);
+ @VisibleForTesting
+ protected void removeNotification(String key, RankingMap ranking, int reason) {
+ removeNotificationInternal(
+ key,
+ ranking,
+ obtainVisibility(key),
+ false /* forceRemove */,
+ null /* dismissedByUserStats */,
+ reason);
}
+ /**
+ * Internally remove a notification because system server has reported the notification
+ * should be removed OR the user has manually dismissed the notification
+ * @param dismissedByUserStats non-null if the user manually dismissed the notification
+ */
private void removeNotificationInternal(
String key,
@Nullable RankingMap ranking,
@Nullable NotificationVisibility visibility,
boolean forceRemove,
- boolean removedByUser,
+ DismissedByUserStats dismissedByUserStats,
int reason) {
final NotificationEntry entry = getActiveNotificationUnfiltered(key);
@@ -512,11 +520,11 @@ public class NotificationEntryManager implements
handleGroupSummaryRemoved(key);
removeVisibleNotification(key);
updateNotifications("removeNotificationInternal");
- removedByUser |= entryDismissed;
+ final boolean removedByUser = dismissedByUserStats != null;
mLogger.logNotifRemoved(entry.getKey(), removedByUser);
if (removedByUser && visibility != null) {
- sendNotificationRemovalToServer(entry.getKey(), entry.getSbn(), visibility);
+ sendNotificationRemovalToServer(entry.getSbn(), dismissedByUserStats);
}
for (NotificationEntryListener listener : mNotificationEntryListeners) {
listener.onEntryRemoved(entry, visibility, removedByUser, reason);
@@ -534,30 +542,18 @@ public class NotificationEntryManager implements
}
private void sendNotificationRemovalToServer(
- String key,
StatusBarNotification notification,
- NotificationVisibility nv) {
- final String pkg = notification.getPackageName();
- final String tag = notification.getTag();
- final int id = notification.getId();
- final int userId = notification.getUser().getIdentifier();
+ DismissedByUserStats dismissedByUserStats) {
try {
- int dismissalSurface = NotificationStats.DISMISSAL_SHADE;
- if (mHeadsUpManager.isAlerting(key)) {
- dismissalSurface = NotificationStats.DISMISSAL_PEEK;
- } else if (mStatusBarStateController.isDozing()) {
- dismissalSurface = NotificationStats.DISMISSAL_AOD;
- }
- int dismissalSentiment = NotificationStats.DISMISS_SENTIMENT_NEUTRAL;
mStatusBarService.onNotificationClear(
- pkg,
- tag,
- id,
- userId,
+ notification.getPackageName(),
+ notification.getTag(),
+ notification.getId(),
+ notification.getUser().getIdentifier(),
notification.getKey(),
- dismissalSurface,
- dismissalSentiment,
- nv);
+ dismissedByUserStats.dismissalSurface,
+ dismissedByUserStats.dismissalSentiment,
+ dismissedByUserStats.notificationVisibility);
} catch (RemoteException ex) {
// system process is dead if we're here.
}
@@ -641,11 +637,7 @@ public class NotificationEntryManager implements
// Construct the expanded view.
if (!mFeatureFlags.isNewNotifPipelineRenderingEnabled()) {
- mNotificationRowBinderLazy.get()
- .inflateViews(
- entry,
- () -> performRemoveNotification(notification, REASON_CANCEL),
- mInflationCallback);
+ mNotificationRowBinderLazy.get().inflateViews(entry, mInflationCallback);
}
mPendingNotifications.put(key, entry);
@@ -675,7 +667,7 @@ public class NotificationEntryManager implements
final String key = notification.getKey();
abortExistingInflation(key, "updateNotification");
- NotificationEntry entry = getActiveNotificationUnfiltered(key);
+ final NotificationEntry entry = getActiveNotificationUnfiltered(key);
if (entry == null) {
return;
}
@@ -701,11 +693,7 @@ public class NotificationEntryManager implements
}
if (!mFeatureFlags.isNewNotifPipelineRenderingEnabled()) {
- mNotificationRowBinderLazy.get()
- .inflateViews(
- entry,
- () -> performRemoveNotification(notification, REASON_CANCEL),
- mInflationCallback);
+ mNotificationRowBinderLazy.get().inflateViews(entry, mInflationCallback);
}
updateNotifications("updateNotificationInternal");
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/GroupEntry.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/GroupEntry.java
index 81494eddd989..0ea685793214 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/GroupEntry.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/GroupEntry.java
@@ -19,7 +19,6 @@ package com.android.systemui.statusbar.notification.collection;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.statusbar.notification.collection.coordinator.PreparationCoordinator;
import java.util.ArrayList;
@@ -39,9 +38,8 @@ public class GroupEntry extends ListEntry {
Collections.unmodifiableList(mChildren);
private int mUntruncatedChildCount;
- @VisibleForTesting
- public GroupEntry(String key) {
- super(key);
+ GroupEntry(String key, long creationTime) {
+ super(key, creationTime);
}
@Override
@@ -59,8 +57,7 @@ public class GroupEntry extends ListEntry {
return mUnmodifiableChildren;
}
- @VisibleForTesting
- public void setSummary(@Nullable NotificationEntry summary) {
+ void setSummary(@Nullable NotificationEntry summary) {
mSummary = summary;
}
@@ -98,6 +95,6 @@ public class GroupEntry extends ListEntry {
return mChildren;
}
- public static final GroupEntry ROOT_ENTRY = new GroupEntry("<root>");
+ public static final GroupEntry ROOT_ENTRY = new GroupEntry("<root>", 0);
}
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 97c1523887ad..3a0520115d67 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
@@ -19,6 +19,8 @@ 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 static java.util.Objects.requireNonNull;
+
import com.android.systemui.statusbar.NotificationInteractionTracker;
import java.util.Arrays;
@@ -56,7 +58,7 @@ public class ListDumper {
List<NotificationEntry> children = ge.getChildren();
for (int childIndex = 0; childIndex < children.size(); childIndex++) {
dumpEntry(children.get(childIndex),
- Integer.toString(topEntryIndex) + "." + Integer.toString(childIndex),
+ topEntryIndex + "." + childIndex,
childEntryIndent,
sb,
true,
@@ -118,7 +120,7 @@ public class ListDumper {
}
if (includeRecordKeeping) {
- NotificationEntry notifEntry = entry.getRepresentativeEntry();
+ NotificationEntry notifEntry = requireNonNull(entry.getRepresentativeEntry());
StringBuilder rksb = new StringBuilder();
if (!notifEntry.mLifetimeExtenders.isEmpty()) {
@@ -165,7 +167,9 @@ public class ListDumper {
.append(" ");
}
- rksb.append("interacted=").append(hasBeenInteractedWith ? "yes" : "no").append(" ");
+ if (hasBeenInteractedWith) {
+ rksb.append("interacted=yes ");
+ }
String rkString = rksb.toString();
if (!rkString.isEmpty()) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListEntry.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListEntry.java
index 837374fe2201..65f5dc4e5f7c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListEntry.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListEntry.java
@@ -17,6 +17,8 @@
package com.android.systemui.statusbar.notification.collection;
+import android.annotation.UptimeMillisLong;
+
import androidx.annotation.Nullable;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSection;
@@ -27,14 +29,16 @@ import com.android.systemui.statusbar.notification.collection.listbuilder.plugga
*/
public abstract class ListEntry {
private final String mKey;
+ private final long mCreationTime;
int mFirstAddedIteration = -1;
private final ListAttachState mPreviousAttachState = ListAttachState.create();
private final ListAttachState mAttachState = ListAttachState.create();
- ListEntry(String key) {
+ ListEntry(String key, long creationTime) {
mKey = key;
+ mCreationTime = creationTime;
}
public String getKey() {
@@ -42,6 +46,19 @@ public abstract class ListEntry {
}
/**
+ * The SystemClock.uptimeMillis() when this object was created. In general, this means the
+ * moment when NotificationManager notifies our listener about the existence of this entry.
+ *
+ * This value will not change if the notification is updated, although it will change if the
+ * notification is removed and then re-posted. It is also wholly independent from
+ * Notification#when.
+ */
+ @UptimeMillisLong
+ public long getCreationTime() {
+ return mCreationTime;
+ }
+
+ /**
* Should return the "representative entry" for this ListEntry. For NotificationEntries, its
* the entry itself. For groups, it should be the summary (but if a summary doesn't exist,
* this can return null). This method exists to interface with
@@ -79,6 +96,14 @@ public abstract class ListEntry {
}
/**
+ * True if this entry has been attached to the shade at least once in its lifetime (it may not
+ * currently be attached).
+ */
+ public boolean hasBeenAttachedBefore() {
+ return mFirstAddedIteration != -1;
+ }
+
+ /**
* Stores the current attach state into {@link #getPreviousAttachState()}} and then starts a
* fresh attach state (all entries will be null/default-initialized).
*/
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 d081e114855e..aaf5c4d6594b 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
@@ -16,17 +16,10 @@
package com.android.systemui.statusbar.notification.collection;
-import static android.service.notification.NotificationStats.DISMISS_SENTIMENT_NEUTRAL;
-
-import android.service.notification.NotificationStats;
-
import com.android.internal.statusbar.IStatusBarService;
-import com.android.internal.statusbar.NotificationVisibility;
import com.android.systemui.statusbar.notification.InflationException;
import com.android.systemui.statusbar.notification.collection.inflation.NotifInflater;
import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl;
-import com.android.systemui.statusbar.notification.collection.notifcollection.DismissedByUserStats;
-import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.notification.row.NotifInflationErrorManager;
import com.android.systemui.statusbar.notification.row.NotificationContentInflater;
@@ -81,7 +74,6 @@ public class NotifInflaterImpl implements NotifInflater {
try {
requireBinder().inflateViews(
entry,
- getDismissCallback(entry),
wrapInflationCallback(callback));
} catch (InflationException e) {
mNotifErrorManager.setInflationError(entry, e);
@@ -93,30 +85,6 @@ public class NotifInflaterImpl implements NotifInflater {
entry.abortTask();
}
- private Runnable getDismissCallback(NotificationEntry entry) {
- return new Runnable() {
- @Override
- public void run() {
- int dismissalSurface = NotificationStats.DISMISSAL_SHADE;
- /*
- * TODO: determine dismissal surface (ie: shade / headsup / aod)
- * see {@link NotificationLogger#logNotificationClear}
- */
- mNotifCollection.dismissNotification(
- entry,
- new DismissedByUserStats(
- dismissalSurface,
- DISMISS_SENTIMENT_NEUTRAL,
- NotificationVisibility.obtain(entry.getKey(),
- entry.getRanking().getRank(),
- mNotifPipeline.getShadeListCount(),
- true,
- NotificationLogger.getNotificationLocation(entry))
- ));
- }
- };
- }
-
private NotificationContentInflater.InflationCallback wrapInflationCallback(
InflationCallback callback) {
return new NotificationContentInflater.InflationCallback() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifViewManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifViewManager.kt
deleted file mode 100644
index 339809e0770b..000000000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifViewManager.kt
+++ /dev/null
@@ -1,204 +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.statusbar.notification.collection
-
-import android.annotation.MainThread
-import android.view.ViewGroup
-
-import com.android.systemui.statusbar.FeatureFlags
-import com.android.systemui.statusbar.notification.VisualStabilityManager
-import com.android.systemui.statusbar.notification.collection.GroupEntry.ROOT_ENTRY
-import com.android.systemui.statusbar.notification.stack.NotificationListItem
-import com.android.systemui.util.Assert
-
-import java.io.FileDescriptor
-import java.io.PrintWriter
-import java.lang.IllegalStateException
-import javax.inject.Inject
-import javax.inject.Singleton
-
-/**
- * A consumer of a Notification tree built by [ShadeListBuilder] which will update the notification
- * presenter with the minimum operations required to make the old tree match the new one
- */
-@MainThread
-@Singleton
-class NotifViewManager @Inject constructor(
- private val rowRegistry: NotifViewBarn,
- private val stabilityManager: VisualStabilityManager,
- private val featureFlags: FeatureFlags
-) {
- var currentNotifs = listOf<ListEntry>()
-
- private lateinit var listContainer: SimpleNotificationListContainer
-
- fun attach(listBuilder: ShadeListBuilder) {
- if (featureFlags.isNewNotifPipelineRenderingEnabled) {
- listBuilder.setOnRenderListListener { entries: List<ListEntry> ->
- this.onNotifTreeBuilt(entries)
- }
- }
- }
-
- fun setViewConsumer(consumer: SimpleNotificationListContainer) {
- listContainer = consumer
- }
-
- /**
- * Callback for when the tree is rebuilt
- */
- fun onNotifTreeBuilt(notifList: List<ListEntry>) {
- Assert.isMainThread()
-
- /*
- * The assumption here is that anything from the old NotificationViewHierarchyManager that
- * is responsible for filtering is done via the NotifFilter logic. This tree we get should
- * be *the stuff to display* +/- redacted stuff
- */
-
- detachRows(notifList)
- attachRows(notifList)
-
- currentNotifs = notifList
- }
-
- private fun detachRows(entries: List<ListEntry>) {
- // To properly detach rows, we are looking to remove any view in the consumer that is not
- // present in the incoming list.
- //
- // Every listItem was top-level, so it's entry's parent was ROOT_ENTRY, but now
- // there are two possibilities:
- //
- // 1. It is not present in the entry list
- // 1a. It has moved to be a child in the entry list - transfer it
- // 1b. It is gone completely - remove it
- // 2. It is present in the entry list - diff the children
- getListItems(listContainer)
- .filter {
- // Ignore things that are showing the blocking helper
- !it.isBlockingHelperShowing
- }
- .forEach { listItem ->
- val noLongerTopLevel = listItem.entry.parent != ROOT_ENTRY
- val becameChild = noLongerTopLevel && listItem.entry.parent != null
-
- val idx = entries.indexOf(listItem.entry)
-
- if (noLongerTopLevel) {
- // Summaries won't become children; remove the whole group
- if (listItem.isSummaryWithChildren) {
- listItem.removeAllChildren()
- }
-
- if (becameChild) {
- // Top-level element is becoming a child, don't generate an animation
- listContainer.setChildTransferInProgress(true)
- }
- listContainer.removeListItem(listItem)
- listContainer.setChildTransferInProgress(false)
- } else if (entries[idx] is GroupEntry) {
- // A top-level entry exists. If it's a group, diff the children
- val groupChildren = (entries[idx] as GroupEntry).children
- listItem.attachedChildren?.forEach { listChild ->
- if (!groupChildren.contains(listChild.entry)) {
- listItem.removeChildNotification(listChild)
-
- // TODO: the old code only calls this if the notif is gone from
- // NEM.getActiveNotificationUnfiltered(). Do we care?
- listContainer.notifyGroupChildRemoved(
- listChild.view, listChild.view.parent as ViewGroup)
- }
- }
- }
- }
- }
-
- /** Convenience method for getting a sequence of [NotificationListItem]s */
- private fun getListItems(container: SimpleNotificationListContainer):
- Sequence<NotificationListItem> {
- return (0 until container.getContainerChildCount()).asSequence()
- .map { container.getContainerChildAt(it) }
- .filterIsInstance<NotificationListItem>()
- }
-
- private fun attachRows(entries: List<ListEntry>) {
-
- var orderChanged = false
-
- // To attach rows we can use _this one weird trick_: if the intended view to add does not
- // have a parent, then simply add it (and its children).
- entries.forEach { entry ->
- // TODO: We should eventually map GroupEntry's themselves to views so that we don't
- // depend on representativeEntry here which may actually be null in the future
- val listItem = rowRegistry.requireView(entry.representativeEntry!!)
-
- if (listItem.view.parent == null) {
- listContainer.addListItem(listItem)
- stabilityManager.notifyViewAddition(listItem.view)
- }
-
- if (entry is GroupEntry) {
- for ((idx, childEntry) in entry.children.withIndex()) {
- val childListItem = rowRegistry.requireView(childEntry)
- // Child hasn't been added yet. add it!
- if (listItem.attachedChildren == null ||
- !listItem.attachedChildren.contains(childListItem)) {
- // TODO: old code here just Log.wtf()'d here. This might wreak havoc
- if (childListItem.view.parent != null) {
- throw IllegalStateException("trying to add a notification child that " +
- "already has a parent. class: " +
- "${childListItem.view.parent?.javaClass} " +
- "\n child: ${childListItem.view}"
- )
- }
-
- listItem.addChildNotification(childListItem, idx)
- stabilityManager.notifyViewAddition(childListItem.view)
- listContainer.notifyGroupChildAdded(childListItem.view)
- }
- }
-
- // finally after removing and adding has been performed we can apply the order
- orderChanged = orderChanged ||
- listItem.applyChildOrder(
- getChildListFromParent(entry),
- stabilityManager,
- null /*TODO: stability callback */
- )
- listItem.setUntruncatedChildCount(entry.untruncatedChildCount)
- }
- }
-
- if (orderChanged) {
- listContainer.generateChildOrderChangedEvent()
- }
- }
-
- private fun getChildListFromParent(parent: ListEntry): List<NotificationListItem> {
- if (parent is GroupEntry) {
- return parent.children.map { child -> rowRegistry.requireView(child) }
- .toList()
- }
-
- return emptyList()
- }
-
- fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<String>) {
- }
-}
-
-private const val TAG = "NotifViewDataSource" \ No newline at end of file
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 bd65ef06f3a9..387247eb6c5b 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
@@ -35,7 +35,6 @@ import static com.android.systemui.statusbar.notification.stack.NotificationSect
import static java.util.Objects.requireNonNull;
-import android.annotation.CurrentTimeMillisLong;
import android.app.Notification;
import android.app.Notification.MessagingStyle.Message;
import android.app.NotificationChannel;
@@ -96,7 +95,6 @@ public final class NotificationEntry extends ListEntry {
private final String mKey;
private StatusBarNotification mSbn;
private Ranking mRanking;
- private long mCreationTime;
/*
* Bookkeeping members
@@ -198,11 +196,10 @@ public final class NotificationEntry extends ListEntry {
boolean allowFgsDismissal,
long creationTime
) {
- super(requireNonNull(requireNonNull(sbn).getKey()));
+ super(requireNonNull(requireNonNull(sbn).getKey()), creationTime);
requireNonNull(ranking);
- mCreationTime = creationTime;
mKey = sbn.getKey();
setSbn(sbn);
setRanking(ranking);
@@ -255,21 +252,6 @@ public final class NotificationEntry extends ListEntry {
}
/**
- * A timestamp of SystemClock.uptimeMillis() of when this entry was first created, regardless
- * of any changes to the data presented. It is set once on creation and will never change, and
- * allows us to know exactly how long this notification has been alive for in our listener
- * service. It is entirely unrelated to the information inside of the notification.
- *
- * This is different to Notification#when because it persists throughout updates, whereas
- * system server treats every single call to notify() as a new notification and we handle
- * updates to NotificationEntry locally.
- */
- @CurrentTimeMillisLong
- public long getCreationTime() {
- return mCreationTime;
- }
-
- /**
* Should only be called by NotificationEntryManager and friends.
* TODO: Make this package-private
*/
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java
index a86ab41141a6..d45f89cb6fe5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java
@@ -47,6 +47,7 @@ import com.android.systemui.statusbar.notification.collection.listbuilder.plugga
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.listbuilder.pluggable.NotifSection;
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.Pluggable;
import com.android.systemui.statusbar.notification.collection.notifcollection.CollectionReadyForBuildListener;
import com.android.systemui.util.Assert;
import com.android.systemui.util.time.SystemClock;
@@ -321,6 +322,7 @@ public class ShadeListBuilder implements Dumpable {
mPipelineState.incrementTo(STATE_FINALIZING);
logChanges();
freeEmptyGroups();
+ cleanupPluggables();
// Step 8: Dispatch the new list, first to any listeners and then to the view layer
dispatchOnBeforeRenderList(mReadOnlyNotifList);
@@ -421,7 +423,7 @@ public class ShadeListBuilder implements Dumpable {
GroupEntry group = mGroups.get(topLevelKey);
if (group == null) {
- group = new GroupEntry(topLevelKey);
+ group = new GroupEntry(topLevelKey, mSystemClock.uptimeMillis());
group.mFirstAddedIteration = mIterationCount;
mGroups.put(topLevelKey, group);
}
@@ -673,6 +675,20 @@ public class ShadeListBuilder implements Dumpable {
}
}
+ private void cleanupPluggables() {
+ callOnCleanup(mNotifPreGroupFilters);
+ callOnCleanup(mNotifPromoters);
+ callOnCleanup(mNotifFinalizeFilters);
+ callOnCleanup(mNotifComparators);
+ callOnCleanup(mNotifSections);
+ }
+
+ private void callOnCleanup(List<? extends Pluggable<?>> pluggables) {
+ for (int i = 0; i < pluggables.size(); i++) {
+ pluggables.get(i).onCleanup();
+ }
+ }
+
private final Comparator<ListEntry> mTopLevelComparator = (o1, o2) -> {
int cmp = Integer.compare(o1.getSection(), o2.getSection());
@@ -849,7 +865,7 @@ public class ShadeListBuilder implements Dumpable {
}
};
- private static final String TAG = "NotifListBuilderImpl";
+ private static final String TAG = "ShadeListBuilder";
private static final int MIN_CHILDREN_FOR_GROUP = 2;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/SimpleNotificationListContainer.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/SimpleNotificationListContainer.kt
deleted file mode 100644
index 2dbe555af519..000000000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/SimpleNotificationListContainer.kt
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.statusbar.notification.collection
-
-import android.view.View
-import android.view.ViewGroup
-import com.android.systemui.statusbar.notification.stack.NotificationListItem
-
-/**
- * Minimal interface of what [NotifViewManager] needs from [NotificationListContainer]
- */
-interface SimpleNotificationListContainer {
- /** Called to signify that a top-level element is becoming a child in the shade */
- fun setChildTransferInProgress(b: Boolean)
- /** Used to generate a list of [NotificationListItem] */
- fun getContainerChildAt(i: Int): View
- /** Similar to above */
- fun getContainerChildCount(): Int
- /** Remove a [NotificationListItem] from the container */
- fun removeListItem(li: NotificationListItem)
- /** Add a [NotificationListItem] to the container */
- fun addListItem(li: NotificationListItem)
- /** Allows [NotifViewManager] to notify the container about a group child removal */
- fun notifyGroupChildRemoved(row: View, parent: ViewGroup)
- /** Allows [NotifViewManager] to notify the container about a group child addition */
- fun notifyGroupChildAdded(row: View)
- /** [NotifViewManager] calls this when the order of the children changes */
- fun generateChildOrderChangedEvent()
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/BubbleCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/BubbleCoordinator.java
index 92426e54ec91..08462c183bd9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/BubbleCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/BubbleCoordinator.java
@@ -16,10 +16,6 @@
package com.android.systemui.statusbar.notification.collection.coordinator;
-import static android.service.notification.NotificationStats.DISMISSAL_OTHER;
-import static android.service.notification.NotificationStats.DISMISS_SENTIMENT_NEUTRAL;
-
-import com.android.internal.statusbar.NotificationVisibility;
import com.android.systemui.bubbles.BubbleController;
import com.android.systemui.statusbar.notification.collection.NotifCollection;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
@@ -27,7 +23,6 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
import com.android.systemui.statusbar.notification.collection.notifcollection.DismissedByUserStats;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifDismissInterceptor;
-import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import java.util.HashSet;
import java.util.Set;
@@ -101,7 +96,6 @@ public class BubbleCoordinator implements Coordinator {
@Override
public boolean shouldInterceptDismissal(NotificationEntry entry) {
- // TODO: b/149041810 add support for intercepting app-cancelled bubble notifications
// for experimental bubbles
if (mBubbleController.handleDismissalInterception(entry)) {
mInterceptedDismissalEntries.add(entry.getKey());
@@ -121,17 +115,21 @@ public class BubbleCoordinator implements Coordinator {
private final BubbleController.NotifCallback mNotifCallback =
new BubbleController.NotifCallback() {
@Override
- public void removeNotification(NotificationEntry entry, int reason) {
+ public void removeNotification(
+ NotificationEntry entry,
+ DismissedByUserStats dismissedByUserStats,
+ int reason
+ ) {
if (isInterceptingDismissal(entry)) {
mInterceptedDismissalEntries.remove(entry.getKey());
mOnEndDismissInterception.onEndDismissInterception(mDismissInterceptor, entry,
- createDismissedByUserStats(entry));
+ dismissedByUserStats);
} else if (mNotifPipeline.getAllNotifs().contains(entry)) {
// Bubbles are hiding the notifications from the shade, but the bubble was
// deleted; therefore, the notification should be cancelled as if it were a user
// dismissal (this won't re-enter handleInterceptDimissal because Bubbles
// will have already marked it as no longer a bubble)
- mNotifCollection.dismissNotification(entry, createDismissedByUserStats(entry));
+ mNotifCollection.dismissNotification(entry, dismissedByUserStats);
}
}
@@ -149,16 +147,4 @@ public class BubbleCoordinator implements Coordinator {
private boolean isInterceptingDismissal(NotificationEntry entry) {
return mInterceptedDismissalEntries.contains(entry.getKey());
}
-
- private DismissedByUserStats createDismissedByUserStats(NotificationEntry entry) {
- return new DismissedByUserStats(
- DISMISSAL_OTHER,
- DISMISS_SENTIMENT_NEUTRAL,
- NotificationVisibility.obtain(entry.getKey(),
- entry.getRanking().getRank(),
- mNotifPipeline.getShadeListCount(),
- true, // was visible as a bubble
- NotificationLogger.getNotificationLocation(entry))
- );
- }
}
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 4159d43e34ec..ee2bb6b1d190 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
@@ -18,6 +18,8 @@ package com.android.systemui.statusbar.notification.collection.coordinator;
import static com.android.systemui.statusbar.notification.stack.NotificationChildrenContainer.NUMBER_OF_CHILDREN_WHEN_CHILDREN_EXPANDED;
+import static java.util.Objects.requireNonNull;
+
import android.annotation.IntDef;
import android.os.RemoteException;
import android.service.notification.StatusBarNotification;
@@ -28,22 +30,21 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.statusbar.IStatusBarService;
import com.android.systemui.statusbar.notification.collection.GroupEntry;
import com.android.systemui.statusbar.notification.collection.ListEntry;
-import com.android.systemui.statusbar.notification.collection.NotifInflaterImpl;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
-import com.android.systemui.statusbar.notification.collection.NotifViewBarn;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.ShadeListBuilder;
import com.android.systemui.statusbar.notification.collection.inflation.NotifInflater;
import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeFinalizeFilterListener;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
+import com.android.systemui.statusbar.notification.collection.render.NotifViewBarn;
import com.android.systemui.statusbar.notification.row.NotifInflationErrorManager;
+import com.android.systemui.statusbar.notification.row.NotifInflationErrorManager.NotifInflationErrorListener;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.List;
import java.util.Map;
-import java.util.Objects;
import java.util.Set;
import javax.inject.Inject;
@@ -81,35 +82,48 @@ public class PreparationCoordinator implements Coordinator {
*/
private final int mChildBindCutoff;
+ /** How long we can delay a group while waiting for all children to inflate */
+ private final long mMaxGroupInflationDelay;
+
@Inject
public PreparationCoordinator(
PreparationCoordinatorLogger logger,
- NotifInflaterImpl notifInflater,
+ NotifInflater notifInflater,
NotifInflationErrorManager errorManager,
NotifViewBarn viewBarn,
IStatusBarService service) {
- this(logger, notifInflater, errorManager, viewBarn, service, CHILD_BIND_CUTOFF);
+ this(
+ logger,
+ notifInflater,
+ errorManager,
+ viewBarn,
+ service,
+ CHILD_BIND_CUTOFF,
+ MAX_GROUP_INFLATION_DELAY);
}
@VisibleForTesting
PreparationCoordinator(
PreparationCoordinatorLogger logger,
- NotifInflaterImpl notifInflater,
+ NotifInflater notifInflater,
NotifInflationErrorManager errorManager,
NotifViewBarn viewBarn,
IStatusBarService service,
- int childBindCutoff) {
+ int childBindCutoff,
+ long maxGroupInflationDelay) {
mLogger = logger;
mNotifInflater = notifInflater;
mNotifErrorManager = errorManager;
- mNotifErrorManager.addInflationErrorListener(mInflationErrorListener);
mViewBarn = viewBarn;
mStatusBarService = service;
mChildBindCutoff = childBindCutoff;
+ mMaxGroupInflationDelay = maxGroupInflationDelay;
}
@Override
public void attach(NotifPipeline pipeline) {
+ mNotifErrorManager.addInflationErrorListener(mInflationErrorListener);
+
pipeline.addCollectionListener(mNotifCollectionListener);
// Inflate after grouping/sorting since that affects what views to inflate.
pipeline.addOnBeforeFinalizeFilterListener(mOnBeforeFinalizeFilterListener);
@@ -127,7 +141,6 @@ public class PreparationCoordinator implements Coordinator {
@Override
public void onEntryUpdated(NotificationEntry entry) {
abortInflation(entry, "entryUpdated");
- mInflatingNotifs.remove(entry);
@InflationState int state = getInflationState(entry);
if (state == STATE_INFLATED) {
mInflationStates.put(entry, STATE_INFLATED_INVALID);
@@ -145,7 +158,6 @@ public class PreparationCoordinator implements Coordinator {
@Override
public void onEntryCleanUp(NotificationEntry entry) {
mInflationStates.remove(entry);
- mInflatingNotifs.remove(entry);
mViewBarn.removeViewForEntry(entry);
}
};
@@ -165,17 +177,32 @@ public class PreparationCoordinator implements Coordinator {
};
private final NotifFilter mNotifInflatingFilter = new NotifFilter(TAG + "Inflating") {
+ private final Map<GroupEntry, Boolean> mIsDelayedGroupCache = new ArrayMap<>();
+
/**
- * Filters out notifications that aren't inflated
+ * Filters out notifications that either (a) aren't inflated or (b) are part of a group
+ * that isn't completely inflated yet
*/
@Override
public boolean shouldFilterOut(NotificationEntry entry, long now) {
- return !isInflated(entry);
+ final GroupEntry parent = requireNonNull(entry.getParent());
+ Boolean isMemberOfDelayedGroup = mIsDelayedGroupCache.get(parent);
+ if (isMemberOfDelayedGroup == null) {
+ isMemberOfDelayedGroup = shouldWaitForGroupToInflate(parent, now);
+ mIsDelayedGroupCache.put(parent, isMemberOfDelayedGroup);
+ }
+
+ return !isInflated(entry) || isMemberOfDelayedGroup;
+ }
+
+ @Override
+ public void onCleanup() {
+ mIsDelayedGroupCache.clear();
}
};
- private final NotifInflationErrorManager.NotifInflationErrorListener mInflationErrorListener =
- new NotifInflationErrorManager.NotifInflationErrorListener() {
+ private final NotifInflationErrorListener mInflationErrorListener =
+ new NotifInflationErrorListener() {
@Override
public void onNotifInflationError(NotificationEntry entry, Exception e) {
mViewBarn.removeViewForEntry(entry);
@@ -191,8 +218,9 @@ public class PreparationCoordinator implements Coordinator {
sbn.getUid(),
sbn.getInitialPid(),
e.getMessage(),
- sbn.getUserId());
+ sbn.getUser().getIdentifier());
} catch (RemoteException ex) {
+ // System server is dead, nothing to do about that
}
mNotifInflationErrorFilter.invalidateList();
}
@@ -297,11 +325,36 @@ public class PreparationCoordinator implements Coordinator {
private @InflationState int getInflationState(NotificationEntry entry) {
Integer stateObj = mInflationStates.get(entry);
- Objects.requireNonNull(stateObj,
+ requireNonNull(stateObj,
"Asking state of a notification preparation coordinator doesn't know about");
return stateObj;
}
+ private boolean shouldWaitForGroupToInflate(GroupEntry group, long now) {
+ if (group == GroupEntry.ROOT_ENTRY || group.hasBeenAttachedBefore()) {
+ return false;
+ }
+ if (isBeyondGroupInitializationWindow(group, now)) {
+ mLogger.logGroupInflationTookTooLong(group.getKey());
+ return false;
+ }
+ if (mInflatingNotifs.contains(group.getSummary())) {
+ mLogger.logDelayingGroupRelease(group.getKey(), group.getSummary().getKey());
+ return true;
+ }
+ for (NotificationEntry child : group.getChildren()) {
+ if (mInflatingNotifs.contains(child) && !child.hasBeenAttachedBefore()) {
+ mLogger.logDelayingGroupRelease(group.getKey(), child.getKey());
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private boolean isBeyondGroupInitializationWindow(GroupEntry entry, long now) {
+ return now - entry.getCreationTime() > mMaxGroupInflationDelay;
+ }
+
@Retention(RetentionPolicy.SOURCE)
@IntDef(prefix = {"STATE_"},
value = {STATE_UNINFLATED, STATE_INFLATED_INVALID, STATE_INFLATED, STATE_ERROR})
@@ -328,6 +381,8 @@ public class PreparationCoordinator implements Coordinator {
*/
private static final int EXTRA_VIEW_BUFFER_COUNT = 1;
+ private static final long MAX_GROUP_INFLATION_DELAY = 500;
+
private static final int CHILD_BIND_CUTOFF =
NUMBER_OF_CHILDREN_WHEN_CHILDREN_EXPANDED + EXTRA_VIEW_BUFFER_COUNT;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorLogger.kt
index 75e7bc9b79a2..dd4794f0a452 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorLogger.kt
@@ -40,6 +40,23 @@ class PreparationCoordinatorLogger @Inject constructor(
"NOTIF INFLATION ABORTED $str1 reason=$str2"
})
}
+
+ fun logGroupInflationTookTooLong(groupKey: String) {
+ buffer.log(TAG, LogLevel.WARNING, {
+ str1 = groupKey
+ }, {
+ "Group inflation took too long far $str1, releasing children early"
+ })
+ }
+
+ fun logDelayingGroupRelease(groupKey: String, childKey: String) {
+ buffer.log(TAG, LogLevel.DEBUG, {
+ str1 = groupKey
+ str2 = childKey
+ }, {
+ "Delaying release of group $str1 because child $str2 is still inflating"
+ })
+ }
}
private const val TAG = "PreparationCoordinator" \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinder.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinder.java
index 710b137d2795..1215ade2abb1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinder.java
@@ -38,7 +38,6 @@ public interface NotificationRowBinder {
*/
void inflateViews(
NotificationEntry entry,
- Runnable onDismissRunnable,
NotificationRowContentBinder.InflationCallback callback)
throws InflationException;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java
index 85a3bc91dc7e..8849824380d3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java
@@ -32,7 +32,6 @@ import com.android.systemui.statusbar.notification.InflationException;
import com.android.systemui.statusbar.notification.NotificationClicker;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.icon.IconManager;
-import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRowController;
import com.android.systemui.statusbar.notification.row.NotifBindPipeline;
@@ -59,7 +58,6 @@ public class NotificationRowBinderImpl implements NotificationRowBinder {
private final NotificationLockscreenUserManager mNotificationLockscreenUserManager;
private final NotifBindPipeline mNotifBindPipeline;
private final RowContentBindStage mRowContentBindStage;
- private final NotificationInterruptStateProvider mNotificationInterruptStateProvider;
private final Provider<RowInflaterTask> mRowInflaterTaskProvider;
private final ExpandableNotificationRowComponent.Builder
mExpandableNotificationRowComponentBuilder;
@@ -79,7 +77,6 @@ public class NotificationRowBinderImpl implements NotificationRowBinder {
NotificationLockscreenUserManager notificationLockscreenUserManager,
NotifBindPipeline notifBindPipeline,
RowContentBindStage rowContentBindStage,
- NotificationInterruptStateProvider notificationInterruptionStateProvider,
Provider<RowInflaterTask> rowInflaterTaskProvider,
ExpandableNotificationRowComponent.Builder expandableNotificationRowComponentBuilder,
IconManager iconManager,
@@ -90,7 +87,6 @@ public class NotificationRowBinderImpl implements NotificationRowBinder {
mMessagingUtil = notificationMessagingUtil;
mNotificationRemoteInputManager = notificationRemoteInputManager;
mNotificationLockscreenUserManager = notificationLockscreenUserManager;
- mNotificationInterruptStateProvider = notificationInterruptionStateProvider;
mRowInflaterTaskProvider = rowInflaterTaskProvider;
mExpandableNotificationRowComponentBuilder = expandableNotificationRowComponentBuilder;
mIconManager = iconManager;
@@ -120,7 +116,6 @@ public class NotificationRowBinderImpl implements NotificationRowBinder {
@Override
public void inflateViews(
NotificationEntry entry,
- Runnable onDismissRunnable,
NotificationRowContentBinder.InflationCallback callback)
throws InflationException {
ViewGroup parent = mListContainer.getViewParentForNotification(entry);
@@ -131,7 +126,6 @@ public class NotificationRowBinderImpl implements NotificationRowBinder {
row.reset();
updateRow(entry, row);
inflateContentViews(entry, row, callback);
- entry.getRowController().setOnDismissRunnable(onDismissRunnable);
} else {
mIconManager.createIcons(entry);
mRowInflaterTaskProvider.get().inflate(mContext, parent, entry,
@@ -141,7 +135,6 @@ public class NotificationRowBinderImpl implements NotificationRowBinder {
mExpandableNotificationRowComponentBuilder
.expandableNotificationRow(row)
.notificationEntry(entry)
- .onDismissRunnable(onDismissRunnable)
.onExpandClickListener(mPresenter)
.build();
ExpandableNotificationRowController rowController =
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/OnDismissCallbackImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/OnDismissCallbackImpl.java
new file mode 100644
index 000000000000..36adf9b87674
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/OnDismissCallbackImpl.java
@@ -0,0 +1,83 @@
+/*
+ * 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.inflation;
+
+import static android.service.notification.NotificationStats.DISMISS_SENTIMENT_NEUTRAL;
+
+import android.service.notification.NotificationListenerService;
+import android.service.notification.NotificationStats;
+
+import com.android.internal.statusbar.NotificationVisibility;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.notification.collection.NotifCollection;
+import com.android.systemui.statusbar.notification.collection.NotifPipeline;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.notifcollection.DismissedByUserStats;
+import com.android.systemui.statusbar.notification.logging.NotificationLogger;
+import com.android.systemui.statusbar.notification.row.OnDismissCallback;
+import com.android.systemui.statusbar.policy.HeadsUpManager;
+
+/**
+ * Callback used when a user:
+ * 1. Manually dismisses a notification {@see ExpandableNotificationRow}.
+ * 2. Clicks on a notification with flag {@link android.app.Notification#FLAG_AUTO_CANCEL}.
+ * {@see StatusBarNotificationActivityStarter}
+ */
+public class OnDismissCallbackImpl implements OnDismissCallback {
+ private final NotifPipeline mNotifPipeline;
+ private final NotifCollection mNotifCollection;
+ private final HeadsUpManager mHeadsUpManager;
+ private final StatusBarStateController mStatusBarStateController;
+
+ public OnDismissCallbackImpl(
+ NotifPipeline notifPipeline,
+ NotifCollection notifCollection,
+ HeadsUpManager headsUpManager,
+ StatusBarStateController statusBarStateController
+ ) {
+ mNotifPipeline = notifPipeline;
+ mNotifCollection = notifCollection;
+ mHeadsUpManager = headsUpManager;
+ mStatusBarStateController = statusBarStateController;
+ }
+
+ @Override
+ public void onDismiss(
+ NotificationEntry entry,
+ @NotificationListenerService.NotificationCancelReason int cancellationReason
+ ) {
+ int dismissalSurface = NotificationStats.DISMISSAL_SHADE;
+ if (mHeadsUpManager.isAlerting(entry.getKey())) {
+ dismissalSurface = NotificationStats.DISMISSAL_PEEK;
+ } else if (mStatusBarStateController.isDozing()) {
+ dismissalSurface = NotificationStats.DISMISSAL_AOD;
+ }
+
+ mNotifCollection.dismissNotification(
+ entry,
+ new DismissedByUserStats(
+ dismissalSurface,
+ DISMISS_SENTIMENT_NEUTRAL,
+ NotificationVisibility.obtain(
+ entry.getKey(),
+ entry.getRanking().getRank(),
+ mNotifPipeline.getShadeListCount(),
+ true,
+ NotificationLogger.getNotificationLocation(entry)))
+ );
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/init/NotifPipelineInitializer.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/init/NotifPipelineInitializer.java
index f150257df252..9782c3ef55fe 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/init/NotifPipelineInitializer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/init/NotifPipelineInitializer.java
@@ -25,11 +25,12 @@ import com.android.systemui.statusbar.NotificationListener;
import com.android.systemui.statusbar.notification.collection.NotifCollection;
import com.android.systemui.statusbar.notification.collection.NotifInflaterImpl;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
-import com.android.systemui.statusbar.notification.collection.NotifViewManager;
import com.android.systemui.statusbar.notification.collection.ShadeListBuilder;
import com.android.systemui.statusbar.notification.collection.coalescer.GroupCoalescer;
import com.android.systemui.statusbar.notification.collection.coordinator.NotifCoordinators;
import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl;
+import com.android.systemui.statusbar.notification.collection.render.NotifViewManager;
+import com.android.systemui.statusbar.notification.collection.render.NotifViewManagerBuilder;
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
import java.io.FileDescriptor;
@@ -50,9 +51,9 @@ public class NotifPipelineInitializer implements Dumpable {
private final NotifCoordinators mNotifPluggableCoordinators;
private final NotifInflaterImpl mNotifInflater;
private final DumpManager mDumpManager;
+ private final NotifViewManagerBuilder mNotifViewManagerBuilder;
private final FeatureFlags mFeatureFlags;
- private final NotifViewManager mNotifViewManager;
@Inject
public NotifPipelineInitializer(
@@ -63,8 +64,8 @@ public class NotifPipelineInitializer implements Dumpable {
NotifCoordinators notifCoordinators,
NotifInflaterImpl notifInflater,
DumpManager dumpManager,
- FeatureFlags featureFlags,
- NotifViewManager notifViewManager) {
+ NotifViewManagerBuilder notifViewManagerBuilder,
+ FeatureFlags featureFlags) {
mPipelineWrapper = pipelineWrapper;
mGroupCoalescer = groupCoalescer;
mNotifCollection = notifCollection;
@@ -73,7 +74,7 @@ public class NotifPipelineInitializer implements Dumpable {
mDumpManager = dumpManager;
mNotifInflater = notifInflater;
mFeatureFlags = featureFlags;
- mNotifViewManager = notifViewManager;
+ mNotifViewManagerBuilder = notifViewManagerBuilder;
}
/** Hooks the new pipeline up to NotificationManager */
@@ -93,8 +94,10 @@ public class NotifPipelineInitializer implements Dumpable {
mNotifPluggableCoordinators.attach(mPipelineWrapper);
// Wire up pipeline
- mNotifViewManager.setViewConsumer(listContainer);
- mNotifViewManager.attach(mListBuilder);
+ if (mFeatureFlags.isNewNotifPipelineRenderingEnabled()) {
+ NotifViewManager notifViewManager = mNotifViewManagerBuilder.build(listContainer);
+ notifViewManager.attach(mListBuilder);
+ }
mListBuilder.attach(mNotifCollection);
mNotifCollection.attach(mGroupCoalescer);
mGroupCoalescer.attach(notificationService);
@@ -104,7 +107,6 @@ public class NotifPipelineInitializer implements Dumpable {
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- mNotifViewManager.dump(fd, pw, args);
mNotifPluggableCoordinators.dump(fd, pw, args);
mGroupCoalescer.dump(fd, pw, args);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/OnDismissCallbackImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/OnDismissCallbackImpl.java
new file mode 100644
index 000000000000..94ffa8f8c5ed
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/OnDismissCallbackImpl.java
@@ -0,0 +1,81 @@
+/*
+ * 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.legacy;
+
+import static android.service.notification.NotificationStats.DISMISS_SENTIMENT_NEUTRAL;
+
+import android.service.notification.NotificationListenerService;
+import android.service.notification.NotificationStats;
+
+import com.android.internal.statusbar.NotificationVisibility;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.notifcollection.DismissedByUserStats;
+import com.android.systemui.statusbar.notification.logging.NotificationLogger;
+import com.android.systemui.statusbar.notification.row.OnDismissCallback;
+import com.android.systemui.statusbar.policy.HeadsUpManager;
+
+/**
+ * Callback used when a user:
+ * 1. Manually dismisses a notification {@see ExpandableNotificationRow}.
+ * 2. Clicks on a notification with flag {@link android.app.Notification#FLAG_AUTO_CANCEL}.
+ * {@see StatusBarNotificationActivityStarter}
+ */
+public class OnDismissCallbackImpl implements OnDismissCallback {
+ private final NotificationEntryManager mNotificationEntryManager;
+ private final HeadsUpManager mHeadsUpManager;
+ private final StatusBarStateController mStatusBarStateController;
+
+ public OnDismissCallbackImpl(
+ NotificationEntryManager notificationEntryManager,
+ HeadsUpManager headsUpManager,
+ StatusBarStateController statusBarStateController
+ ) {
+ mNotificationEntryManager = notificationEntryManager;
+ mHeadsUpManager = headsUpManager;
+ mStatusBarStateController = statusBarStateController;
+ }
+
+ @Override
+ public void onDismiss(
+ NotificationEntry entry,
+ @NotificationListenerService.NotificationCancelReason int cancellationReason
+ ) {
+ int dismissalSurface = NotificationStats.DISMISSAL_SHADE;
+ if (mHeadsUpManager.isAlerting(entry.getKey())) {
+ dismissalSurface = NotificationStats.DISMISSAL_PEEK;
+ } else if (mStatusBarStateController.isDozing()) {
+ dismissalSurface = NotificationStats.DISMISSAL_AOD;
+ }
+
+ mNotificationEntryManager.performRemoveNotification(
+ entry.getSbn(),
+ new DismissedByUserStats(
+ dismissalSurface,
+ DISMISS_SENTIMENT_NEUTRAL,
+ NotificationVisibility.obtain(
+ entry.getKey(),
+ entry.getRanking().getRank(),
+ mNotificationEntryManager.getActiveNotificationsCount(),
+ true,
+ NotificationLogger.getNotificationLocation(entry))),
+ cancellationReason
+ );
+ }
+}
+
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/ShadeListBuilderLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/ShadeListBuilderLogger.kt
index aa107824729e..67f8bfeaf141 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/ShadeListBuilderLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/ShadeListBuilderLogger.kt
@@ -125,13 +125,18 @@ class ShadeListBuilderLogger @Inject constructor(
str2 = prevParent?.key
str3 = newParent?.key
}, {
- if (str2 == null && str3 != null) {
- "(Build $int1) ATTACHED {$str1}"
+
+ val action = if (str2 == null && str3 != null) {
+ "ATTACHED"
} else if (str2 != null && str3 == null) {
- "(Build $int1) DETACHED {$str1}"
+ "DETACHED"
+ } else if (str2 == null && str3 == null) {
+ "MODIFIED (DETACHED)"
} else {
- "(Build $int1) MODIFIED {$str1}"
+ "MODIFIED (ATTACHED)"
}
+
+ "(Build $int1) $action {$str1}"
})
}
@@ -146,7 +151,7 @@ class ShadeListBuilderLogger @Inject constructor(
} else if (str1 != null && str2 == null) {
"(Build $int1) Parent was {$str1}"
} else {
- "(Build $int1) Reparent: {$str2} -> {$str3}"
+ "(Build $int1) Reparent: {$str1} -> {$str2}"
}
})
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/Pluggable.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/Pluggable.java
index 4270408d0c66..8e4fb7523767 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/Pluggable.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/Pluggable.java
@@ -55,11 +55,17 @@ public abstract class Pluggable<This> {
}
/** Set a listener to be notified when a pluggable is invalidated. */
- public void setInvalidationListener(PluggableListener<This> listener) {
+ public final void setInvalidationListener(PluggableListener<This> listener) {
mListener = listener;
}
/**
+ * Called on the pluggable once at the end of every pipeline run. Override this method to
+ * perform any necessary cleanup.
+ */
+ public void onCleanup() { }
+
+ /**
* Listener interface for when pluggables are invalidated.
*
* @param <T> The type of pluggable that is being listened to.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifViewBarn.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifViewBarn.kt
index e7948cd1216e..54000950e3ef 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifViewBarn.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifViewBarn.kt
@@ -14,26 +14,22 @@
* limitations under the License.
*/
-package com.android.systemui.statusbar.notification.collection
+package com.android.systemui.statusbar.notification.collection.render
import android.view.textclassifier.Log
-import com.android.systemui.statusbar.notification.stack.NotificationListItem
-import java.lang.IllegalStateException
-
+import com.android.systemui.statusbar.notification.collection.ListEntry
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
import javax.inject.Inject
import javax.inject.Singleton
/**
- * The ViewBarn is just a map from [ListEntry] to an instance of [NotificationListItem] which is
- * usually just an [ExpandableNotificationRow]
+ * The ViewBarn is just a map from [ListEntry] to an instance of an [ExpandableNotificationRow].
*/
@Singleton
class NotifViewBarn @Inject constructor() {
- private val DEBUG = false
-
- private val rowMap = mutableMapOf<String, NotificationListItem>()
+ private val rowMap = mutableMapOf<String, ExpandableNotificationRow>()
- fun requireView(forEntry: ListEntry): NotificationListItem {
+ fun requireView(forEntry: ListEntry): ExpandableNotificationRow {
if (DEBUG) {
Log.d(TAG, "requireView: $forEntry.key")
}
@@ -45,7 +41,7 @@ class NotifViewBarn @Inject constructor() {
return li
}
- fun registerViewForEntry(entry: ListEntry, view: NotificationListItem) {
+ fun registerViewForEntry(entry: ListEntry, view: ExpandableNotificationRow) {
if (DEBUG) {
Log.d(TAG, "registerViewForEntry: $entry.key")
}
@@ -60,4 +56,6 @@ class NotifViewBarn @Inject constructor() {
}
}
-private const val TAG = "NotifViewBarn" \ No newline at end of file
+private const val TAG = "NotifViewBarn"
+
+private const val DEBUG = false \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifViewManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifViewManager.kt
new file mode 100644
index 000000000000..f2e2c39ab612
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifViewManager.kt
@@ -0,0 +1,240 @@
+/*
+ * 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.render
+
+import android.annotation.MainThread
+import android.view.View
+import com.android.systemui.statusbar.notification.collection.GroupEntry
+import com.android.systemui.statusbar.notification.collection.GroupEntry.ROOT_ENTRY
+import com.android.systemui.statusbar.notification.collection.ListEntry
+import com.android.systemui.statusbar.notification.collection.NotificationEntry
+import com.android.systemui.statusbar.notification.collection.ShadeListBuilder
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
+import com.android.systemui.statusbar.notification.stack.NotificationListContainer
+import javax.inject.Inject
+
+/**
+ * A consumer of a Notification tree built by [ShadeListBuilder] which will update the notification
+ * presenter with the minimum operations required to make the old tree match the new one
+ */
+@MainThread
+class NotifViewManager constructor(
+ private val listContainer: NotificationListContainer,
+ private val viewBarn: NotifViewBarn,
+ private val logger: NotifViewManagerLogger
+) {
+ private val rootNode = RootWrapper(listContainer)
+ private val rows = mutableMapOf<ListEntry, RowNode>()
+
+ fun attach(listBuilder: ShadeListBuilder) {
+ listBuilder.setOnRenderListListener(::onNewNotifTree)
+ }
+
+ private fun onNewNotifTree(tree: List<ListEntry>) {
+ // Step 1: Detach all views whose parents have changed
+ detachRowsWithModifiedParents()
+
+ // Step 2: Attach all new views and reattach all views whose parents changed.
+ // Also reorder existing children to match the spec we've received
+ val orderChanged = addAndReorderChildren(rootNode, tree)
+ if (orderChanged) {
+ listContainer.generateChildOrderChangedEvent()
+ }
+ }
+
+ private fun detachRowsWithModifiedParents() {
+ val toRemove = mutableListOf<ListEntry>()
+ for (row in rows.values) {
+ val oldParentEntry = row.nodeParent?.entry
+ val newParentEntry = row.entry.parent
+
+ if (newParentEntry != oldParentEntry) {
+ // If the parent is null, then we should remove the child completely. If not, then
+ // the parent merely changed: we'll detach it for now and then attach it to the
+ // new parent in step 2.
+ val isTransfer = newParentEntry != null
+ if (!isTransfer) {
+ toRemove.add(row.entry)
+ }
+
+ if (!isTransfer && !isAttachedToRootEntry(oldParentEntry)) {
+ // If our view parent has also been removed (i.e. is no longer attached to the
+ // root entry) then we skip removing the child here
+ logger.logSkippingDetach(row.entry.key, row.nodeParent?.entry?.key)
+ } else {
+ logger.logDetachingChild(
+ row.entry.key,
+ isTransfer,
+ oldParentEntry?.key,
+ newParentEntry?.key)
+ row.nodeParent?.removeChild(row, isTransfer)
+ row.nodeParent = null
+ }
+ }
+ }
+ rows.keys.removeAll(toRemove)
+ }
+
+ private fun addAndReorderChildren(parent: ParentNode, childEntries: List<ListEntry>): Boolean {
+ var orderChanged = false
+ for ((index, entry) in childEntries.withIndex()) {
+ val row = getRowNode(entry)
+ val currView = parent.getChildViewAt(index)
+ if (currView != row.view) {
+ when (row.nodeParent) {
+ null -> {
+ logger.logAttachingChild(row.entry.key, parent.entry.key)
+ parent.addChildAt(row, index)
+ row.nodeParent = parent
+ }
+ parent -> {
+ logger.logMovingChild(row.entry.key, parent.entry.key, index)
+ parent.moveChild(row, index)
+ orderChanged = true
+ }
+ else -> {
+ throw IllegalStateException("Child ${row.entry.key} should have parent " +
+ "${parent.entry.key} but is actually " +
+ "${row.nodeParent?.entry?.key}")
+ }
+ }
+ }
+ if (row is GroupWrapper) {
+ val childOrderChanged = addAndReorderChildren(row, row.entry.children)
+ orderChanged = orderChanged || childOrderChanged
+ }
+ }
+ // TODO: setUntruncatedChildCount
+
+ return orderChanged
+ }
+
+ private fun getRowNode(entry: ListEntry): RowNode {
+ return rows.getOrPut(entry) {
+ when (entry) {
+ is NotificationEntry -> RowWrapper(entry, viewBarn.requireView(entry))
+ is GroupEntry ->
+ GroupWrapper(
+ entry,
+ viewBarn.requireView(checkNotNull(entry.summary)),
+ listContainer)
+ else -> throw RuntimeException(
+ "Unexpected entry type for ${entry.key}: ${entry.javaClass}")
+ }
+ }
+ }
+}
+
+class NotifViewManagerBuilder @Inject constructor(
+ private val viewBarn: NotifViewBarn,
+ private val logger: NotifViewManagerLogger
+) {
+ fun build(listContainer: NotificationListContainer): NotifViewManager {
+ return NotifViewManager(listContainer, viewBarn, logger)
+ }
+}
+
+private fun isAttachedToRootEntry(entry: ListEntry?): Boolean {
+ return when (entry) {
+ null -> false
+ ROOT_ENTRY -> true
+ else -> isAttachedToRootEntry(entry.parent)
+ }
+}
+
+private interface Node {
+ val entry: ListEntry
+ val nodeParent: ParentNode?
+}
+
+private interface ParentNode : Node {
+ fun getChildViewAt(index: Int): View?
+ fun addChildAt(child: RowNode, index: Int)
+ fun moveChild(child: RowNode, index: Int)
+ fun removeChild(child: RowNode, isTransfer: Boolean)
+}
+
+private interface RowNode : Node {
+ val view: ExpandableNotificationRow
+ override var nodeParent: ParentNode?
+}
+
+private class RootWrapper(
+ private val listContainer: NotificationListContainer
+) : ParentNode {
+ override val entry: ListEntry = ROOT_ENTRY
+ override val nodeParent: ParentNode? = null
+
+ override fun getChildViewAt(index: Int): View? {
+ return listContainer.getContainerChildAt(index)
+ }
+
+ override fun addChildAt(child: RowNode, index: Int) {
+ listContainer.addContainerViewAt(child.view, index)
+ }
+
+ override fun moveChild(child: RowNode, index: Int) {
+ listContainer.changeViewPosition(child.view, index)
+ }
+
+ override fun removeChild(child: RowNode, isTransfer: Boolean) {
+ if (isTransfer) {
+ listContainer.setChildTransferInProgress(true)
+ }
+ listContainer.removeContainerView(child.view)
+ if (isTransfer) {
+ listContainer.setChildTransferInProgress(false)
+ }
+ }
+}
+
+private class GroupWrapper(
+ override val entry: GroupEntry,
+ override val view: ExpandableNotificationRow,
+ val listContainer: NotificationListContainer
+) : RowNode, ParentNode {
+
+ override var nodeParent: ParentNode? = null
+
+ override fun getChildViewAt(index: Int): View? {
+ return view.getChildNotificationAt(index)
+ }
+
+ override fun addChildAt(child: RowNode, index: Int) {
+ view.addChildNotification(child.view, index)
+ listContainer.notifyGroupChildAdded(child.view)
+ }
+
+ override fun moveChild(child: RowNode, index: Int) {
+ view.removeChildNotification(child.view)
+ view.addChildNotification(child.view, index)
+ }
+
+ override fun removeChild(child: RowNode, isTransfer: Boolean) {
+ view.removeChildNotification(child.view)
+ if (isTransfer) {
+ listContainer.notifyGroupChildRemoved(child.view, view)
+ }
+ }
+}
+
+private class RowWrapper(
+ override val entry: NotificationEntry,
+ override val view: ExpandableNotificationRow
+) : RowNode {
+ override var nodeParent: ParentNode? = null
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifViewManagerLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifViewManagerLogger.kt
new file mode 100644
index 000000000000..3d561264d367
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifViewManagerLogger.kt
@@ -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 com.android.systemui.statusbar.notification.collection.render
+
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.LogLevel
+import com.android.systemui.log.dagger.NotificationLog
+import javax.inject.Inject
+
+class NotifViewManagerLogger @Inject constructor(
+ @NotificationLog private val buffer: LogBuffer
+) {
+ fun logDetachingChild(
+ key: String,
+ isTransfer: Boolean,
+ oldParent: String?,
+ newParent: String?
+ ) {
+ buffer.log(TAG, LogLevel.DEBUG, {
+ str1 = key
+ bool1 = isTransfer
+ str2 = oldParent
+ str3 = newParent
+ }, {
+ "Detach $str1 isTransfer=$bool1 oldParent=$str2 newParent=$str3"
+ })
+ }
+
+ fun logSkippingDetach(key: String, parent: String?) {
+ buffer.log(TAG, LogLevel.DEBUG, {
+ str1 = key
+ str2 = parent
+ }, {
+ "Skipping detach of $str1 because its parent $str2 is also being detached"
+ })
+ }
+
+ fun logAttachingChild(key: String, parent: String) {
+ buffer.log(TAG, LogLevel.DEBUG, {
+ str1 = key
+ str2 = parent
+ }, {
+ "Attaching view $str1 to $str2"
+ })
+ }
+
+ fun logMovingChild(key: String, parent: String, toIndex: Int) {
+ buffer.log(TAG, LogLevel.DEBUG, {
+ str1 = key
+ str2 = parent
+ int1 = toIndex
+ }, {
+ "Moving child view $str1 in $str2 to index $int1"
+ })
+ }
+}
+
+private const val TAG = "NotifViewManager" \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
index d661b5e2b7cf..046dc3c8dce6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
@@ -25,6 +25,7 @@ import android.view.accessibility.AccessibilityManager;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.UiEventLogger;
+import com.android.internal.statusbar.IStatusBarService;
import com.android.systemui.R;
import com.android.systemui.bubbles.BubbleController;
import com.android.systemui.dagger.qualifiers.Background;
@@ -40,9 +41,13 @@ import com.android.systemui.statusbar.notification.ForegroundServiceDismissalFea
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.NotificationEntryManagerLogger;
import com.android.systemui.statusbar.notification.VisualStabilityManager;
+import com.android.systemui.statusbar.notification.collection.NotifCollection;
+import com.android.systemui.statusbar.notification.collection.NotifInflaterImpl;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationRankingManager;
+import com.android.systemui.statusbar.notification.collection.inflation.NotifInflater;
import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinder;
+import com.android.systemui.statusbar.notification.collection.inflation.OnDismissCallbackImpl;
import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection;
import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider;
import com.android.systemui.statusbar.notification.init.NotificationsController;
@@ -56,6 +61,7 @@ import com.android.systemui.statusbar.notification.logging.NotificationPanelLogg
import com.android.systemui.statusbar.notification.row.ChannelEditorDialogController;
import com.android.systemui.statusbar.notification.row.NotificationBlockingHelperManager;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
+import com.android.systemui.statusbar.notification.row.OnDismissCallback;
import com.android.systemui.statusbar.notification.row.PriorityOnboardingDialogController;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.phone.StatusBar;
@@ -90,8 +96,7 @@ public interface NotificationsModule {
Lazy<NotificationRemoteInputManager> notificationRemoteInputManagerLazy,
LeakDetector leakDetector,
ForegroundServiceDismissalFeatureController fgsFeatureController,
- HeadsUpManager headsUpManager,
- StatusBarStateController statusBarStateController) {
+ IStatusBarService statusBarService) {
return new NotificationEntryManager(
logger,
groupManager,
@@ -102,8 +107,7 @@ public interface NotificationsModule {
notificationRemoteInputManagerLazy,
leakDetector,
fgsFeatureController,
- headsUpManager,
- statusBarStateController);
+ statusBarService);
}
/** Provides an instance of {@link NotificationGutsManager} */
@@ -217,8 +221,34 @@ public interface NotificationsModule {
return featureFlags.isNewNotifPipelineRenderingEnabled() ? pipeline.get() : entryManager;
}
+ /**
+ * Provide a dismissal callback that's triggered when a user manually dismissed a notification
+ * from the notification shade or it gets auto-cancelled by click.
+ */
+ @Provides
+ @Singleton
+ static OnDismissCallback provideOnDismissCallback(
+ FeatureFlags featureFlags,
+ HeadsUpManager headsUpManager,
+ StatusBarStateController statusBarStateController,
+ Lazy<NotifPipeline> pipeline,
+ Lazy<NotifCollection> notifCollection,
+ NotificationEntryManager entryManager) {
+ return featureFlags.isNewNotifPipelineRenderingEnabled()
+ ? new OnDismissCallbackImpl(
+ pipeline.get(), notifCollection.get(), headsUpManager,
+ statusBarStateController)
+ : new com.android.systemui.statusbar.notification.collection
+ .legacy.OnDismissCallbackImpl(
+ entryManager, headsUpManager, statusBarStateController);
+ }
+
/** */
@Binds
NotificationInterruptStateProvider bindNotificationInterruptStateProvider(
NotificationInterruptStateProviderImpl notificationInterruptStateProviderImpl);
+
+ /** */
+ @Binds
+ NotifInflater bindNotifInflater(NotifInflaterImpl notifInflaterImpl);
}
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 d1ce8d1cf4c7..22d0357b14c2 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
@@ -16,6 +16,8 @@
package com.android.systemui.statusbar.notification.row;
+import static android.service.notification.NotificationListenerService.REASON_CANCEL;
+
import static com.android.systemui.statusbar.notification.ActivityLaunchAnimator.ExpandAnimationParameters;
import static com.android.systemui.statusbar.notification.row.NotificationContentView.VISIBLE_TYPE_HEADSUP;
import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_PUBLIC;
@@ -92,7 +94,6 @@ import com.android.systemui.statusbar.notification.stack.AmbientState;
import com.android.systemui.statusbar.notification.stack.AnimationProperties;
import com.android.systemui.statusbar.notification.stack.ExpandableViewState;
import com.android.systemui.statusbar.notification.stack.NotificationChildrenContainer;
-import com.android.systemui.statusbar.notification.stack.NotificationListItem;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
import com.android.systemui.statusbar.notification.stack.SwipeableView;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
@@ -115,8 +116,7 @@ import java.util.function.Consumer;
* the group summary (which contains 1 or more child notifications).
*/
public class ExpandableNotificationRow extends ActivatableNotificationView
- implements PluginListener<NotificationMenuRowPlugin>, SwipeableView,
- NotificationListItem {
+ implements PluginListener<NotificationMenuRowPlugin>, SwipeableView {
private static final boolean DEBUG = false;
private static final int DEFAULT_DIVIDER_ALPHA = 0x29;
@@ -323,7 +323,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
private View mGroupParentWhenDismissed;
private boolean mShelfIconVisible;
private boolean mAboveShelf;
- private Runnable mOnDismissRunnable;
+ private OnDismissCallback mOnDismissCallback;
private boolean mIsLowPriority;
private boolean mIsColorized;
private boolean mUseIncreasedCollapsedHeight;
@@ -801,17 +801,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
row.setIsChildInGroup(true, this);
}
- /**
- * Same as {@link #addChildNotification(ExpandableNotificationRow, int)}, but takes a
- * {@link NotificationListItem} instead
- *
- * @param childItem item
- * @param childIndex index
- */
- public void addChildNotification(NotificationListItem childItem, int childIndex) {
- addChildNotification((ExpandableNotificationRow) childItem.getView(), childIndex);
- }
-
public void removeChildNotification(ExpandableNotificationRow row) {
if (mChildrenContainer != null) {
mChildrenContainer.removeNotification(row);
@@ -821,9 +810,15 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
row.setBottomRoundness(0.0f, false /* animate */);
}
- @Override
- public void removeChildNotification(NotificationListItem child) {
- removeChildNotification((ExpandableNotificationRow) child.getView());
+ /** Returns the child notification at [index], or null if no such child. */
+ @Nullable
+ public ExpandableNotificationRow getChildNotificationAt(int index) {
+ if (mChildrenContainer == null
+ || mChildrenContainer.getAttachedChildren().size() <= index) {
+ return null;
+ } else {
+ return mChildrenContainer.getAttachedChildren().get(index);
+ }
}
@Override
@@ -914,7 +909,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
* @param callback the callback to invoked in case it is not allowed
* @return whether the list order has changed
*/
- public boolean applyChildOrder(List<? extends NotificationListItem> childOrder,
+ public boolean applyChildOrder(List<ExpandableNotificationRow> childOrder,
VisualStabilityManager visualStabilityManager,
VisualStabilityManager.Callback callback) {
return mChildrenContainer != null && mChildrenContainer.applyChildOrder(childOrder,
@@ -1321,11 +1316,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
onAttachedChildrenCountChanged();
}
- @Override
- public View getView() {
- return this;
- }
-
public void setForceUnlocked(boolean forceUnlocked) {
mForceUnlocked = forceUnlocked;
if (mIsSummaryWithChildren) {
@@ -1456,10 +1446,8 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
}
dismiss(fromAccessibility);
if (mEntry.isClearable()) {
- // TODO: beverlyt, log dismissal
- // TODO: track dismiss sentiment
- if (mOnDismissRunnable != null) {
- mOnDismissRunnable.run();
+ if (mOnDismissCallback != null) {
+ mOnDismissCallback.onDismiss(mEntry, REASON_CANCEL);
}
}
}
@@ -1476,8 +1464,8 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
return mIsBlockingHelperShowing && mNotificationTranslationFinished;
}
- void setOnDismissRunnable(Runnable onDismissRunnable) {
- mOnDismissRunnable = onDismissRunnable;
+ void setOnDismissCallback(OnDismissCallback onDismissCallback) {
+ mOnDismissCallback = onDismissCallback;
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
index c9839355b9ba..86a3271c4eac 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
@@ -30,7 +30,6 @@ import com.android.systemui.statusbar.NotificationMediaManager;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier;
import com.android.systemui.statusbar.notification.row.dagger.AppName;
-import com.android.systemui.statusbar.notification.row.dagger.DismissRunnable;
import com.android.systemui.statusbar.notification.row.dagger.NotificationKey;
import com.android.systemui.statusbar.notification.row.dagger.NotificationRowScope;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
@@ -66,7 +65,7 @@ public class ExpandableNotificationRowController {
private final ExpandableNotificationRow.CoordinateOnClickListener mOnAppOpsClickListener;
private final ExpandableNotificationRow.CoordinateOnClickListener mOnFeedbackClickListener;
private final NotificationGutsManager mNotificationGutsManager;
- private Runnable mOnDismissRunnable;
+ private final OnDismissCallback mOnDismissCallback;
private final FalsingManager mFalsingManager;
private final boolean mAllowLongPress;
private final PeopleNotificationIdentifier mPeopleNotificationIdentifier;
@@ -84,7 +83,7 @@ public class ExpandableNotificationRowController {
StatusBarStateController statusBarStateController,
NotificationGutsManager notificationGutsManager,
@Named(ALLOW_NOTIFICATION_LONG_PRESS_NAME) boolean allowLongPress,
- @DismissRunnable Runnable onDismissRunnable, FalsingManager falsingManager,
+ OnDismissCallback onDismissCallback, FalsingManager falsingManager,
PeopleNotificationIdentifier peopleNotificationIdentifier) {
mView = view;
mActivatableNotificationViewController = activatableNotificationViewController;
@@ -101,7 +100,7 @@ public class ExpandableNotificationRowController {
mOnExpandClickListener = onExpandClickListener;
mStatusBarStateController = statusBarStateController;
mNotificationGutsManager = notificationGutsManager;
- mOnDismissRunnable = onDismissRunnable;
+ mOnDismissCallback = onDismissCallback;
mOnAppOpsClickListener = mNotificationGutsManager::openGuts;
mOnFeedbackClickListener = mNotificationGutsManager::openGuts;
mAllowLongPress = allowLongPress;
@@ -130,7 +129,7 @@ public class ExpandableNotificationRowController {
mStatusBarStateController,
mPeopleNotificationIdentifier
);
- mView.setOnDismissRunnable(mOnDismissRunnable);
+ mView.setOnDismissCallback(mOnDismissCallback);
mView.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
if (mAllowLongPress) {
mView.setLongPressListener((v, x, y, item) -> {
@@ -163,10 +162,4 @@ public class ExpandableNotificationRowController {
private void logNotificationExpansion(String key, boolean userAction, boolean expanded) {
mNotificationLogger.onExpansionChanged(key, userAction, expanded);
}
-
- /** */
- public void setOnDismissRunnable(Runnable onDismissRunnable) {
- mOnDismissRunnable = onDismissRunnable;
- mView.setOnDismissRunnable(onDismissRunnable);
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/OnDismissCallback.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/OnDismissCallback.java
new file mode 100644
index 000000000000..f1aed899e060
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/OnDismissCallback.java
@@ -0,0 +1,35 @@
+/*
+ * 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.service.notification.NotificationListenerService;
+
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+
+/**
+ * Callback when a user clicks on an auto-cancelled notification or manually swipes to dismiss the
+ * notification.
+ */
+public interface OnDismissCallback {
+
+ /**
+ * Handle a user interaction that triggers a notification dismissal.
+ */
+ void onDismiss(
+ NotificationEntry entry,
+ @NotificationListenerService.NotificationCancelReason int cancellationReason);
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/dagger/ExpandableNotificationRowComponent.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/dagger/ExpandableNotificationRowComponent.java
index 321656df504a..28ddf5971bcb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/dagger/ExpandableNotificationRowComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/dagger/ExpandableNotificationRowComponent.java
@@ -54,8 +54,6 @@ public interface ExpandableNotificationRowComponent {
@BindsInstance
Builder notificationEntry(NotificationEntry entry);
@BindsInstance
- Builder onDismissRunnable(@DismissRunnable Runnable runnable);
- @BindsInstance
Builder onExpandClickListener(ExpandableNotificationRow.OnExpandClickListener presenter);
ExpandableNotificationRowComponent build();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
index 907b89040a28..93c2377ccfae 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
@@ -447,7 +447,7 @@ public class NotificationChildrenContainer extends ViewGroup {
* @param callback
* @return whether the list order has changed
*/
- public boolean applyChildOrder(List<? extends NotificationListItem> childOrder,
+ public boolean applyChildOrder(List<ExpandableNotificationRow> childOrder,
VisualStabilityManager visualStabilityManager,
VisualStabilityManager.Callback callback) {
if (childOrder == null) {
@@ -456,7 +456,7 @@ public class NotificationChildrenContainer extends ViewGroup {
boolean result = false;
for (int i = 0; i < mAttachedChildren.size() && i < childOrder.size(); i++) {
ExpandableNotificationRow child = mAttachedChildren.get(i);
- ExpandableNotificationRow desiredChild = (ExpandableNotificationRow) childOrder.get(i);
+ ExpandableNotificationRow desiredChild = childOrder.get(i);
if (child != desiredChild) {
if (visualStabilityManager.canReorderNotification(desiredChild)) {
mAttachedChildren.remove(desiredChild);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationListContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationListContainer.java
index 09ab1d89473e..72f32161038a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationListContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationListContainer.java
@@ -18,15 +18,15 @@ package com.android.systemui.statusbar.notification.stack;
import static com.android.systemui.statusbar.notification.ActivityLaunchAnimator.ExpandAnimationParameters;
-import android.annotation.NonNull;
import android.view.View;
import android.view.ViewGroup;
+import androidx.annotation.Nullable;
+
import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper;
import com.android.systemui.statusbar.notification.NotificationActivityStarter;
import com.android.systemui.statusbar.notification.VisibilityLocationProvider;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-import com.android.systemui.statusbar.notification.collection.SimpleNotificationListContainer;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.ExpandableView;
@@ -35,8 +35,9 @@ import com.android.systemui.statusbar.notification.row.ExpandableView;
* Interface representing the entity that contains notifications. It can have
* notification views added and removed from it, and will manage displaying them to the user.
*/
-public interface NotificationListContainer extends ExpandableView.OnHeightChangedListener,
- VisibilityLocationProvider, SimpleNotificationListContainer {
+public interface NotificationListContainer extends
+ ExpandableView.OnHeightChangedListener,
+ VisibilityLocationProvider {
/**
* Called when a child is being transferred.
@@ -91,6 +92,7 @@ public interface NotificationListContainer extends ExpandableView.OnHeightChange
* @param i ith child to get
* @return the ith child in the list container
*/
+ @Nullable
View getContainerChildAt(int i);
/**
@@ -108,6 +110,11 @@ public interface NotificationListContainer extends ExpandableView.OnHeightChange
void addContainerView(View v);
/**
+ * Add a view to the container at a particular index
+ */
+ void addContainerViewAt(View v, int index);
+
+ /**
* Sets the maximum number of notifications to display.
*
* @param maxNotifications max number of notifications to display
@@ -188,13 +195,10 @@ public interface NotificationListContainer extends ExpandableView.OnHeightChange
return true;
}
- default void setWillExpand(boolean willExpand) {};
-
/**
- * Remove a list item from the container
- * @param v the item to remove
+ * Tells the container that an animation is about to expand it.
*/
- void removeListItem(@NonNull NotificationListItem v);
+ default void setWillExpand(boolean willExpand) {}
void setNotificationActivityStarter(NotificationActivityStarter notificationActivityStarter);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationListItem.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationListItem.java
deleted file mode 100644
index c2dd2296aa17..000000000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationListItem.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.statusbar.notification.stack;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.view.View;
-
-import com.android.systemui.statusbar.notification.VisualStabilityManager;
-import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-
-import java.util.List;
-
-/**
-* A NotificationListItem is a child view of the notification list that can yield a
-* NotificationEntry when asked. I.e., it's an ExpandableNotificationRow but doesn't require us
-* to strictly rely on ExpandableNotificationRow as our consumed type
- */
-public interface NotificationListItem {
- /** @return entry for this item */
- @NonNull
- NotificationEntry getEntry();
-
- /** @return true if the blocking helper is showing */
- boolean isBlockingHelperShowing();
-
- /** @return true if this list item is a summary with children */
- boolean isSummaryWithChildren();
-
- // This generic is kind of ugly - we should change this once the old VHM is gone
- /** @return list of the children of this item */
- List<? extends NotificationListItem> getAttachedChildren();
-
- /** remove all children from this list item */
- void removeAllChildren();
-
- /** remove particular child */
- void removeChildNotification(NotificationListItem child);
-
- /** add an item as a child */
- void addChildNotification(NotificationListItem child, int childIndex);
-
- /** set the child count view should display */
- void setUntruncatedChildCount(int count);
-
- /** Update the order of the children with the new list */
- boolean applyChildOrder(
- List<? extends NotificationListItem> childOrderList,
- VisualStabilityManager vsm,
- @Nullable VisualStabilityManager.Callback callback);
-
- /** return the associated view for this list item */
- @NonNull
- View getView();
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt
index 91cc8963b947..ff7793d506fd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt
@@ -329,6 +329,7 @@ class NotificationSectionsManager @Inject internal constructor(
// shade.
for (i in parent.childCount - 1 downTo -1) {
val child: View? = parent.getChildAt(i)
+
child?.let {
logShadeChild(i, child)
// If this child is a header, update the tracked positions
@@ -342,7 +343,8 @@ class NotificationSectionsManager @Inject internal constructor(
}
}
- val row = child as? ExpandableNotificationRow
+ val row = (child as? ExpandableNotificationRow)
+ ?.takeUnless { it.visibility == View.GONE }
// Is there a section discontinuity? This usually occurs due to HUNs
inIncomingSection = inIncomingSection || nextBucket?.let { next ->
@@ -389,7 +391,7 @@ class NotificationSectionsManager @Inject internal constructor(
// Offset the target to account for the current position of the people header.
peopleState?.targetPosition = peopleState?.currentPosition?.let { current ->
- peopleState?.targetPosition?.let { target ->
+ peopleState.targetPosition?.let { target ->
if (current < target) target - 1 else target
}
}
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 b9d31a93f408..66a541a923a4 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
@@ -11,7 +11,7 @@
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
- * limitations under the License
+ * limitations under the License.
*/
package com.android.systemui.statusbar.notification.stack;
@@ -3387,21 +3387,11 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
}
@Override
- public void notifyGroupChildRemoved(View child, ViewGroup parent) {
- notifyGroupChildRemoved((ExpandableView) child, parent);
- }
-
- @Override
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void notifyGroupChildAdded(ExpandableView row) {
onViewAddedInternal(row);
}
- @Override
- public void notifyGroupChildAdded(View view) {
- notifyGroupChildAdded((ExpandableView) view);
- }
-
@ShadeViewRefactor(RefactorComponent.STATE_RESOLVER)
public void setAnimationsEnabled(boolean animationsEnabled) {
mAnimationsEnabled = animationsEnabled;
@@ -5246,20 +5236,15 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
@Override
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
- public void removeListItem(NotificationListItem v) {
- removeContainerView(v.getView());
- }
-
- @Override
- @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public void addContainerView(View v) {
Assert.isMainThread();
addView(v);
}
@Override
- public void addListItem(NotificationListItem v) {
- addContainerView(v.getView());
+ public void addContainerViewAt(View v, int index) {
+ Assert.isMainThread();
+ addView(v, index);
}
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
@@ -6596,40 +6581,25 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
} else {
final List<Pair<NotificationEntry, DismissedByUserStats>>
entriesWithRowsDismissedFromShade = new ArrayList<>();
- final List<DismissedByUserStats> dismissalUserStats = new ArrayList<>();
final int numVisibleEntries = mNotifPipeline.getShadeListCount();
for (int i = 0; i < viewsToRemove.size(); i++) {
final NotificationEntry entry = viewsToRemove.get(i).getEntry();
- final DismissedByUserStats stats =
- new DismissedByUserStats(
- DISMISSAL_SHADE,
- DISMISS_SENTIMENT_NEUTRAL,
- NotificationVisibility.obtain(
- entry.getKey(),
- entry.getRanking().getRank(),
- numVisibleEntries,
- true,
- NotificationLogger.getNotificationLocation(entry)));
entriesWithRowsDismissedFromShade.add(
- new Pair<NotificationEntry, DismissedByUserStats>(entry, stats));
+ new Pair<NotificationEntry, DismissedByUserStats>(
+ entry,
+ getDismissedByUserStats(entry, numVisibleEntries)));
}
mNotifCollection.dismissNotifications(entriesWithRowsDismissedFromShade);
}
} else {
for (ExpandableNotificationRow rowToRemove : viewsToRemove) {
if (canChildBeDismissed(rowToRemove)) {
- if (selectedRows == ROWS_ALL) {
- // TODO: This is a listener method; we shouldn't be calling it. Can we just
- // call performRemoveNotification as below?
- mEntryManager.removeNotification(
- rowToRemove.getEntry().getKey(),
- null /* ranking */,
- NotificationListenerService.REASON_CANCEL_ALL);
- } else {
- mEntryManager.performRemoveNotification(
- rowToRemove.getEntry().getSbn(),
- NotificationListenerService.REASON_CANCEL_ALL);
- }
+ mEntryManager.performRemoveNotification(
+ rowToRemove.getEntry().getSbn(),
+ getDismissedByUserStats(
+ rowToRemove.getEntry(),
+ mEntryManager.getActiveNotificationsCount()),
+ NotificationListenerService.REASON_CANCEL_ALL);
} else {
rowToRemove.resetTranslation();
}
@@ -6643,6 +6613,21 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
}
}
+ private DismissedByUserStats getDismissedByUserStats(
+ NotificationEntry entry,
+ int numVisibleEntries
+ ) {
+ return new DismissedByUserStats(
+ DISMISSAL_SHADE,
+ DISMISS_SENTIMENT_NEUTRAL,
+ NotificationVisibility.obtain(
+ entry.getKey(),
+ entry.getRanking().getRank(),
+ numVisibleEntries,
+ true,
+ NotificationLogger.getNotificationLocation(entry)));
+ }
+
// ---------------------- DragDownHelper.OnDragDownListener ------------------------------------
@ShadeViewRefactor(RefactorComponent.INPUT)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
index 303a0831b52f..0e76c904f8cd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
@@ -152,6 +152,7 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp
private final Context mContext;
private final int mWakeUpDelay;
private int mMode;
+ private BiometricSourceType mBiometricType;
private KeyguardViewController mKeyguardViewController;
private DozeScrimController mDozeScrimController;
private KeyguardViewMediator mKeyguardViewMediator;
@@ -340,6 +341,7 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp
Trace.endSection();
return;
}
+ mBiometricType = biometricSourceType;
mMetricsLogger.write(new LogMaker(MetricsEvent.BIOMETRIC_AUTH)
.setType(MetricsEvent.TYPE_SUCCESS).setSubtype(toSubtype(biometricSourceType)));
Optional.ofNullable(BiometricUiEvent.SUCCESS_EVENT_BY_SOURCE_TYPE.get(biometricSourceType))
@@ -615,6 +617,7 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp
private void resetMode() {
mMode = MODE_NONE;
+ mBiometricType = null;
mNotificationShadeWindowController.setForceDozeBrightness(false);
if (mStatusBar.getNavigationBarView() != null) {
mStatusBar.getNavigationBarView().setWakeAndUnlocking(false);
@@ -680,8 +683,8 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp
/**
* Successful authentication with fingerprint, face, or iris when the lockscreen fades away
*/
- public boolean isUnlockFading() {
- return mMode == MODE_UNLOCK_FADING;
+ public BiometricSourceType getBiometricType() {
+ return mBiometricType;
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
index e05ba12781c4..1d82e0808332 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
@@ -241,7 +241,7 @@ public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable,
/**
* Set that we are exiting the headsUp pinned mode, but some notifications might still be
- * animating out. This is used to keep the touchable regions in a sane state.
+ * animating out. This is used to keep the touchable regions in a reasonable state.
*/
void setHeadsUpGoingAway(boolean headsUpGoingAway) {
if (headsUpGoingAway != mHeadsUpGoingAway) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardLiftController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardLiftController.kt
index 74d9f5402e36..bfe0684b5411 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardLiftController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardLiftController.kt
@@ -84,7 +84,9 @@ class KeyguardLiftController constructor(
val onKeyguard = keyguardUpdateMonitor.isKeyguardVisible &&
!statusBarStateController.isDozing
- val shouldListen = onKeyguard || bouncerVisible
+ val userId = KeyguardUpdateMonitor.getCurrentUser()
+ val isFaceEnabled = keyguardUpdateMonitor.isFaceAuthEnabledForUser(userId)
+ val shouldListen = (onKeyguard || bouncerVisible) && isFaceEnabled
if (shouldListen != isListening) {
isListening = shouldListen
@@ -95,4 +97,4 @@ class KeyguardLiftController constructor(
}
}
}
-} \ No newline at end of file
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenLockIconController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenLockIconController.java
index 141bdc242861..1dc0f070835b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenLockIconController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenLockIconController.java
@@ -83,6 +83,7 @@ public class LockscreenLockIconController {
private boolean mWakeAndUnlockRunning;
private boolean mShowingLaunchAffordance;
private boolean mBouncerShowingScrimmed;
+ private boolean mFingerprintUnlock;
private int mStatusBarState = StatusBarState.SHADE;
private LockIcon mLockIcon;
@@ -377,14 +378,19 @@ public class LockscreenLockIconController {
/**
* We need to hide the lock whenever there's a fingerprint unlock, otherwise you'll see the
* icon on top of the black front scrim.
+ * We also want to halt padlock the animation when we're in face bypass mode or dismissing the
+ * keyguard with fingerprint.
* @param wakeAndUnlock are we wake and unlocking
* @param isUnlock are we currently unlocking
*/
- public void onBiometricAuthModeChanged(boolean wakeAndUnlock, boolean isUnlock) {
+ public void onBiometricAuthModeChanged(boolean wakeAndUnlock, boolean isUnlock,
+ BiometricSourceType type) {
if (wakeAndUnlock) {
mWakeAndUnlockRunning = true;
}
- if (isUnlock && mKeyguardBypassController.getBypassEnabled() && canBlockUpdates()) {
+ mFingerprintUnlock = type == BiometricSourceType.FINGERPRINT;
+ if (isUnlock && (mFingerprintUnlock || mKeyguardBypassController.getBypassEnabled())
+ && canBlockUpdates()) {
// We don't want the icon to change while we are unlocking
mBlockUpdates = true;
}
@@ -498,10 +504,13 @@ public class LockscreenLockIconController {
private boolean updateIconVisibility() {
boolean onAodOrDocked = mStatusBarStateController.isDozing() && mDocked;
boolean invisible = onAodOrDocked || mWakeAndUnlockRunning || mShowingLaunchAffordance;
- if (mKeyguardBypassController.getBypassEnabled() && !mBouncerShowingScrimmed) {
+ boolean fingerprintOrBypass = mFingerprintUnlock
+ || mKeyguardBypassController.getBypassEnabled();
+ if (fingerprintOrBypass && !mBouncerShowingScrimmed) {
if ((mHeadsUpManagerPhone.isHeadsUpGoingAway()
|| mHeadsUpManagerPhone.hasPinnedHeadsUp()
- || mStatusBarState == StatusBarState.KEYGUARD)
+ || mStatusBarState == StatusBarState.KEYGUARD
+ || mStatusBarState == StatusBarState.SHADE)
&& !mNotificationWakeUpCoordinator.getNotificationsFullyHidden()) {
invisible = true;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
index f43fa648a1a2..6297052550c3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
@@ -1211,6 +1211,9 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback
}
private void updateAccessibilityServicesState(AccessibilityManager accessibilityManager) {
+ if (mNavigationBarView == null) {
+ return;
+ }
boolean[] feedbackEnabled = new boolean[1];
int a11yFlags = getA11yButtonState(feedbackEnabled);
@@ -1428,6 +1431,9 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
+ if (mNavigationBarView == null) {
+ return;
+ }
String action = intent.getAction();
if (Intent.ACTION_SCREEN_OFF.equals(action)
|| Intent.ACTION_SCREEN_ON.equals(action)) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
index 375af6b099c2..99cb4760a8d9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -62,7 +62,7 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.util.LatencyTracker;
-import com.android.keyguard.KeyguardClockSwitch;
+import com.android.keyguard.KeyguardClockSwitchController;
import com.android.keyguard.KeyguardStatusView;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
@@ -124,6 +124,7 @@ import java.util.function.Consumer;
import java.util.function.Function;
import javax.inject.Inject;
+import javax.inject.Provider;
@StatusBarComponent.StatusBarScope
public class NotificationPanelViewController extends PanelViewController {
@@ -252,6 +253,7 @@ public class NotificationPanelViewController extends PanelViewController {
private final ConversationNotificationManager mConversationNotificationManager;
private final MediaHierarchyManager mMediaHierarchyManager;
private final StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
+ private final Provider<KeyguardClockSwitchController> mKeyguardClockSwitchControllerProvider;
private KeyguardAffordanceHelper mAffordanceHelper;
private KeyguardUserSwitcher mKeyguardUserSwitcher;
@@ -495,7 +497,8 @@ public class NotificationPanelViewController extends PanelViewController {
ConversationNotificationManager conversationNotificationManager,
MediaHierarchyManager mediaHierarchyManager,
BiometricUnlockController biometricUnlockController,
- StatusBarKeyguardViewManager statusBarKeyguardViewManager) {
+ StatusBarKeyguardViewManager statusBarKeyguardViewManager,
+ Provider<KeyguardClockSwitchController> keyguardClockSwitchControllerProvider) {
super(view, falsingManager, dozeLog, keyguardStateController,
(SysuiStatusBarStateController) statusBarStateController, vibratorHelper,
latencyTracker, flingAnimationUtilsBuilder, statusBarTouchableRegionManager);
@@ -507,6 +510,7 @@ public class NotificationPanelViewController extends PanelViewController {
mFlingAnimationUtilsBuilder = flingAnimationUtilsBuilder;
mMediaHierarchyManager = mediaHierarchyManager;
mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
+ mKeyguardClockSwitchControllerProvider = keyguardClockSwitchControllerProvider;
mView.setWillNotDraw(!DEBUG);
mInjectionInflationController = injectionInflationController;
mFalsingManager = falsingManager;
@@ -579,9 +583,11 @@ public class NotificationPanelViewController extends PanelViewController {
mKeyguardStatusBar = mView.findViewById(R.id.keyguard_header);
mKeyguardStatusView = mView.findViewById(R.id.keyguard_status_view);
- KeyguardClockSwitch keyguardClockSwitch = mView.findViewById(R.id.keyguard_clock_container);
+ KeyguardClockSwitchController keyguardClockSwitchController =
+ mKeyguardClockSwitchControllerProvider.get();
+ keyguardClockSwitchController.attach(mView.findViewById(R.id.keyguard_clock_container));
mBigClockContainer = mView.findViewById(R.id.big_clock_container);
- keyguardClockSwitch.setBigClockContainer(mBigClockContainer);
+ keyguardClockSwitchController.setBigClockContainer(mBigClockContainer);
mNotificationContainerParent = mView.findViewById(R.id.notification_container_parent);
mNotificationStackScroller = mView.findViewById(R.id.notification_stack_scroller);
@@ -703,8 +709,10 @@ public class NotificationPanelViewController extends PanelViewController {
// Re-associate the clock container with the keyguard clock switch.
mBigClockContainer.removeAllViews();
- KeyguardClockSwitch keyguardClockSwitch = mView.findViewById(R.id.keyguard_clock_container);
- keyguardClockSwitch.setBigClockContainer(mBigClockContainer);
+ KeyguardClockSwitchController keyguardClockSwitchController =
+ mKeyguardClockSwitchControllerProvider.get();
+ keyguardClockSwitchController.attach(mView.findViewById(R.id.keyguard_clock_container));
+ keyguardClockSwitchController.setBigClockContainer(mBigClockContainer);
// Update keyguard bottom area
index = mView.indexOfChild(mKeyguardBottomArea);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
index e942d85790c1..ac329e2598a9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java
@@ -408,7 +408,7 @@ public abstract class PanelViewController {
&& !mKeyguardStateController.isKeyguardFadingAway()) {
long timePassed = SystemClock.uptimeMillis() - mDownTime;
if (timePassed < ViewConfiguration.getLongPressTimeout()) {
- // Lets show the user that he can actually expand the panel
+ // Let's show the user that they can actually expand the panel
runPeekAnimation(
PEEK_ANIMATION_DURATION, getPeekHeight(), true /* collapseWhenFinished */);
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index c5571e8ceb20..eb626280b494 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -3975,7 +3975,8 @@ public class StatusBar extends SystemUI implements DemoMode,
updateScrimController();
mLockscreenLockIconController.onBiometricAuthModeChanged(
mBiometricUnlockController.isWakeAndUnlock(),
- mBiometricUnlockController.isBiometricUnlock());
+ mBiometricUnlockController.isBiometricUnlock(),
+ mBiometricUnlockController.getBiometricType());
}
@VisibleForTesting
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
index 3ae84ecfc2f0..b89cb210dea1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
@@ -79,15 +79,16 @@ public interface StatusBarIconController {
public void removeIcon(String slot, int tag);
public void removeAllIconsForSlot(String slot);
- public static final String ICON_BLACKLIST = "icon_blacklist";
+ // TODO: See if we can rename this tunable name.
+ String ICON_HIDE_LIST = "icon_blacklist";
- /** Reads the default blacklist from config value unless blacklistStr is provided. */
- static ArraySet<String> getIconBlacklist(Context context, String blackListStr) {
+ /** Reads the default hide list from config value unless hideListStr is provided. */
+ static ArraySet<String> getIconHideList(Context context, String hideListStr) {
ArraySet<String> ret = new ArraySet<>();
- String[] blacklist = blackListStr == null
+ String[] hideList = hideListStr == null
? context.getResources().getStringArray(R.array.config_statusBarIconBlackList)
- : blackListStr.split(",");
- for (String slot : blacklist) {
+ : hideListStr.split(",");
+ for (String slot : hideList) {
if (!TextUtils.isEmpty(slot)) {
ret.add(slot);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java
index d0e806769f14..21e1d319cffa 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java
@@ -59,7 +59,7 @@ public class StatusBarIconControllerImpl extends StatusBarIconList implements Tu
private static final String TAG = "StatusBarIconController";
private final ArrayList<IconManager> mIconGroups = new ArrayList<>();
- private final ArraySet<String> mIconBlacklist = new ArraySet<>();
+ private final ArraySet<String> mIconHideList = new ArraySet<>();
// Points to light or dark context depending on the... context?
private Context mContext;
@@ -79,7 +79,7 @@ public class StatusBarIconControllerImpl extends StatusBarIconList implements Tu
loadDimens();
commandQueue.addCallback(this);
- Dependency.get(TunerService.class).addTunable(this, ICON_BLACKLIST);
+ Dependency.get(TunerService.class).addTunable(this, ICON_HIDE_LIST);
}
@Override
@@ -89,12 +89,12 @@ public class StatusBarIconControllerImpl extends StatusBarIconList implements Tu
for (int i = 0; i < allSlots.size(); i++) {
Slot slot = allSlots.get(i);
List<StatusBarIconHolder> holders = slot.getHolderListInViewOrder();
- boolean blocked = mIconBlacklist.contains(slot.getName());
+ boolean hidden = mIconHideList.contains(slot.getName());
for (StatusBarIconHolder holder : holders) {
int tag = holder.getTag();
int viewIndex = getViewIndex(getSlotIndex(slot.getName()), holder.getTag());
- group.onIconAdded(viewIndex, slot.getName(), blocked, holder);
+ group.onIconAdded(viewIndex, slot.getName(), hidden, holder);
}
}
}
@@ -107,11 +107,11 @@ public class StatusBarIconControllerImpl extends StatusBarIconList implements Tu
@Override
public void onTuningChanged(String key, String newValue) {
- if (!ICON_BLACKLIST.equals(key)) {
+ if (!ICON_HIDE_LIST.equals(key)) {
return;
}
- mIconBlacklist.clear();
- mIconBlacklist.addAll(StatusBarIconController.getIconBlacklist(mContext, newValue));
+ mIconHideList.clear();
+ mIconHideList.addAll(StatusBarIconController.getIconHideList(mContext, newValue));
ArrayList<Slot> currentSlots = getSlots();
ArrayMap<Slot, List<StatusBarIconHolder>> slotsToReAdd = new ArrayMap<>();
@@ -142,9 +142,9 @@ public class StatusBarIconControllerImpl extends StatusBarIconList implements Tu
private void addSystemIcon(int index, StatusBarIconHolder holder) {
String slot = getSlotName(index);
int viewIndex = getViewIndex(index, holder.getTag());
- boolean blocked = mIconBlacklist.contains(slot);
+ boolean hidden = mIconHideList.contains(slot);
- mIconGroups.forEach(l -> l.onIconAdded(viewIndex, slot, blocked, holder));
+ mIconGroups.forEach(l -> l.onIconAdded(viewIndex, slot, hidden, holder));
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
index 7bcfb466d7d9..4de648402464 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
@@ -17,7 +17,6 @@
package com.android.systemui.statusbar.phone;
import static android.service.notification.NotificationListenerService.REASON_CLICK;
-import static android.service.notification.NotificationStats.DISMISS_SENTIMENT_NEUTRAL;
import static com.android.systemui.statusbar.phone.StatusBar.getActivityOptions;
@@ -37,7 +36,6 @@ import android.os.RemoteException;
import android.os.UserHandle;
import android.provider.Settings;
import android.service.dreams.IDreamManager;
-import android.service.notification.NotificationStats;
import android.service.notification.StatusBarNotification;
import android.text.TextUtils;
import android.util.EventLog;
@@ -71,11 +69,11 @@ import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.collection.NotifCollection;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-import com.android.systemui.statusbar.notification.collection.notifcollection.DismissedByUserStats;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
+import com.android.systemui.statusbar.notification.row.OnDismissCallback;
import com.android.systemui.statusbar.policy.HeadsUpUtil;
import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -128,6 +126,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
private final NotificationPresenter mPresenter;
private final NotificationPanelViewController mNotificationPanel;
private final ActivityLaunchAnimator mActivityLaunchAnimator;
+ private final OnDismissCallback mOnDismissCallback;
private boolean mIsCollapsingToShowActivityOverLockscreen;
@@ -162,6 +161,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
FeatureFlags featureFlags,
MetricsLogger metricsLogger,
StatusBarNotificationActivityStarterLogger logger,
+ OnDismissCallback onDismissCallback,
StatusBar statusBar,
NotificationPresenter presenter,
@@ -197,6 +197,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
mFeatureFlags = featureFlags;
mMetricsLogger = metricsLogger;
mLogger = logger;
+ mOnDismissCallback = onDismissCallback;
// TODO: use KeyguardStateController#isOccluded to remove this dependency
mStatusBar = statusBar;
@@ -574,13 +575,14 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
private void removeNotification(NotificationEntry entry) {
// We have to post it to the UI thread for synchronization
mMainThreadHandler.post(() -> {
- Runnable removeRunnable = createRemoveRunnable(entry);
if (mPresenter.isCollapsing()) {
// To avoid lags we're only performing the remove
// after the shade was collapsed
- mShadeController.addPostCollapseAction(removeRunnable);
+ mShadeController.addPostCollapseAction(
+ () -> mOnDismissCallback.onDismiss(entry, REASON_CLICK)
+ );
} else {
- removeRunnable.run();
+ mOnDismissCallback.onDismiss(entry, REASON_CLICK);
}
});
}
@@ -595,43 +597,6 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
}
}
- private Runnable createRemoveRunnable(NotificationEntry entry) {
- if (mFeatureFlags.isNewNotifPipelineRenderingEnabled()) {
- return new Runnable() {
- @Override
- public void run() {
- // see NotificationLogger#logNotificationClear
- int dismissalSurface = NotificationStats.DISMISSAL_SHADE;
- if (mHeadsUpManager.isAlerting(entry.getKey())) {
- dismissalSurface = NotificationStats.DISMISSAL_PEEK;
- } else if (mNotificationPanel.hasPulsingNotifications()) {
- dismissalSurface = NotificationStats.DISMISSAL_AOD;
- }
-
- mNotifCollection.dismissNotification(
- entry,
- new DismissedByUserStats(
- dismissalSurface,
- DISMISS_SENTIMENT_NEUTRAL,
- NotificationVisibility.obtain(
- entry.getKey(),
- entry.getRanking().getRank(),
- mNotifPipeline.getShadeListCount(),
- true,
- NotificationLogger.getNotificationLocation(entry))
- ));
- }
- };
- } else {
- return new Runnable() {
- @Override
- public void run() {
- mEntryManager.performRemoveNotification(entry.getSbn(), REASON_CLICK);
- }
- };
- }
- }
-
/**
* Public builder for {@link StatusBarNotificationActivityStarter}.
*/
@@ -667,6 +632,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
private final FeatureFlags mFeatureFlags;
private final MetricsLogger mMetricsLogger;
private final StatusBarNotificationActivityStarterLogger mLogger;
+ private final OnDismissCallback mOnDismissCallback;
private StatusBar mStatusBar;
private NotificationPresenter mNotificationPresenter;
@@ -704,7 +670,8 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
FeatureFlags featureFlags,
MetricsLogger metricsLogger,
- StatusBarNotificationActivityStarterLogger logger) {
+ StatusBarNotificationActivityStarterLogger logger,
+ OnDismissCallback onDismissCallback) {
mContext = context;
mCommandQueue = commandQueue;
@@ -736,6 +703,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
mFeatureFlags = featureFlags;
mMetricsLogger = metricsLogger;
mLogger = logger;
+ mOnDismissCallback = onDismissCallback;
}
/** Sets the status bar to use as {@link StatusBar}. */
@@ -793,6 +761,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit
mFeatureFlags,
mMetricsLogger,
mLogger,
+ mOnDismissCallback,
mStatusBar,
mNotificationPresenter,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java
index 690d57345db6..7eefaf28517e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java
@@ -52,12 +52,12 @@ public class StatusBarSignalPolicy implements NetworkControllerImpl.SignalCallba
private final SecurityController mSecurityController;
private final Handler mHandler = Handler.getMain();
- private boolean mBlockAirplane;
- private boolean mBlockMobile;
- private boolean mBlockWifi;
- private boolean mBlockEthernet;
+ private boolean mHideAirplane;
+ private boolean mHideMobile;
+ private boolean mHideWifi;
+ private boolean mHideEthernet;
private boolean mActivityEnabled;
- private boolean mForceBlockWifi;
+ private boolean mForceHideWifi;
// Track as little state as possible, and only for padding purposes
private boolean mIsAirplaneMode = false;
@@ -80,7 +80,7 @@ public class StatusBarSignalPolicy implements NetworkControllerImpl.SignalCallba
mNetworkController = Dependency.get(NetworkController.class);
mSecurityController = Dependency.get(SecurityController.class);
- Dependency.get(TunerService.class).addTunable(this, StatusBarIconController.ICON_BLACKLIST);
+ Dependency.get(TunerService.class).addTunable(this, StatusBarIconController.ICON_HIDE_LIST);
mNetworkController.addCallback(this);
mSecurityController.addCallback(this);
}
@@ -114,21 +114,21 @@ public class StatusBarSignalPolicy implements NetworkControllerImpl.SignalCallba
@Override
public void onTuningChanged(String key, String newValue) {
- if (!StatusBarIconController.ICON_BLACKLIST.equals(key)) {
+ if (!StatusBarIconController.ICON_HIDE_LIST.equals(key)) {
return;
}
- ArraySet<String> blockList = StatusBarIconController.getIconBlacklist(mContext, newValue);
- boolean blockAirplane = blockList.contains(mSlotAirplane);
- boolean blockMobile = blockList.contains(mSlotMobile);
- boolean blockWifi = blockList.contains(mSlotWifi);
- boolean blockEthernet = blockList.contains(mSlotEthernet);
-
- if (blockAirplane != mBlockAirplane || blockMobile != mBlockMobile
- || blockEthernet != mBlockEthernet || blockWifi != mBlockWifi) {
- mBlockAirplane = blockAirplane;
- mBlockMobile = blockMobile;
- mBlockEthernet = blockEthernet;
- mBlockWifi = blockWifi || mForceBlockWifi;
+ ArraySet<String> hideList = StatusBarIconController.getIconHideList(mContext, newValue);
+ boolean hideAirplane = hideList.contains(mSlotAirplane);
+ boolean hideMobile = hideList.contains(mSlotMobile);
+ boolean hideWifi = hideList.contains(mSlotWifi);
+ boolean hideEthernet = hideList.contains(mSlotEthernet);
+
+ if (hideAirplane != mHideAirplane || hideMobile != mHideMobile
+ || hideEthernet != mHideEthernet || hideWifi != mHideWifi) {
+ mHideAirplane = hideAirplane;
+ mHideMobile = hideMobile;
+ mHideEthernet = hideEthernet;
+ mHideWifi = hideWifi || mForceHideWifi;
// Re-register to get new callbacks.
mNetworkController.removeCallback(this);
mNetworkController.addCallback(this);
@@ -140,7 +140,7 @@ public class StatusBarSignalPolicy implements NetworkControllerImpl.SignalCallba
boolean activityIn, boolean activityOut, String description, boolean isTransient,
String statusLabel) {
- boolean visible = statusIcon.visible && !mBlockWifi;
+ boolean visible = statusIcon.visible && !mHideWifi;
boolean in = activityIn && mActivityEnabled && visible;
boolean out = activityOut && mActivityEnabled && visible;
@@ -189,7 +189,7 @@ public class StatusBarSignalPolicy implements NetworkControllerImpl.SignalCallba
// Visibility of the data type indicator changed
boolean typeChanged = statusType != state.typeId && (statusType == 0 || state.typeId == 0);
- state.visible = statusIcon.visible && !mBlockMobile;
+ state.visible = statusIcon.visible && !mHideMobile;
state.strengthId = statusIcon.icon;
state.typeId = statusType;
state.contentDescription = statusIcon.contentDescription;
@@ -270,7 +270,7 @@ public class StatusBarSignalPolicy implements NetworkControllerImpl.SignalCallba
@Override
public void setEthernetIndicators(IconState state) {
- boolean visible = state.visible && !mBlockEthernet;
+ boolean visible = state.visible && !mHideEthernet;
int resId = state.icon;
String description = state.contentDescription;
@@ -284,7 +284,7 @@ public class StatusBarSignalPolicy implements NetworkControllerImpl.SignalCallba
@Override
public void setIsAirplaneMode(IconState icon) {
- mIsAirplaneMode = icon.visible && !mBlockAirplane;
+ mIsAirplaneMode = icon.visible && !mHideAirplane;
int resId = icon.icon;
String description = icon.contentDescription;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java
index d30f01a658f6..88a6263c1dca 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java
@@ -74,7 +74,7 @@ public class BatteryControllerImpl extends BroadcastReceiver implements BatteryC
protected boolean mPowerSave;
private boolean mAodPowerSave;
protected boolean mWirelessCharging;
- private boolean mTestmode = false;
+ private boolean mTestMode = false;
@VisibleForTesting
boolean mHasReceivedBattery = false;
private Estimate mEstimate;
@@ -154,7 +154,7 @@ public class BatteryControllerImpl extends BroadcastReceiver implements BatteryC
public void onReceive(final Context context, Intent intent) {
final String action = intent.getAction();
if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {
- if (mTestmode && !intent.getBooleanExtra("testmode", false)) return;
+ if (mTestMode && !intent.getBooleanExtra("testmode", false)) return;
mHasReceivedBattery = true;
mLevel = (int)(100f
* intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0)
@@ -172,29 +172,29 @@ public class BatteryControllerImpl extends BroadcastReceiver implements BatteryC
} else if (action.equals(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED)) {
updatePowerSave();
} else if (action.equals(ACTION_LEVEL_TEST)) {
- mTestmode = true;
+ mTestMode = true;
mMainHandler.post(new Runnable() {
int curLevel = 0;
int incr = 1;
int saveLevel = mLevel;
boolean savePlugged = mPluggedIn;
- Intent dummy = new Intent(Intent.ACTION_BATTERY_CHANGED);
+ Intent mTestIntent = new Intent(Intent.ACTION_BATTERY_CHANGED);
@Override
public void run() {
if (curLevel < 0) {
- mTestmode = false;
- dummy.putExtra("level", saveLevel);
- dummy.putExtra("plugged", savePlugged);
- dummy.putExtra("testmode", false);
+ mTestMode = false;
+ mTestIntent.putExtra("level", saveLevel);
+ mTestIntent.putExtra("plugged", savePlugged);
+ mTestIntent.putExtra("testmode", false);
} else {
- dummy.putExtra("level", curLevel);
- dummy.putExtra("plugged", incr > 0 ? BatteryManager.BATTERY_PLUGGED_AC
+ mTestIntent.putExtra("level", curLevel);
+ mTestIntent.putExtra("plugged", incr > 0 ? BatteryManager.BATTERY_PLUGGED_AC
: 0);
- dummy.putExtra("testmode", true);
+ mTestIntent.putExtra("testmode", true);
}
- context.sendBroadcast(dummy);
+ context.sendBroadcast(mTestIntent);
- if (!mTestmode) return;
+ if (!mTestMode) return;
curLevel += incr;
if (curLevel == 100) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
index 95601955ec04..120a0e3abba4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
@@ -191,7 +191,7 @@ public class Clock extends TextView implements DemoMode, Tunable, CommandQueue.C
mBroadcastDispatcher.registerReceiverWithHandler(mIntentReceiver, filter,
Dependency.get(Dependency.TIME_TICK_HANDLER), UserHandle.ALL);
Dependency.get(TunerService.class).addTunable(this, CLOCK_SECONDS,
- StatusBarIconController.ICON_BLACKLIST);
+ StatusBarIconController.ICON_HIDE_LIST);
mCommandQueue.addCallback(this);
if (mShowDark) {
Dependency.get(DarkIconDispatcher.class).addDarkReceiver(this);
@@ -305,8 +305,8 @@ public class Clock extends TextView implements DemoMode, Tunable, CommandQueue.C
if (CLOCK_SECONDS.equals(key)) {
mShowSeconds = TunerService.parseIntegerSwitch(newValue, false);
updateShowSeconds();
- } else {
- setClockVisibleByUser(!StatusBarIconController.getIconBlacklist(getContext(), newValue)
+ } else if (StatusBarIconController.ICON_HIDE_LIST.equals(key)) {
+ setClockVisibleByUser(!StatusBarIconController.getIconHideList(getContext(), newValue)
.contains("clock"));
updateClockVisibility();
}
@@ -404,7 +404,7 @@ public class Clock extends TextView implements DemoMode, Tunable, CommandQueue.C
mContentDescriptionFormat = new SimpleDateFormat(format);
/*
* Search for an unquoted "a" in the format string, so we can
- * add dummy characters around it to let us find it again after
+ * add marker characters around it to let us find it again after
* formatting and change its size.
*/
if (mAmPmStyle != AM_PM_STYLE_NORMAL) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeadZone.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeadZone.java
index 54502e41ca64..12d0617d90ff 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeadZone.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeadZone.java
@@ -198,7 +198,7 @@ public class DeadZone {
can.drawARGB((int) (frac * 0xFF), 0xDD, 0xEE, 0xAA);
if (DEBUG && size > mSizeMin)
- // crazy aggressive redrawing here, for debugging only
+ // Very aggressive redrawing here, for debugging only
mNavigationBarView.postInvalidateDelayed(100);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/BatteryPreference.java b/packages/SystemUI/src/com/android/systemui/tuner/BatteryPreference.java
index 66372c311325..b71aafdf6b96 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/BatteryPreference.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/BatteryPreference.java
@@ -38,7 +38,7 @@ public class BatteryPreference extends DropDownPreference implements TunerServic
private final String mBattery;
private boolean mBatteryEnabled;
private boolean mHasPercentage;
- private ArraySet<String> mBlacklist;
+ private ArraySet<String> mHideList;
private boolean mHasSetValue;
public BatteryPreference(Context context, AttributeSet attrs) {
@@ -52,7 +52,7 @@ public class BatteryPreference extends DropDownPreference implements TunerServic
super.onAttached();
mHasPercentage = Settings.System.getInt(getContext().getContentResolver(),
SHOW_BATTERY_PERCENT, 0) != 0;
- Dependency.get(TunerService.class).addTunable(this, StatusBarIconController.ICON_BLACKLIST);
+ Dependency.get(TunerService.class).addTunable(this, StatusBarIconController.ICON_HIDE_LIST);
}
@Override
@@ -63,9 +63,9 @@ public class BatteryPreference extends DropDownPreference implements TunerServic
@Override
public void onTuningChanged(String key, String newValue) {
- if (StatusBarIconController.ICON_BLACKLIST.equals(key)) {
- mBlacklist = StatusBarIconController.getIconBlacklist(getContext(), newValue);
- mBatteryEnabled = !mBlacklist.contains(mBattery);
+ if (StatusBarIconController.ICON_HIDE_LIST.equals(key)) {
+ mHideList = StatusBarIconController.getIconHideList(getContext(), newValue);
+ mBatteryEnabled = !mHideList.contains(mBattery);
}
if (!mHasSetValue) {
// Because of the complicated tri-state it can end up looping and setting state back to
@@ -88,12 +88,12 @@ public class BatteryPreference extends DropDownPreference implements TunerServic
MetricsLogger.action(getContext(), MetricsEvent.TUNER_BATTERY_PERCENTAGE, v);
Settings.System.putInt(getContext().getContentResolver(), SHOW_BATTERY_PERCENT, v ? 1 : 0);
if (DISABLED.equals(value)) {
- mBlacklist.add(mBattery);
+ mHideList.add(mBattery);
} else {
- mBlacklist.remove(mBattery);
+ mHideList.remove(mBattery);
}
- Dependency.get(TunerService.class).setValue(StatusBarIconController.ICON_BLACKLIST,
- TextUtils.join(",", mBlacklist));
+ Dependency.get(TunerService.class).setValue(StatusBarIconController.ICON_HIDE_LIST,
+ TextUtils.join(",", mHideList));
return true;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/ClockPreference.java b/packages/SystemUI/src/com/android/systemui/tuner/ClockPreference.java
index f7d0c9fb9d86..c92d7bbfe0b7 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/ClockPreference.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/ClockPreference.java
@@ -33,7 +33,7 @@ public class ClockPreference extends DropDownPreference implements TunerService.
private final String mClock;
private boolean mClockEnabled;
private boolean mHasSeconds;
- private ArraySet<String> mBlacklist;
+ private ArraySet<String> mHideList;
private boolean mHasSetValue;
private boolean mReceivedSeconds;
private boolean mReceivedClock;
@@ -47,7 +47,7 @@ public class ClockPreference extends DropDownPreference implements TunerService.
@Override
public void onAttached() {
super.onAttached();
- Dependency.get(TunerService.class).addTunable(this, StatusBarIconController.ICON_BLACKLIST,
+ Dependency.get(TunerService.class).addTunable(this, StatusBarIconController.ICON_HIDE_LIST,
Clock.CLOCK_SECONDS);
}
@@ -59,10 +59,10 @@ public class ClockPreference extends DropDownPreference implements TunerService.
@Override
public void onTuningChanged(String key, String newValue) {
- if (StatusBarIconController.ICON_BLACKLIST.equals(key)) {
+ if (StatusBarIconController.ICON_HIDE_LIST.equals(key)) {
mReceivedClock = true;
- mBlacklist = StatusBarIconController.getIconBlacklist(getContext(), newValue);
- mClockEnabled = !mBlacklist.contains(mClock);
+ mHideList = StatusBarIconController.getIconHideList(getContext(), newValue);
+ mClockEnabled = !mHideList.contains(mClock);
} else if (Clock.CLOCK_SECONDS.equals(key)) {
mReceivedSeconds = true;
mHasSeconds = newValue != null && Integer.parseInt(newValue) != 0;
@@ -87,12 +87,12 @@ public class ClockPreference extends DropDownPreference implements TunerService.
Dependency.get(TunerService.class).setValue(Clock.CLOCK_SECONDS, SECONDS.equals(value) ? 1
: 0);
if (DISABLED.equals(value)) {
- mBlacklist.add(mClock);
+ mHideList.add(mClock);
} else {
- mBlacklist.remove(mClock);
+ mHideList.remove(mClock);
}
- Dependency.get(TunerService.class).setValue(StatusBarIconController.ICON_BLACKLIST,
- TextUtils.join(",", mBlacklist));
+ Dependency.get(TunerService.class).setValue(StatusBarIconController.ICON_HIDE_LIST,
+ TextUtils.join(",", mHideList));
return true;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/StatusBarSwitch.java b/packages/SystemUI/src/com/android/systemui/tuner/StatusBarSwitch.java
index de8ccfa848e3..cc0050b64d60 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/StatusBarSwitch.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/StatusBarSwitch.java
@@ -34,7 +34,7 @@ import java.util.Set;
public class StatusBarSwitch extends SwitchPreference implements Tunable {
- private Set<String> mBlacklist;
+ private Set<String> mHideList;
public StatusBarSwitch(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -43,7 +43,7 @@ public class StatusBarSwitch extends SwitchPreference implements Tunable {
@Override
public void onAttached() {
super.onAttached();
- Dependency.get(TunerService.class).addTunable(this, StatusBarIconController.ICON_BLACKLIST);
+ Dependency.get(TunerService.class).addTunable(this, StatusBarIconController.ICON_HIDE_LIST);
}
@Override
@@ -54,35 +54,35 @@ public class StatusBarSwitch extends SwitchPreference implements Tunable {
@Override
public void onTuningChanged(String key, String newValue) {
- if (!StatusBarIconController.ICON_BLACKLIST.equals(key)) {
+ if (!StatusBarIconController.ICON_HIDE_LIST.equals(key)) {
return;
}
- mBlacklist = StatusBarIconController.getIconBlacklist(getContext(), newValue);
- setChecked(!mBlacklist.contains(getKey()));
+ mHideList = StatusBarIconController.getIconHideList(getContext(), newValue);
+ setChecked(!mHideList.contains(getKey()));
}
@Override
protected boolean persistBoolean(boolean value) {
if (!value) {
- // If not enabled add to blacklist.
- if (!mBlacklist.contains(getKey())) {
+ // If not enabled add to hideList.
+ if (!mHideList.contains(getKey())) {
MetricsLogger.action(getContext(), MetricsEvent.TUNER_STATUS_BAR_DISABLE,
getKey());
- mBlacklist.add(getKey());
- setList(mBlacklist);
+ mHideList.add(getKey());
+ setList(mHideList);
}
} else {
- if (mBlacklist.remove(getKey())) {
+ if (mHideList.remove(getKey())) {
MetricsLogger.action(getContext(), MetricsEvent.TUNER_STATUS_BAR_ENABLE, getKey());
- setList(mBlacklist);
+ setList(mHideList);
}
}
return true;
}
- private void setList(Set<String> blacklist) {
+ private void setList(Set<String> hideList) {
ContentResolver contentResolver = getContext().getContentResolver();
- Settings.Secure.putStringForUser(contentResolver, StatusBarIconController.ICON_BLACKLIST,
- TextUtils.join(",", blacklist), ActivityManager.getCurrentUser());
+ Settings.Secure.putStringForUser(contentResolver, StatusBarIconController.ICON_HIDE_LIST,
+ TextUtils.join(",", hideList), ActivityManager.getCurrentUser());
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java
index 9ad2aa257aa0..644f7582f146 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java
@@ -60,7 +60,7 @@ public class TunerServiceImpl extends TunerService {
// Things that use the tunable infrastructure but are now real user settings and
// shouldn't be reset with tuner settings.
- private static final String[] RESET_BLACKLIST = new String[] {
+ private static final String[] RESET_EXCEPTION_LIST = new String[] {
QSTileHost.TILES_SETTING,
Settings.Secure.DOZE_ALWAYS_ON,
Settings.Secure.MEDIA_CONTROLS_RESUME
@@ -116,17 +116,17 @@ public class TunerServiceImpl extends TunerService {
private void upgradeTuner(int oldVersion, int newVersion, Handler mainHandler) {
if (oldVersion < 1) {
- String blacklistStr = getValue(StatusBarIconController.ICON_BLACKLIST);
- if (blacklistStr != null) {
- ArraySet<String> iconBlacklist =
- StatusBarIconController.getIconBlacklist(mContext, blacklistStr);
+ String hideListStr = getValue(StatusBarIconController.ICON_HIDE_LIST);
+ if (hideListStr != null) {
+ ArraySet<String> iconHideList =
+ StatusBarIconController.getIconHideList(mContext, hideListStr);
- iconBlacklist.add("rotate");
- iconBlacklist.add("headset");
+ iconHideList.add("rotate");
+ iconHideList.add("headset");
Settings.Secure.putStringForUser(mContentResolver,
- StatusBarIconController.ICON_BLACKLIST,
- TextUtils.join(",", iconBlacklist), mCurrentUser);
+ StatusBarIconController.ICON_HIDE_LIST,
+ TextUtils.join(",", iconHideList), mCurrentUser);
}
}
if (oldVersion < 2) {
@@ -251,7 +251,7 @@ public class TunerServiceImpl extends TunerService {
mContext.sendBroadcast(intent);
for (String key : mTunableLookup.keySet()) {
- if (ArrayUtils.contains(RESET_BLACKLIST, key)) {
+ if (ArrayUtils.contains(RESET_EXCEPTION_LIST, key)) {
continue;
}
Settings.Secure.putStringForUser(mContentResolver, key, null, user);
diff --git a/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIRootComponent.java b/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIRootComponent.java
index 2c8297cbfd88..dce38c109930 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIRootComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/TvSystemUIRootComponent.java
@@ -16,8 +16,6 @@
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;
@@ -30,7 +28,6 @@ import com.android.systemui.onehanded.dagger.OneHandedModule;
import javax.inject.Singleton;
-import dagger.BindsInstance;
import dagger.Component;
/**
@@ -52,9 +49,7 @@ 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);
-
+ interface Builder extends SystemUIRootComponent.Builder {
TvSystemUIRootComponent build();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java b/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java
index c63712389a80..551b7b41212a 100644
--- a/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java
+++ b/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java
@@ -23,7 +23,6 @@ import android.view.InflateException;
import android.view.LayoutInflater;
import android.view.View;
-import com.android.keyguard.KeyguardClockSwitch;
import com.android.keyguard.KeyguardMessageArea;
import com.android.keyguard.KeyguardSliceView;
import com.android.systemui.dagger.SystemUIRootComponent;
@@ -132,11 +131,6 @@ public class InjectionInflationController {
NotificationShelf creatNotificationShelf();
/**
- * Creates the KeyguardClockSwitch.
- */
- KeyguardClockSwitch createKeyguardClockSwitch();
-
- /**
* Creates the KeyguardSliceView.
*/
KeyguardSliceView createKeyguardSliceView();
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WindowManagerShellModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/WindowManagerShellModule.java
index fbc167683a2a..5b2c39db2eae 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WindowManagerShellModule.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WindowManagerShellModule.java
@@ -59,9 +59,10 @@ public class WindowManagerShellModule {
@Singleton
@Provides
- static DisplayImeController provideDisplayImeController(
- IWindowManager wmService, DisplayController displayController,
- @Main Handler mainHandler, TransactionPool transactionPool) {
- return new DisplayImeController(wmService, displayController, mainHandler, transactionPool);
+ static DisplayImeController provideDisplayImeController(IWindowManager wmService,
+ DisplayController displayController, @Main Handler mainHandler,
+ TransactionPool transactionPool) {
+ return new DisplayImeController.Builder(wmService, displayController, mainHandler,
+ transactionPool).build();
}
}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
new file mode 100644
index 000000000000..657e4fbb4633
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
@@ -0,0 +1,162 @@
+/*
+ * 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.keyguard;
+
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.test.suitebuilder.annotation.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+
+import com.android.internal.colorextraction.ColorExtractor;
+import com.android.keyguard.clock.ClockManager;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.colorextraction.SysuiColorExtractor;
+import com.android.systemui.plugins.ClockPlugin;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.StatusBarState;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.mockito.verification.VerificationMode;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+public class KeyguardClockSwitchControllerTest extends SysuiTestCase {
+
+ @Mock
+ private StatusBarStateController mStatusBarStateController;
+ @Mock
+ private SysuiColorExtractor mColorExtractor;
+ @Mock
+ private ClockManager mClockManager;
+ @Mock
+ private KeyguardClockSwitch mView;
+ @Mock
+ private ClockPlugin mClockPlugin;
+ @Mock
+ ColorExtractor.GradientColors mGradientColors;
+
+ private KeyguardClockSwitchController mController;
+
+ @Before
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+
+ mController = new KeyguardClockSwitchController(
+ mStatusBarStateController, mColorExtractor, mClockManager);
+
+ when(mView.isAttachedToWindow()).thenReturn(true);
+ when(mStatusBarStateController.getState()).thenReturn(StatusBarState.SHADE);
+ when(mColorExtractor.getColors(anyInt())).thenReturn(mGradientColors);
+ }
+
+ @Test
+ public void testAttach_viewAlreadyAttached() {
+ mController.attach(mView);
+
+ verifyAttachment(times(1));
+ }
+
+ @Test
+ public void testAttach_viewNotYetAttached() {
+ ArgumentCaptor<View.OnAttachStateChangeListener> listenerArgumentCaptor =
+ ArgumentCaptor.forClass(View.OnAttachStateChangeListener.class);
+
+ when(mView.isAttachedToWindow()).thenReturn(false);
+ mController.attach(mView);
+ verify(mView).addOnAttachStateChangeListener(listenerArgumentCaptor.capture());
+
+ verifyAttachment(never());
+
+ listenerArgumentCaptor.getValue().onViewAttachedToWindow(mView);
+
+ verifyAttachment(times(1));
+ }
+
+
+ @Test
+ public void testAttach_viewDetached() {
+ ArgumentCaptor<View.OnAttachStateChangeListener> listenerArgumentCaptor =
+ ArgumentCaptor.forClass(View.OnAttachStateChangeListener.class);
+ mController.attach(mView);
+ verify(mView).addOnAttachStateChangeListener(listenerArgumentCaptor.capture());
+
+ verifyAttachment(times(1));
+
+ listenerArgumentCaptor.getValue().onViewDetachedFromWindow(mView);
+
+ verify(mStatusBarStateController).removeCallback(
+ any(StatusBarStateController.StateListener.class));
+ verify(mColorExtractor).removeOnColorsChangedListener(
+ any(ColorExtractor.OnColorsChangedListener.class));
+ }
+
+ @Test
+ public void testBigClockPassesStatusBarState() {
+ ViewGroup testView = new FrameLayout(mContext);
+
+ mController.attach(mView);
+ when(mStatusBarStateController.getState()).thenReturn(StatusBarState.SHADE);
+ mController.setBigClockContainer(testView);
+ verify(mView).setBigClockContainer(testView, StatusBarState.SHADE);
+
+
+ when(mStatusBarStateController.getState()).thenReturn(StatusBarState.KEYGUARD);
+ mController.setBigClockContainer(testView);
+ verify(mView).setBigClockContainer(testView, StatusBarState.KEYGUARD);
+
+
+ when(mStatusBarStateController.getState()).thenReturn(StatusBarState.SHADE_LOCKED);
+ mController.setBigClockContainer(testView);
+ verify(mView).setBigClockContainer(testView, StatusBarState.SHADE_LOCKED);
+ }
+
+ @Test
+ public void testPluginPassesStatusBarState() {
+ ArgumentCaptor<ClockManager.ClockChangedListener> listenerArgumentCaptor =
+ ArgumentCaptor.forClass(ClockManager.ClockChangedListener.class);
+
+ mController.attach(mView);
+ verify(mClockManager).addOnClockChangedListener(listenerArgumentCaptor.capture());
+
+ listenerArgumentCaptor.getValue().onClockChanged(mClockPlugin);
+ verify(mView).setClockPlugin(mClockPlugin, StatusBarState.SHADE);
+ }
+
+ private void verifyAttachment(VerificationMode times) {
+ verify(mClockManager, times).addOnClockChangedListener(
+ any(ClockManager.ClockChangedListener.class));
+ verify(mStatusBarStateController, times).addCallback(
+ any(StatusBarStateController.StateListener.class));
+ verify(mColorExtractor, times).addOnColorsChangedListener(
+ any(ColorExtractor.OnColorsChangedListener.class));
+ verify(mView, times).updateColors(mGradientColors);
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java
index 04ceee8b9cea..4c0762e4ea32 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java
@@ -40,12 +40,10 @@ import android.view.View;
import android.widget.FrameLayout;
import android.widget.TextClock;
-import com.android.keyguard.clock.ClockManager;
import com.android.systemui.R;
import com.android.systemui.SystemUIFactory;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.plugins.ClockPlugin;
-import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.util.InjectionInflationController;
@@ -66,7 +64,6 @@ public class KeyguardClockSwitchTest extends SysuiTestCase {
private FrameLayout mClockContainer;
private FrameLayout mBigClockContainer;
private TextClock mBigClock;
- private StatusBarStateController.StateListener mStateListener;
@Mock
TextClock mClockView;
@@ -108,7 +105,6 @@ public class KeyguardClockSwitchTest extends SysuiTestCase {
mBigClock = new TextClock(getContext());
MockitoAnnotations.initMocks(this);
when(mClockView.getPaint()).thenReturn(mock(TextPaint.class));
- mStateListener = mKeyguardClockSwitch.getStateListener();
}
@Test
@@ -117,7 +113,7 @@ public class KeyguardClockSwitchTest extends SysuiTestCase {
TextClock pluginView = new TextClock(getContext());
when(plugin.getView()).thenReturn(pluginView);
- mKeyguardClockSwitch.getClockChangedListener().onClockChanged(plugin);
+ mKeyguardClockSwitch.setClockPlugin(plugin, StatusBarState.KEYGUARD);
verify(mClockView).setVisibility(GONE);
assertThat(plugin.getView().getParent()).isEqualTo(mClockContainer);
@@ -127,14 +123,14 @@ public class KeyguardClockSwitchTest extends SysuiTestCase {
public void onPluginConnected_showPluginBigClock() {
// GIVEN that the container for the big clock has visibility GONE
mBigClockContainer.setVisibility(GONE);
- mKeyguardClockSwitch.setBigClockContainer(mBigClockContainer);
+ mKeyguardClockSwitch.setBigClockContainer(mBigClockContainer, StatusBarState.KEYGUARD);
// AND the plugin returns a view for the big clock
ClockPlugin plugin = mock(ClockPlugin.class);
when(plugin.getBigClockView()).thenReturn(mBigClock);
// AND in the keyguard state
- mStateListener.onStateChanged(StatusBarState.KEYGUARD);
+ mKeyguardClockSwitch.updateBigClockVisibility(StatusBarState.KEYGUARD);
// WHEN the plugin is connected
- mKeyguardClockSwitch.getClockChangedListener().onClockChanged(plugin);
+ mKeyguardClockSwitch.setClockPlugin(plugin, StatusBarState.KEYGUARD);
// THEN the big clock container is visible and it is the parent of the
// big clock view.
assertThat(mBigClockContainer.getVisibility()).isEqualTo(View.VISIBLE);
@@ -144,7 +140,7 @@ public class KeyguardClockSwitchTest extends SysuiTestCase {
@Test
public void onPluginConnected_nullView() {
ClockPlugin plugin = mock(ClockPlugin.class);
- mKeyguardClockSwitch.getClockChangedListener().onClockChanged(plugin);
+ mKeyguardClockSwitch.setClockPlugin(plugin, StatusBarState.KEYGUARD);
verify(mClockView, never()).setVisibility(GONE);
}
@@ -153,11 +149,11 @@ public class KeyguardClockSwitchTest extends SysuiTestCase {
// GIVEN a plugin has already connected
ClockPlugin plugin1 = mock(ClockPlugin.class);
when(plugin1.getView()).thenReturn(new TextClock(getContext()));
- mKeyguardClockSwitch.getClockChangedListener().onClockChanged(plugin1);
+ mKeyguardClockSwitch.setClockPlugin(plugin1, StatusBarState.KEYGUARD);
// WHEN a second plugin is connected
ClockPlugin plugin2 = mock(ClockPlugin.class);
when(plugin2.getView()).thenReturn(new TextClock(getContext()));
- mKeyguardClockSwitch.getClockChangedListener().onClockChanged(plugin2);
+ mKeyguardClockSwitch.setClockPlugin(plugin2, StatusBarState.KEYGUARD);
// THEN only the view from the second plugin should be a child of KeyguardClockSwitch.
assertThat(plugin2.getView().getParent()).isEqualTo(mClockContainer);
assertThat(plugin1.getView().getParent()).isNull();
@@ -169,7 +165,7 @@ public class KeyguardClockSwitchTest extends SysuiTestCase {
mKeyguardClockSwitch.setDarkAmount(0.5f);
// WHEN a plugin is connected
ClockPlugin plugin = mock(ClockPlugin.class);
- mKeyguardClockSwitch.getClockChangedListener().onClockChanged(plugin);
+ mKeyguardClockSwitch.setClockPlugin(plugin, StatusBarState.KEYGUARD);
// THEN dark amount should be initalized on the plugin.
verify(plugin).setDarkAmount(0.5f);
}
@@ -181,8 +177,8 @@ public class KeyguardClockSwitchTest extends SysuiTestCase {
when(plugin.getView()).thenReturn(pluginView);
mClockView.setVisibility(GONE);
- mKeyguardClockSwitch.getClockChangedListener().onClockChanged(plugin);
- mKeyguardClockSwitch.getClockChangedListener().onClockChanged(null);
+ mKeyguardClockSwitch.setClockPlugin(plugin, StatusBarState.KEYGUARD);
+ mKeyguardClockSwitch.setClockPlugin(null, StatusBarState.KEYGUARD);
verify(mClockView).setVisibility(VISIBLE);
assertThat(plugin.getView().getParent()).isNull();
@@ -193,16 +189,16 @@ public class KeyguardClockSwitchTest extends SysuiTestCase {
// GIVEN that the big clock container is visible
FrameLayout bigClockContainer = new FrameLayout(getContext());
bigClockContainer.setVisibility(VISIBLE);
- mKeyguardClockSwitch.setBigClockContainer(bigClockContainer);
+ mKeyguardClockSwitch.setBigClockContainer(bigClockContainer, StatusBarState.KEYGUARD);
// AND the plugin returns a view for the big clock
ClockPlugin plugin = mock(ClockPlugin.class);
TextClock pluginView = new TextClock(getContext());
when(plugin.getBigClockView()).thenReturn(pluginView);
// AND in the keyguard state
- mStateListener.onStateChanged(StatusBarState.KEYGUARD);
+ mKeyguardClockSwitch.updateBigClockVisibility(StatusBarState.KEYGUARD);
// WHEN the plugin is connected and then disconnected
- mKeyguardClockSwitch.getClockChangedListener().onClockChanged(plugin);
- mKeyguardClockSwitch.getClockChangedListener().onClockChanged(null);
+ mKeyguardClockSwitch.setClockPlugin(plugin, StatusBarState.KEYGUARD);
+ mKeyguardClockSwitch.setClockPlugin(null, StatusBarState.KEYGUARD);
// THEN the big lock container is GONE and the big clock view doesn't have
// a parent.
assertThat(bigClockContainer.getVisibility()).isEqualTo(GONE);
@@ -212,8 +208,8 @@ public class KeyguardClockSwitchTest extends SysuiTestCase {
@Test
public void onPluginDisconnected_nullView() {
ClockPlugin plugin = mock(ClockPlugin.class);
- mKeyguardClockSwitch.getClockChangedListener().onClockChanged(plugin);
- mKeyguardClockSwitch.getClockChangedListener().onClockChanged(null);
+ mKeyguardClockSwitch.setClockPlugin(plugin, StatusBarState.KEYGUARD);
+ mKeyguardClockSwitch.setClockPlugin(null, StatusBarState.KEYGUARD);
verify(mClockView, never()).setVisibility(GONE);
}
@@ -222,13 +218,12 @@ public class KeyguardClockSwitchTest extends SysuiTestCase {
// GIVEN two plugins are connected
ClockPlugin plugin1 = mock(ClockPlugin.class);
when(plugin1.getView()).thenReturn(new TextClock(getContext()));
- ClockManager.ClockChangedListener listener = mKeyguardClockSwitch.getClockChangedListener();
- listener.onClockChanged(plugin1);
+ mKeyguardClockSwitch.setClockPlugin(plugin1, StatusBarState.KEYGUARD);
ClockPlugin plugin2 = mock(ClockPlugin.class);
when(plugin2.getView()).thenReturn(new TextClock(getContext()));
- listener.onClockChanged(plugin2);
+ mKeyguardClockSwitch.setClockPlugin(plugin2, StatusBarState.KEYGUARD);
// WHEN the second plugin is disconnected
- listener.onClockChanged(null);
+ mKeyguardClockSwitch.setClockPlugin(null, StatusBarState.KEYGUARD);
// THEN the default clock should be shown.
verify(mClockView).setVisibility(VISIBLE);
assertThat(plugin1.getView().getParent()).isNull();
@@ -240,10 +235,9 @@ public class KeyguardClockSwitchTest extends SysuiTestCase {
// GIVEN a plugin is connected
ClockPlugin clockPlugin = mock(ClockPlugin.class);
when(clockPlugin.getView()).thenReturn(new TextClock(getContext()));
- ClockManager.ClockChangedListener listener = mKeyguardClockSwitch.getClockChangedListener();
- listener.onClockChanged(clockPlugin);
+ mKeyguardClockSwitch.setClockPlugin(clockPlugin, StatusBarState.KEYGUARD);
// WHEN the plugin is disconnected
- listener.onClockChanged(null);
+ mKeyguardClockSwitch.setClockPlugin(null, StatusBarState.KEYGUARD);
// THEN onDestroyView is called on the plugin
verify(clockPlugin).onDestroyView();
}
@@ -260,7 +254,7 @@ public class KeyguardClockSwitchTest extends SysuiTestCase {
ClockPlugin plugin = mock(ClockPlugin.class);
TextClock pluginView = new TextClock(getContext());
when(plugin.getView()).thenReturn(pluginView);
- mKeyguardClockSwitch.getClockChangedListener().onClockChanged(plugin);
+ mKeyguardClockSwitch.setClockPlugin(plugin, StatusBarState.KEYGUARD);
mKeyguardClockSwitch.setTextColor(Color.WHITE);
@@ -284,7 +278,7 @@ public class KeyguardClockSwitchTest extends SysuiTestCase {
TextClock pluginView = new TextClock(getContext());
when(plugin.getView()).thenReturn(pluginView);
Style style = mock(Style.class);
- mKeyguardClockSwitch.getClockChangedListener().onClockChanged(plugin);
+ mKeyguardClockSwitch.setClockPlugin(plugin, StatusBarState.KEYGUARD);
mKeyguardClockSwitch.setStyle(style);
@@ -295,9 +289,9 @@ public class KeyguardClockSwitchTest extends SysuiTestCase {
public void onStateChanged_GoneInShade() {
// GIVEN that the big clock container is visible
mBigClockContainer.setVisibility(View.VISIBLE);
- mKeyguardClockSwitch.setBigClockContainer(mBigClockContainer);
+ mKeyguardClockSwitch.setBigClockContainer(mBigClockContainer, StatusBarState.KEYGUARD);
// WHEN transitioned to SHADE state
- mStateListener.onStateChanged(StatusBarState.SHADE);
+ mKeyguardClockSwitch.updateBigClockVisibility(StatusBarState.SHADE);
// THEN the container is gone.
assertThat(mBigClockContainer.getVisibility()).isEqualTo(View.GONE);
}
@@ -306,13 +300,13 @@ public class KeyguardClockSwitchTest extends SysuiTestCase {
public void onStateChanged_VisibleInKeyguard() {
// GIVEN that the big clock container is gone
mBigClockContainer.setVisibility(View.GONE);
- mKeyguardClockSwitch.setBigClockContainer(mBigClockContainer);
+ mKeyguardClockSwitch.setBigClockContainer(mBigClockContainer, StatusBarState.KEYGUARD);
// AND GIVEN that a plugin is active.
ClockPlugin plugin = mock(ClockPlugin.class);
when(plugin.getBigClockView()).thenReturn(mBigClock);
- mKeyguardClockSwitch.getClockChangedListener().onClockChanged(plugin);
+ mKeyguardClockSwitch.setClockPlugin(plugin, StatusBarState.KEYGUARD);
// WHEN transitioned to KEYGUARD state
- mStateListener.onStateChanged(StatusBarState.KEYGUARD);
+ mKeyguardClockSwitch.updateBigClockVisibility(StatusBarState.KEYGUARD);
// THEN the container is visible.
assertThat(mBigClockContainer.getVisibility()).isEqualTo(View.VISIBLE);
}
@@ -324,11 +318,11 @@ public class KeyguardClockSwitchTest extends SysuiTestCase {
// AND GIVEN that a plugin is active.
ClockPlugin plugin = mock(ClockPlugin.class);
when(plugin.getBigClockView()).thenReturn(mBigClock);
- mKeyguardClockSwitch.getClockChangedListener().onClockChanged(plugin);
+ mKeyguardClockSwitch.setClockPlugin(plugin, StatusBarState.KEYGUARD);
// AND in the keyguard state
- mStateListener.onStateChanged(StatusBarState.KEYGUARD);
+ mKeyguardClockSwitch.updateBigClockVisibility(StatusBarState.KEYGUARD);
// WHEN the container is associated with the clock switch
- mKeyguardClockSwitch.setBigClockContainer(mBigClockContainer);
+ mKeyguardClockSwitch.setBigClockContainer(mBigClockContainer, StatusBarState.KEYGUARD);
// THEN the container remains visible.
assertThat(mBigClockContainer.getVisibility()).isEqualTo(View.VISIBLE);
}
@@ -340,11 +334,11 @@ public class KeyguardClockSwitchTest extends SysuiTestCase {
// AND GIVEN that a plugin is active.
ClockPlugin plugin = mock(ClockPlugin.class);
when(plugin.getBigClockView()).thenReturn(mBigClock);
- mKeyguardClockSwitch.getClockChangedListener().onClockChanged(plugin);
+ mKeyguardClockSwitch.setClockPlugin(plugin, StatusBarState.KEYGUARD);
// AND in the keyguard state
- mStateListener.onStateChanged(StatusBarState.KEYGUARD);
+ mKeyguardClockSwitch.updateBigClockVisibility(StatusBarState.KEYGUARD);
// WHEN the container is associated with the clock switch
- mKeyguardClockSwitch.setBigClockContainer(mBigClockContainer);
+ mKeyguardClockSwitch.setBigClockContainer(mBigClockContainer, StatusBarState.KEYGUARD);
// THEN the container is made visible.
assertThat(mBigClockContainer.getVisibility()).isEqualTo(View.VISIBLE);
}
@@ -353,14 +347,14 @@ public class KeyguardClockSwitchTest extends SysuiTestCase {
public void setKeyguardHidingBigClock_gone() {
// GIVEN that the container for the big clock has visibility GONE
mBigClockContainer.setVisibility(GONE);
- mKeyguardClockSwitch.setBigClockContainer(mBigClockContainer);
+ mKeyguardClockSwitch.setBigClockContainer(mBigClockContainer, StatusBarState.KEYGUARD);
// AND the plugin returns a view for the big clock
ClockPlugin plugin = mock(ClockPlugin.class);
when(plugin.getBigClockView()).thenReturn(mBigClock);
// AND in the keyguard state
- mStateListener.onStateChanged(StatusBarState.KEYGUARD);
+ mKeyguardClockSwitch.updateBigClockVisibility(StatusBarState.KEYGUARD);
// WHEN the plugin is connected
- mKeyguardClockSwitch.getClockChangedListener().onClockChanged(plugin);
+ mKeyguardClockSwitch.setClockPlugin(plugin, StatusBarState.KEYGUARD);
// WHEN the container set hiding clock as true
mKeyguardClockSwitch.setKeyguardHidingBigClock(true);
// THEN the container is gone.
@@ -371,14 +365,14 @@ public class KeyguardClockSwitchTest extends SysuiTestCase {
public void setKeyguardHidingBigClock_visible() {
// GIVEN that the container for the big clock has visibility GONE
mBigClockContainer.setVisibility(GONE);
- mKeyguardClockSwitch.setBigClockContainer(mBigClockContainer);
+ mKeyguardClockSwitch.setBigClockContainer(mBigClockContainer, StatusBarState.KEYGUARD);
// AND the plugin returns a view for the big clock
ClockPlugin plugin = mock(ClockPlugin.class);
when(plugin.getBigClockView()).thenReturn(mBigClock);
// AND in the keyguard state
- mStateListener.onStateChanged(StatusBarState.KEYGUARD);
+ mKeyguardClockSwitch.updateBigClockVisibility(StatusBarState.KEYGUARD);
// WHEN the plugin is connected
- mKeyguardClockSwitch.getClockChangedListener().onClockChanged(plugin);
+ mKeyguardClockSwitch.setClockPlugin(plugin, StatusBarState.KEYGUARD);
// WHEN the container set hiding clock as false
mKeyguardClockSwitch.setKeyguardHidingBigClock(false);
// THEN the container is made visible.
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
index 4a8ada09b3d2..a0e5f73b6a4c 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
@@ -777,7 +777,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
private Intent putPhoneInfo(Intent intent, Bundle data, Boolean simInited) {
int subscription = simInited
- ? 1/* mock subid=1 */ : SubscriptionManager.DUMMY_SUBSCRIPTION_ID_BASE;
+ ? 1/* mock subid=1 */ : SubscriptionManager.PLACEHOLDER_SUBSCRIPTION_ID_BASE;
if (data != null) intent.putExtras(data);
intent.putExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, subscription);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/DependencyTest.java b/packages/SystemUI/tests/src/com/android/systemui/DependencyTest.java
index 475ddc1ea11a..35be496d1a2c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/DependencyTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/DependencyTest.java
@@ -46,9 +46,8 @@ public class DependencyTest extends SysuiTestCase {
@Test
public void testInitDependency() {
Dependency.clearDependencies();
- Dependency dependency = new Dependency();
- SystemUIFactory
- .getInstance().getRootComponent().createDependency().createSystemUI(dependency);
+ Dependency dependency =
+ SystemUIFactory.getInstance().getRootComponent().createDependency();
dependency.start();
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/SysuiBaseFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/SysuiBaseFragmentTest.java
index cf778504190a..3687b4ca7889 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/SysuiBaseFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/SysuiBaseFragmentTest.java
@@ -54,7 +54,10 @@ public abstract class SysuiBaseFragmentTest extends BaseFragmentTest {
@Before
public void SysuiSetup() {
SystemUIFactory.createFromConfig(mContext);
- mDependency = new TestableDependency(mContext);
+ mDependency = new TestableDependency(
+ SystemUIFactory.getInstance().getRootComponent().createDependency());
+ Dependency.setInstance(mDependency);
+
// TODO: Figure out another way to give reference to a SysuiTestableContext.
mSysuiContext = (SysuiTestableContext) mContext;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java b/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java
index b6cc2ee03f38..08e27841de03 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java
@@ -73,7 +73,9 @@ public abstract class SysuiTestCase {
@Before
public void SysuiSetup() throws Exception {
SystemUIFactory.createFromConfig(mContext);
- mDependency = new TestableDependency(mContext);
+ mDependency = new TestableDependency(
+ SystemUIFactory.getInstance().getRootComponent().createDependency());
+ Dependency.setInstance(mDependency);
mFakeBroadcastDispatcher = new FakeBroadcastDispatcher(mContext, mock(Looper.class),
mock(Executor.class), mock(DumpManager.class),
mock(BroadcastDispatcherLogger.class));
diff --git a/packages/SystemUI/tests/src/com/android/systemui/TestableDependency.java b/packages/SystemUI/tests/src/com/android/systemui/TestableDependency.java
index a7f4fa5768b4..ee52c7804b69 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/TestableDependency.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/TestableDependency.java
@@ -16,7 +16,6 @@ package com.android.systemui;
import static org.mockito.Mockito.mock;
-import android.content.Context;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Log;
@@ -26,13 +25,10 @@ public class TestableDependency extends Dependency {
private final ArrayMap<Object, Object> mObjs = new ArrayMap<>();
private final ArraySet<Object> mInstantiatedObjects = new ArraySet<>();
+ private final Dependency mParent;
- public TestableDependency(Context context) {
- SystemUIFactory.createFromConfig(context);
- SystemUIFactory.getInstance().getRootComponent()
- .createDependency()
- .createSystemUI(this);
- start();
+ public TestableDependency(Dependency parent) {
+ mParent = parent;
}
public <T> T injectMockDependency(Class<T> cls) {
@@ -53,11 +49,11 @@ public class TestableDependency extends Dependency {
}
@Override
- protected <T> T createDependency(Object key) {
+ public <T> T createDependency(Object key) {
if (mObjs.containsKey(key)) return (T) mObjs.get(key);
mInstantiatedObjects.add(key);
- return super.createDependency(key);
+ return mParent.createDependency(key);
}
@Override
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationModeSwitchTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationModeSwitchTest.java
index 71f3d5bee225..ee151c441b68 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationModeSwitchTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationModeSwitchTest.java
@@ -32,6 +32,7 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.Context;
+import android.content.pm.ActivityInfo;
import android.provider.Settings;
import android.testing.AndroidTestingRunner;
import android.view.View;
@@ -61,6 +62,7 @@ public class MagnificationModeSwitchTest extends SysuiTestCase {
@Mock
private ViewPropertyAnimator mViewPropertyAnimator;
private MagnificationModeSwitch mMagnificationModeSwitch;
+
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
@@ -111,6 +113,15 @@ public class MagnificationModeSwitchTest extends SysuiTestCase {
}
@Test
+ public void onConfigurationChanged_setImageResource() {
+ mMagnificationModeSwitch.showButton(ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN);
+ mMagnificationModeSwitch.onConfigurationChanged(ActivityInfo.CONFIG_DENSITY);
+
+ verify(mMockImageView, times(2)).setImageResource(
+ getIconResId(ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN));
+ }
+
+ @Test
public void performClick_fullscreenMode_removeViewAndChangeSettingsValue() {
ArgumentCaptor<View.OnClickListener> captor = ArgumentCaptor.forClass(
View.OnClickListener.class);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/ModeSwitchesControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/ModeSwitchesControllerTest.java
index 69482791ef23..9fa5b87af3b4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/ModeSwitchesControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/ModeSwitchesControllerTest.java
@@ -16,10 +16,10 @@
package com.android.systemui.accessibility;
-import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
+import android.content.pm.ActivityInfo;
+import android.hardware.display.DisplayManager;
import android.provider.Settings;
import android.testing.AndroidTestingRunner;
import android.view.Display;
@@ -39,8 +39,7 @@ import org.mockito.MockitoAnnotations;
/** Tests the ModeSwitchesController. */
public class ModeSwitchesControllerTest extends SysuiTestCase {
- @Mock
- private ModeSwitchesController.SwitchSupplier mSupplier;
+ private FakeSwitchSupplier mSupplier;
@Mock
private MagnificationModeSwitch mModeSwitch;
private ModeSwitchesController mModeSwitchesController;
@@ -49,7 +48,7 @@ public class ModeSwitchesControllerTest extends SysuiTestCase {
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
- when(mSupplier.get(anyInt())).thenReturn(mModeSwitch);
+ mSupplier = new FakeSwitchSupplier(mContext.getSystemService(DisplayManager.class));
mModeSwitchesController = new ModeSwitchesController(mSupplier);
}
@@ -70,4 +69,25 @@ public class ModeSwitchesControllerTest extends SysuiTestCase {
verify(mModeSwitch).removeButton();
}
+
+ @Test
+ public void testControllerOnConfigurationChanged_notifyShowingButton() {
+ mModeSwitchesController.showButton(Display.DEFAULT_DISPLAY,
+ Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW);
+ mModeSwitchesController.onConfigurationChanged(ActivityInfo.CONFIG_DENSITY);
+
+ verify(mModeSwitch).onConfigurationChanged(ActivityInfo.CONFIG_DENSITY);
+ }
+
+ private class FakeSwitchSupplier extends DisplayIdIndexSupplier<MagnificationModeSwitch> {
+
+ FakeSwitchSupplier(DisplayManager displayManager) {
+ super(displayManager);
+ }
+
+ @Override
+ protected MagnificationModeSwitch createInstance(Display display) {
+ return mModeSwitch;
+ }
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
index a898c3ce2773..2007fbb8fc6c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
@@ -16,13 +16,19 @@
package com.android.systemui.accessibility;
+import static android.view.Choreographer.FrameCallback;
+
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
import android.app.Instrumentation;
import android.os.Handler;
import android.testing.AndroidTestingRunner;
+import android.view.SurfaceControl;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
@@ -49,6 +55,8 @@ public class WindowMagnificationControllerTest extends SysuiTestCase {
MirrorWindowControl mMirrorWindowControl;
@Mock
WindowMagnifierCallback mWindowMagnifierCallback;
+ @Mock
+ SurfaceControl.Transaction mTransaction;
private WindowMagnificationController mWindowMagnificationController;
private Instrumentation mInstrumentation;
@@ -56,9 +64,19 @@ public class WindowMagnificationControllerTest extends SysuiTestCase {
public void setUp() {
MockitoAnnotations.initMocks(this);
mInstrumentation = InstrumentationRegistry.getInstrumentation();
+ doAnswer(invocation -> {
+ FrameCallback callback = invocation.getArgument(0);
+ callback.doFrame(0);
+ return null;
+ }).when(mSfVsyncFrameProvider).postFrameCallback(
+ any(FrameCallback.class));
+ when(mTransaction.remove(any())).thenReturn(mTransaction);
+ when(mTransaction.setGeometry(any(), any(), any(),
+ anyInt())).thenReturn(mTransaction);
+
mWindowMagnificationController = new WindowMagnificationController(getContext(),
mHandler, mSfVsyncFrameProvider,
- mMirrorWindowControl, mWindowMagnifierCallback);
+ mMirrorWindowControl, mTransaction, mWindowMagnifierCallback);
verify(mMirrorWindowControl).setWindowDelegate(
any(MirrorWindowControl.MirrorWindowDelegate.class));
}
@@ -71,7 +89,7 @@ public class WindowMagnificationControllerTest extends SysuiTestCase {
}
@Test
- public void createWindowMagnification_showControl() {
+ public void enableWindowMagnification_showControl() {
mInstrumentation.runOnMainSync(() -> {
mWindowMagnificationController.enableWindowMagnification(Float.NaN, Float.NaN,
Float.NaN);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationTest.java
index 61a2c3f519cb..41360130ac65 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationTest.java
@@ -17,10 +17,12 @@
package com.android.systemui.accessibility;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.verify;
import android.content.Context;
+import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.RemoteException;
import android.testing.AndroidTestingRunner;
@@ -96,4 +98,13 @@ public class WindowMagnificationTest extends SysuiTestCase {
verify(connectionCallback).onWindowMagnifierBoundsChanged(Display.DEFAULT_DISPLAY,
testBounds);
}
+
+ @Test
+ public void onConfigurationChanged_updateModeSwitches() {
+ final Configuration config = new Configuration();
+ config.densityDpi = Configuration.DENSITY_DPI_ANY;
+ mWindowMagnification.onConfigurationChanged(config);
+
+ verify(mModeSwitchesController).onConfigurationChanged(anyInt());
+ }
}
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 15828b41cc7c..b7589534a770 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
@@ -321,7 +321,7 @@ public class BubbleControllerTest extends SysuiTestCase {
Bubble b = mBubbleData.getOverflowBubbleWithKey(mRow.getEntry().getKey());
assertThat(mBubbleData.getOverflowBubbles()).isEqualTo(ImmutableList.of(b));
verify(mNotificationEntryManager, never()).performRemoveNotification(
- eq(mRow.getEntry().getSbn()), anyInt());
+ eq(mRow.getEntry().getSbn()), any(), anyInt());
assertThat(mRow.getEntry().isBubble()).isFalse();
Bubble b2 = mBubbleData.getBubbleInStackWithKey(mRow2.getEntry().getKey());
@@ -352,7 +352,7 @@ public class BubbleControllerTest extends SysuiTestCase {
mBubbleController.removeBubble(
mRow.getEntry().getKey(), BubbleController.DISMISS_NOTIF_CANCEL);
verify(mNotificationEntryManager, times(1)).performRemoveNotification(
- eq(mRow.getEntry().getSbn()), anyInt());
+ eq(mRow.getEntry().getSbn()), any(), anyInt());
assertThat(mBubbleData.getOverflowBubbles()).isEmpty();
assertFalse(mRow.getEntry().isBubble());
}
@@ -365,7 +365,7 @@ public class BubbleControllerTest extends SysuiTestCase {
mBubbleController.removeBubble(
mRow.getEntry().getKey(), BubbleController.DISMISS_USER_CHANGED);
verify(mNotificationEntryManager, never()).performRemoveNotification(
- eq(mRow.getEntry().getSbn()), anyInt());
+ eq(mRow.getEntry().getSbn()), any(), anyInt());
assertFalse(mBubbleController.hasBubbles());
assertFalse(mSysUiStateBubblesExpanded);
assertTrue(mRow.getEntry().isBubble());
@@ -873,7 +873,7 @@ public class BubbleControllerTest extends SysuiTestCase {
mRow2.getEntry().getKey(), BubbleController.DISMISS_USER_GESTURE);
// Overflow max of 1 is reached; mRow is oldest, so it gets removed
verify(mNotificationEntryManager, times(1)).performRemoveNotification(
- mRow.getEntry().getSbn(), REASON_CANCEL);
+ eq(mRow.getEntry().getSbn()), any(), eq(REASON_CANCEL));
assertEquals(mBubbleData.getBubbles().size(), 1);
assertEquals(mBubbleData.getOverflowBubbles().size(), 1);
}
@@ -985,11 +985,13 @@ public class BubbleControllerTest extends SysuiTestCase {
// THEN only the NON-bubble children are dismissed
List<ExpandableNotificationRow> childrenRows = groupSummary.getAttachedChildren();
verify(mNotificationEntryManager, times(1)).performRemoveNotification(
- childrenRows.get(0).getEntry().getSbn(), REASON_GROUP_SUMMARY_CANCELED);
+ eq(childrenRows.get(0).getEntry().getSbn()), any(),
+ eq(REASON_GROUP_SUMMARY_CANCELED));
verify(mNotificationEntryManager, times(1)).performRemoveNotification(
- childrenRows.get(1).getEntry().getSbn(), REASON_GROUP_SUMMARY_CANCELED);
+ eq(childrenRows.get(1).getEntry().getSbn()), any(),
+ eq(REASON_GROUP_SUMMARY_CANCELED));
verify(mNotificationEntryManager, never()).performRemoveNotification(
- eq(groupedBubble.getEntry().getSbn()), anyInt());
+ eq(groupedBubble.getEntry().getSbn()), any(), anyInt());
// THEN the bubble child is suppressed from the shade
assertTrue(mBubbleController.isBubbleNotificationSuppressedFromShade(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java
index 686a09444ee6..43bf19111049 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java
@@ -26,6 +26,7 @@ import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
@@ -301,7 +302,7 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
assertTrue(mBubbleData.hasOverflowBubbleWithKey(mRow.getEntry().getKey()));
// We don't remove the notification since the bubble is still in overflow.
- verify(mNotifCallback, never()).removeNotification(eq(mRow.getEntry()), anyInt());
+ verify(mNotifCallback, never()).removeNotification(eq(mRow.getEntry()), any(), anyInt());
assertFalse(mBubbleController.hasBubbles());
}
@@ -325,7 +326,8 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
// Since the notif is dismissed and not in overflow, once the bubble is removed,
// removeNotification gets called to really remove the notif
- verify(mNotifCallback, times(1)).removeNotification(eq(mRow.getEntry()), anyInt());
+ verify(mNotifCallback, times(1)).removeNotification(eq(mRow.getEntry()),
+ any(), anyInt());
assertFalse(mBubbleController.hasBubbles());
}
@@ -831,10 +833,11 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase {
// THEN only the NON-bubble children are dismissed
List<ExpandableNotificationRow> childrenRows = groupSummary.getAttachedChildren();
verify(mNotifCallback, times(1)).removeNotification(
- childrenRows.get(0).getEntry(), REASON_GROUP_SUMMARY_CANCELED);
+ eq(childrenRows.get(0).getEntry()), any(), eq(REASON_GROUP_SUMMARY_CANCELED));
verify(mNotifCallback, times(1)).removeNotification(
- childrenRows.get(1).getEntry(), REASON_GROUP_SUMMARY_CANCELED);
- verify(mNotifCallback, never()).removeNotification(eq(groupedBubble.getEntry()), anyInt());
+ eq(childrenRows.get(1).getEntry()), any(), eq(REASON_GROUP_SUMMARY_CANCELED));
+ verify(mNotifCallback, never()).removeNotification(eq(groupedBubble.getEntry()),
+ any(), anyInt());
// THEN the bubble child still exists as a bubble and is suppressed from the shade
assertTrue(mBubbleData.hasBubbleInStackWithKey(groupedBubble.getEntry().getKey()));
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/SeekBarObserverTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/SeekBarObserverTest.kt
index 71554608f04b..7d8728e4acab 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/SeekBarObserverTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/SeekBarObserverTest.kt
@@ -94,11 +94,11 @@ public class SeekBarObserverTest : SysuiTestCase() {
@Test
fun seekBarProgress() {
- // WHEN seek bar progress is about half
+ // WHEN part of the track has been played
val data = SeekBarViewModel.Progress(true, true, 3000, 120000)
observer.onChanged(data)
- // THEN seek bar is visible
- assertThat(seekBarView.progress).isEqualTo(100)
+ // THEN seek bar shows the progress
+ assertThat(seekBarView.progress).isEqualTo(3000)
assertThat(seekBarView.max).isEqualTo(120000)
assertThat(elapsedTimeView.getText()).isEqualTo("00:03")
assertThat(totalTimeView.getText()).isEqualTo("02:00")
diff --git a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedAnimationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedAnimationControllerTest.java
index 583d0692565f..73164b520b9d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedAnimationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedAnimationControllerTest.java
@@ -44,6 +44,7 @@ public class OneHandedAnimationControllerTest extends OneHandedTestCase {
private static final int TEST_BOUNDS_HEIGHT = 1000;
OneHandedAnimationController mOneHandedAnimationController;
+ OneHandedTutorialHandler mTutorialHandler;
@Mock
private SurfaceControl mMockLeash;
@@ -52,6 +53,7 @@ public class OneHandedAnimationControllerTest extends OneHandedTestCase {
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
+ mTutorialHandler = new OneHandedTutorialHandler(mContext);
mOneHandedAnimationController = new OneHandedAnimationController(
new OneHandedSurfaceTransactionHelper(mContext));
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedDisplayAreaOrganizerTest.java b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedDisplayAreaOrganizerTest.java
index 3231b2852e7c..a989cd1f9c40 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedDisplayAreaOrganizerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedDisplayAreaOrganizerTest.java
@@ -61,6 +61,7 @@ public class OneHandedDisplayAreaOrganizerTest extends OneHandedTestCase {
DisplayAreaInfo mDisplayAreaInfo;
Display mDisplay;
OneHandedDisplayAreaOrganizer mDisplayAreaOrganizer;
+ OneHandedTutorialHandler mTutorialHandler;
OneHandedAnimationController.OneHandedTransitionAnimator mFakeAnimator;
WindowContainerToken mToken;
SurfaceControl mLeash;
@@ -97,14 +98,15 @@ public class OneHandedDisplayAreaOrganizerTest extends OneHandedTestCase {
mMockSurfaceTransactionHelper);
when(mMockAnimator.isRunning()).thenReturn(true);
when(mMockAnimator.setDuration(anyInt())).thenReturn(mFakeAnimator);
- when(mMockAnimator.setOneHandedAnimationCallback(any())).thenReturn(mFakeAnimator);
+ when(mMockAnimator.setOneHandedAnimationCallbacks(any())).thenReturn(mFakeAnimator);
when(mMockAnimator.setTransitionDirection(anyInt())).thenReturn(mFakeAnimator);
when(mMockLeash.getWidth()).thenReturn(DISPLAY_WIDTH);
when(mMockLeash.getHeight()).thenReturn(DISPLAY_HEIGHT);
mDisplayAreaOrganizer = new OneHandedDisplayAreaOrganizer(mContext,
mMockDisplayController,
- mMockAnimationController);
+ mMockAnimationController,
+ mTutorialHandler);
mUpdateHandler = mDisplayAreaOrganizer.getUpdateHandler();
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedGestureHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedGestureHandlerTest.java
index 3b284b14c36f..694f51be4e30 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedGestureHandlerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedGestureHandlerTest.java
@@ -48,6 +48,7 @@ import org.mockito.MockitoAnnotations;
public class OneHandedGestureHandlerTest extends OneHandedTestCase {
Instrumentation mInstrumentation;
OneHandedTouchHandler mTouchHandler;
+ OneHandedTutorialHandler mTutorialHandler;
OneHandedGestureHandler mGestureHandler;
OneHandedManagerImpl mOneHandedManagerImpl;
@Mock
@@ -62,13 +63,15 @@ public class OneHandedGestureHandlerTest extends OneHandedTestCase {
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
mInstrumentation = InstrumentationRegistry.getInstrumentation();
- mTouchHandler = Mockito.spy(new OneHandedTouchHandler());
+ mTouchHandler = new OneHandedTouchHandler();
+ mTutorialHandler = new OneHandedTutorialHandler(mContext);
mGestureHandler = Mockito.spy(new OneHandedGestureHandler(
mContext, mMockDisplayController, mMockNavigationModeController));
mOneHandedManagerImpl = new OneHandedManagerImpl(mInstrumentation.getContext(),
mMockDisplayController,
mMockDisplayAreaOrganizer,
mTouchHandler,
+ mTutorialHandler,
mGestureHandler,
mMockSysUiState);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedManagerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedManagerImplTest.java
index 55bec54eacb8..3418ebf75e0c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedManagerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedManagerImplTest.java
@@ -57,6 +57,8 @@ public class OneHandedManagerImplTest extends OneHandedTestCase {
@Mock
OneHandedTouchHandler mMockTouchHandler;
@Mock
+ OneHandedTutorialHandler mMockTutorialHandler;
+ @Mock
OneHandedGestureHandler mMockGestureHandler;
@Mock
SysUiState mMockSysUiState;
@@ -69,6 +71,7 @@ public class OneHandedManagerImplTest extends OneHandedTestCase {
mMockDisplayController,
mMockDisplayAreaOrganizer,
mMockTouchHandler,
+ mMockTutorialHandler,
mMockGestureHandler,
mMockSysUiState);
mTimeoutHandler = Mockito.spy(OneHandedTimeoutHandler.get());
@@ -84,7 +87,7 @@ public class OneHandedManagerImplTest extends OneHandedTestCase {
final OneHandedAnimationController animationController = new OneHandedAnimationController(
transactionHelper);
OneHandedDisplayAreaOrganizer displayAreaOrganizer = new OneHandedDisplayAreaOrganizer(
- mContext, mMockDisplayController, animationController);
+ mContext, mMockDisplayController, animationController, mMockTutorialHandler);
assertThat(displayAreaOrganizer.isInOneHanded()).isFalse();
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedTouchHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedTouchHandlerTest.java
index 3a4ba6a213dc..fdb28d3d43b5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedTouchHandlerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedTouchHandlerTest.java
@@ -46,6 +46,7 @@ import org.mockito.MockitoAnnotations;
public class OneHandedTouchHandlerTest extends OneHandedTestCase {
Instrumentation mInstrumentation;
OneHandedTouchHandler mTouchHandler;
+ OneHandedTutorialHandler mTutorialHandler;
OneHandedGestureHandler mGestureHandler;
OneHandedManagerImpl mOneHandedManagerImpl;
@Mock
@@ -68,13 +69,15 @@ public class OneHandedTouchHandlerTest extends OneHandedTestCase {
mMockDisplayController,
mMockDisplayAreaOrganizer,
mTouchHandler,
+ mTutorialHandler,
mGestureHandler,
mMockSysUiState);
}
@Test
public void testOneHandedManager_registerForDisplayAreaOrganizer() {
- verify(mMockDisplayAreaOrganizer, times(1)).registerTransitionCallback(mTouchHandler);
+ verify(mMockDisplayAreaOrganizer, times(1))
+ .registerTransitionCallback(mTouchHandler);
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedTutorialHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedTutorialHandlerTest.java
new file mode 100644
index 000000000000..f4aa00eaf02f
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedTutorialHandlerTest.java
@@ -0,0 +1,80 @@
+/*
+ * 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.onehanded;
+
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.app.Instrumentation;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.systemui.model.SysUiState;
+import com.android.systemui.statusbar.phone.NavigationModeController;
+import com.android.wm.shell.common.DisplayController;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+public class OneHandedTutorialHandlerTest extends OneHandedTestCase {
+ Instrumentation mInstrumentation;
+ OneHandedTouchHandler mTouchHandler;
+ OneHandedTutorialHandler mTutorialHandler;
+ OneHandedGestureHandler mGestureHandler;
+ OneHandedManagerImpl mOneHandedManagerImpl;
+ @Mock
+ DisplayController mMockDisplayController;
+ @Mock
+ NavigationModeController mMockNavigationModeController;
+ @Mock
+ OneHandedDisplayAreaOrganizer mMockDisplayAreaOrganizer;
+ @Mock
+ SysUiState mMockSysUiState;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mInstrumentation = InstrumentationRegistry.getInstrumentation();
+ mTouchHandler = new OneHandedTouchHandler();
+ mTutorialHandler = Mockito.spy(new OneHandedTutorialHandler(mContext));
+ mGestureHandler = new OneHandedGestureHandler(mContext, mMockDisplayController,
+ mMockNavigationModeController);
+ mOneHandedManagerImpl = new OneHandedManagerImpl(mInstrumentation.getContext(),
+ mMockDisplayController,
+ mMockDisplayAreaOrganizer,
+ mTouchHandler,
+ mTutorialHandler,
+ mGestureHandler,
+ mMockSysUiState);
+ }
+
+ @Test
+ public void testOneHandedManager_registerForDisplayAreaOrganizer() {
+ verify(mMockDisplayAreaOrganizer, times(1))
+ .registerTransitionCallback(mTutorialHandler);
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedUITest.java b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedUITest.java
index 7a234a4d89a7..ffedb07b8db4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedUITest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/onehanded/OneHandedUITest.java
@@ -20,6 +20,7 @@ import static org.mockito.Mockito.any;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
+import android.os.SystemProperties;
import android.provider.Settings;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
@@ -42,6 +43,9 @@ import org.mockito.MockitoAnnotations;
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
public class OneHandedUITest extends OneHandedTestCase {
+ private static final String SUPPORT_ONE_HANDED_MODE = "ro.support_one_handed_mode";
+
+ boolean mIsSupportOneHandedMode;
CommandQueue mCommandQueue;
KeyguardUpdateMonitor mKeyguardUpdateMonitor;
OneHandedUI mOneHandedUI;
@@ -58,6 +62,7 @@ public class OneHandedUITest extends OneHandedTestCase {
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
+ mIsSupportOneHandedMode = SystemProperties.getBoolean(SUPPORT_ONE_HANDED_MODE, false);
mCommandQueue = new CommandQueue(mContext);
mScreenLifecycle = new ScreenLifecycle();
mOneHandedUI = new OneHandedUI(mContext,
@@ -72,6 +77,10 @@ public class OneHandedUITest extends OneHandedTestCase {
@Test
public void testStartOneHanded() {
+ // Bypass test if device not support one-handed mode
+ if (!mIsSupportOneHandedMode) {
+ return;
+ }
mOneHandedUI.startOneHanded();
verify(mMockOneHandedManagerImpl, times(1)).startOneHanded();
@@ -79,6 +88,10 @@ public class OneHandedUITest extends OneHandedTestCase {
@Test
public void testStopOneHanded() {
+ // Bypass test if device not support one-handed mode
+ if (!mIsSupportOneHandedMode) {
+ return;
+ }
mOneHandedUI.stopOneHanded();
verify(mMockOneHandedManagerImpl, times(1)).stopOneHanded();
@@ -86,6 +99,10 @@ public class OneHandedUITest extends OneHandedTestCase {
@Test
public void testRegisterSettingsObserver_forEnabled() {
+ // Bypass test if device not support one-handed mode
+ if (!mIsSupportOneHandedMode) {
+ return;
+ }
final String key = Settings.Secure.ONE_HANDED_MODE_ENABLED;
verify(mMockSettingsUtil, times(1)).registerSettingsKeyObserver(key, any(), any());
@@ -93,6 +110,10 @@ public class OneHandedUITest extends OneHandedTestCase {
@Test
public void testRegisterSettingsObserver_forTimeout() {
+ // Bypass test if device not support one-handed mode
+ if (!mIsSupportOneHandedMode) {
+ return;
+ }
final String key = Settings.Secure.ONE_HANDED_MODE_TIMEOUT;
verify(mMockSettingsUtil, times(1)).registerSettingsKeyObserver(key, any(), any());
@@ -100,6 +121,10 @@ public class OneHandedUITest extends OneHandedTestCase {
@Test
public void testRegisterSettingsObserver_forTapAppExit() {
+ // Bypass test if device not support one-handed mode
+ if (!mIsSupportOneHandedMode) {
+ return;
+ }
final String key = Settings.Secure.TAPS_APP_TO_EXIT;
verify(mMockSettingsUtil, times(1)).registerSettingsKeyObserver(key, any(), any());
@@ -107,6 +132,10 @@ public class OneHandedUITest extends OneHandedTestCase {
@Test
public void tesSettingsObserver_updateTapAppToExit() {
+ // Bypass test if device not support one-handed mode
+ if (!mIsSupportOneHandedMode) {
+ return;
+ }
Settings.Secure.putInt(mContext.getContentResolver(),
Settings.Secure.TAPS_APP_TO_EXIT, 1);
@@ -115,6 +144,10 @@ public class OneHandedUITest extends OneHandedTestCase {
@Test
public void tesSettingsObserver_updateEnabled() {
+ // Bypass test if device not support one-handed mode
+ if (!mIsSupportOneHandedMode) {
+ return;
+ }
Settings.Secure.putInt(mContext.getContentResolver(),
Settings.Secure.ONE_HANDED_MODE_ENABLED, 1);
@@ -123,6 +156,10 @@ public class OneHandedUITest extends OneHandedTestCase {
@Test
public void tesSettingsObserver_updateTimeout() {
+ // Bypass test if device not support one-handed mode
+ if (!mIsSupportOneHandedMode) {
+ return;
+ }
Settings.Secure.putInt(mContext.getContentResolver(),
Settings.Secure.ONE_HANDED_MODE_TIMEOUT,
OneHandedSettingsUtil.ONE_HANDED_TIMEOUT_MEDIUM_IN_SECONDS);
@@ -134,6 +171,10 @@ public class OneHandedUITest extends OneHandedTestCase {
@Ignore("Clarifying do not receive callback")
@Test
public void testKeyguardBouncerShowing_shouldStopOneHanded() {
+ // Bypass test if device not support one-handed mode
+ if (!mIsSupportOneHandedMode) {
+ return;
+ }
mKeyguardUpdateMonitor.sendKeyguardBouncerChanged(true);
verify(mMockOneHandedManagerImpl, times(1)).stopOneHanded();
@@ -141,6 +182,10 @@ public class OneHandedUITest extends OneHandedTestCase {
@Test
public void testScreenTurningOff_shouldStopOneHanded() {
+ // Bypass test if device not support one-handed mode
+ if (!mIsSupportOneHandedMode) {
+ return;
+ }
mScreenLifecycle.dispatchScreenTurningOff();
verify(mMockOneHandedManagerImpl, times(1)).stopOneHanded();
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 4fd5d057c003..6f46923cda5e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java
@@ -55,7 +55,6 @@ import com.android.systemui.statusbar.notification.row.ExpandableView;
import com.android.systemui.statusbar.notification.row.NotificationTestHelper;
import com.android.systemui.statusbar.notification.stack.ForegroundServiceSectionController;
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
-import com.android.systemui.statusbar.notification.stack.NotificationListItem;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
@@ -293,15 +292,9 @@ public class NotificationViewHierarchyManagerTest extends SysuiTestCase {
public void notifyGroupChildAdded(ExpandableView row) {}
@Override
- public void notifyGroupChildAdded(View v) {}
-
- @Override
public void notifyGroupChildRemoved(ExpandableView row, ViewGroup childrenContainer) {}
@Override
- public void notifyGroupChildRemoved(View v, ViewGroup childrenContainer) {}
-
- @Override
public void generateAddAnimation(ExpandableView child, boolean fromMoreCard) {}
@Override
@@ -327,11 +320,6 @@ public class NotificationViewHierarchyManagerTest extends SysuiTestCase {
}
@Override
- public void removeListItem(NotificationListItem li) {
- removeContainerView(li.getView());
- }
-
- @Override
public void setNotificationActivityStarter(
NotificationActivityStarter notificationActivityStarter) {}
@@ -342,8 +330,9 @@ public class NotificationViewHierarchyManagerTest extends SysuiTestCase {
}
@Override
- public void addListItem(NotificationListItem li) {
- addContainerView(li.getView());
+ public void addContainerViewAt(View v, int index) {
+ mLayout.addView(v, index);
+ mRows.add(index, v);
}
@Override
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 8a49326add25..d4718e7e55fa 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
@@ -57,11 +57,11 @@ import android.util.ArraySet;
import androidx.annotation.NonNull;
import androidx.test.filters.SmallTest;
+import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.statusbar.NotificationVisibility;
import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
-import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.NotificationLifetimeExtender;
import com.android.systemui.statusbar.NotificationMediaManager;
@@ -75,6 +75,7 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
import com.android.systemui.statusbar.notification.collection.NotificationRankingManager;
import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinder;
+import com.android.systemui.statusbar.notification.collection.notifcollection.DismissedByUserStats;
import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider;
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
@@ -202,8 +203,7 @@ public class NotificationEntryManagerTest extends SysuiTestCase {
() -> mRemoteInputManager,
mLeakDetector,
mock(ForegroundServiceDismissalFeatureController.class),
- mock(HeadsUpManager.class),
- mock(StatusBarStateController.class)
+ mock(IStatusBarService.class)
);
mEntryManager.setUpWithPresenter(mPresenter);
mEntryManager.addNotificationEntryListener(mEntryListener);
@@ -294,7 +294,8 @@ public class NotificationEntryManagerTest extends SysuiTestCase {
assertTrue(entriesContainKey(mEntryManager.getAllNotifs(), mSbn.getKey()));
// WHEN the uninflated entry is removed
- mEntryManager.performRemoveNotification(mSbn, UNDEFINED_DISMISS_REASON);
+ mEntryManager.performRemoveNotification(mSbn, mock(DismissedByUserStats.class),
+ UNDEFINED_DISMISS_REASON);
// THEN the entry is still removed from the allNotifications list
assertFalse(entriesContainKey(mEntryManager.getAllNotifs(), mSbn.getKey()));
@@ -470,7 +471,8 @@ public class NotificationEntryManagerTest extends SysuiTestCase {
@Test
public void testPerformRemoveNotification_removedEntry() {
mEntryManager.removeNotification(mSbn.getKey(), null, 0);
- mEntryManager.performRemoveNotification(mSbn, REASON_CANCEL);
+ mEntryManager.performRemoveNotification(mSbn, mock(DismissedByUserStats.class),
+ REASON_CANCEL);
}
@Test
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/dagger/DismissRunnable.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/EntryUtil.kt
index 433114224289..62667bc5281f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/dagger/DismissRunnable.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/EntryUtil.kt
@@ -14,17 +14,19 @@
* limitations under the License.
*/
-package com.android.systemui.statusbar.notification.row.dagger;
+package com.android.systemui.statusbar.notification.collection
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-
-import javax.inject.Qualifier;
-
-@Qualifier
-@Documented
-@Retention(RUNTIME)
-public @interface DismissRunnable {
+/**
+ * Modifies a NotificationEntry
+ *
+ * The [modifier] function will be passed an instance of a NotificationEntryBuilder. Any
+ * modifications made to the builder will be applied to the [entry].
+ */
+inline fun modifyEntry(
+ entry: NotificationEntry,
+ crossinline modifier: NotificationEntryBuilder.() -> Unit
+) {
+ val builder = NotificationEntryBuilder(entry)
+ modifier(builder)
+ builder.apply(entry)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/GroupEntryBuilder.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/GroupEntryBuilder.java
new file mode 100644
index 000000000000..2971c05487c6
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/GroupEntryBuilder.java
@@ -0,0 +1,82 @@
+/*
+ * 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;
+
+import androidx.annotation.Nullable;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Builder to construct instances of {@link GroupEntry} for tests.
+ */
+public class GroupEntryBuilder {
+ private String mKey = "test_group_key";
+ private long mCreationTime = 0;
+ @Nullable private GroupEntry mParent = GroupEntry.ROOT_ENTRY;
+ private NotificationEntry mSummary = null;
+ private List<NotificationEntry> mChildren = new ArrayList<>();
+
+ /** Builds a new instance of GroupEntry */
+ public GroupEntry build() {
+ GroupEntry ge = new GroupEntry(mKey, mCreationTime);
+ ge.setParent(mParent);
+
+ ge.setSummary(mSummary);
+ mSummary.setParent(ge);
+
+ for (NotificationEntry child : mChildren) {
+ ge.addChild(child);
+ child.setParent(ge);
+ }
+ return ge;
+ }
+
+ public GroupEntryBuilder setKey(String key) {
+ mKey = key;
+ return this;
+ }
+
+ public GroupEntryBuilder setCreationTime(long creationTime) {
+ mCreationTime = creationTime;
+ return this;
+ }
+
+ public GroupEntryBuilder setParent(@Nullable GroupEntry entry) {
+ mParent = entry;
+ return this;
+ }
+
+ public GroupEntryBuilder setSummary(
+ NotificationEntry summary) {
+ mSummary = summary;
+ return this;
+ }
+
+ public GroupEntryBuilder setChildren(List<NotificationEntry> children) {
+ mChildren.clear();
+ mChildren.addAll(children);
+ return this;
+ }
+
+ /** Adds a child to the existing list of children */
+ public GroupEntryBuilder addChild(NotificationEntry entry) {
+ mChildren.add(entry);
+ return this;
+ }
+
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/GroupEntryHelper.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/GroupEntryHelper.java
deleted file mode 100644
index 038dd17a9814..000000000000
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/GroupEntryHelper.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.statusbar.notification.collection;
-
-import java.util.List;
-
-/**
- * Helper class to provide methods for test classes that need {@link GroupEntry}'s for their tests.
- */
-public class GroupEntryHelper {
- /**
- * Create a group entry for testing purposes.
- * @param groupKey group key for the group and all its entries
- * @param summary summary notification for group
- * @param children group's children notifications
- */
- public static final GroupEntry createGroup(
- String groupKey,
- NotificationEntry summary,
- List<NotificationEntry> children) {
- GroupEntry groupEntry = new GroupEntry(groupKey);
- groupEntry.setSummary(summary);
- for (NotificationEntry child : children) {
- groupEntry.addChild(child);
- }
- return groupEntry;
- }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/HighPriorityProviderTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/HighPriorityProviderTest.java
index 2b12c22cae39..386c866cdd03 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/HighPriorityProviderTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/HighPriorityProviderTest.java
@@ -191,9 +191,10 @@ public class HighPriorityProviderTest extends SysuiTestCase {
@Test
public void testIsHighPriority_summaryUpdated() {
// GIVEN a GroupEntry with a lowPrioritySummary and no children
- final GroupEntry parentEntry = new GroupEntry("test_group_key");
final NotificationEntry lowPrioritySummary = createNotifEntry(false);
- setSummary(parentEntry, lowPrioritySummary);
+ final GroupEntry parentEntry = new GroupEntryBuilder()
+ .setSummary(lowPrioritySummary)
+ .build();
assertFalse(mHighPriorityProvider.isHighPriority(parentEntry));
// WHEN the summary changes to high priority
@@ -214,10 +215,11 @@ public class HighPriorityProviderTest extends SysuiTestCase {
// GroupEntry = parentEntry, summary = lowPrioritySummary
// NotificationEntry = lowPriorityChild
// NotificationEntry = highPriorityChild
- final GroupEntry parentEntry = new GroupEntry("test_group_key");
- setSummary(parentEntry, createNotifEntry(false));
- addChild(parentEntry, createNotifEntry(false));
- addChild(parentEntry, createNotifEntry(true));
+ final GroupEntry parentEntry = new GroupEntryBuilder()
+ .setSummary(createNotifEntry(false))
+ .addChild(createNotifEntry(false))
+ .addChild(createNotifEntry(true))
+ .build();
// THEN the GroupEntry parentEntry is high priority since it has a high priority child
assertTrue(mHighPriorityProvider.isHighPriority(parentEntry));
@@ -228,10 +230,11 @@ public class HighPriorityProviderTest extends SysuiTestCase {
// GIVEN:
// GroupEntry = parentEntry, summary = lowPrioritySummary
// NotificationEntry = lowPriorityChild
- final GroupEntry parentEntry = new GroupEntry("test_group_key");
final NotificationEntry lowPriorityChild = createNotifEntry(false);
- setSummary(parentEntry, createNotifEntry(false));
- addChild(parentEntry, lowPriorityChild);
+ final GroupEntry parentEntry = new GroupEntryBuilder()
+ .setSummary(createNotifEntry(false))
+ .addChild(lowPriorityChild)
+ .build();
// WHEN the child entry ranking changes to high priority
lowPriorityChild.setRanking(
@@ -250,14 +253,4 @@ public class HighPriorityProviderTest extends SysuiTestCase {
.setImportance(highPriority ? IMPORTANCE_HIGH : IMPORTANCE_MIN)
.build();
}
-
- private void setSummary(GroupEntry parent, NotificationEntry summary) {
- parent.setSummary(summary);
- summary.setParent(parent);
- }
-
- private void addChild(GroupEntry parent, NotificationEntry child) {
- parent.addChild(child);
- child.setParent(parent);
- }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryBuilder.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryBuilder.java
index 4a7c6c643118..1523653dec3c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryBuilder.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryBuilder.java
@@ -23,6 +23,7 @@ import android.app.NotificationManager;
import android.content.Context;
import android.content.pm.ShortcutInfo;
import android.os.UserHandle;
+import android.service.notification.NotificationListenerService.Ranking;
import android.service.notification.SnoozeCriterion;
import android.service.notification.StatusBarNotification;
@@ -33,6 +34,8 @@ import com.android.systemui.util.time.FakeSystemClock;
import java.util.ArrayList;
+import kotlin.Unit;
+
/**
* Combined builder for constructing a NotificationEntry and its associated StatusBarNotification
* and Ranking. Is largely a proxy for the SBN and Ranking builders, but does a little extra magic
@@ -43,8 +46,8 @@ import java.util.ArrayList;
* Only for use in tests.
*/
public class NotificationEntryBuilder {
- private final SbnBuilder mSbnBuilder = new SbnBuilder();
- private final RankingBuilder mRankingBuilder = new RankingBuilder();
+ private final SbnBuilder mSbnBuilder;
+ private final RankingBuilder mRankingBuilder;
private final FakeSystemClock mClock = new FakeSystemClock();
private StatusBarNotification mSbn = null;
@@ -55,12 +58,49 @@ public class NotificationEntryBuilder {
/* If set, use this creation time instead of mClock.uptimeMillis */
private long mCreationTime = -1;
+ public NotificationEntryBuilder() {
+ mSbnBuilder = new SbnBuilder();
+ mRankingBuilder = new RankingBuilder();
+ }
+
+ public NotificationEntryBuilder(NotificationEntry source) {
+ mSbnBuilder = new SbnBuilder(source.getSbn());
+ mRankingBuilder = new RankingBuilder(source.getRanking());
+
+ mParent = source.getParent();
+ mSection = source.getSection();
+ mCreationTime = source.getCreationTime();
+ }
+
+ /** Build a new instance of NotificationEntry */
public NotificationEntry build() {
- StatusBarNotification sbn = mSbn != null ? mSbn : mSbnBuilder.build();
- mRankingBuilder.setKey(sbn.getKey());
- long creationTime = mCreationTime != -1 ? mCreationTime : mClock.uptimeMillis();
- final NotificationEntry entry = new NotificationEntry(
- sbn, mRankingBuilder.build(), mClock.uptimeMillis());
+ return buildOrApply(null);
+ }
+
+ /** Modifies [target] to match the contents of this builder */
+ public void apply(NotificationEntry target) {
+ buildOrApply(target);
+ }
+
+ /** Convenience method for Kotlin callbacks that are passed a builder and need to return Unit */
+ public Unit done() {
+ return Unit.INSTANCE;
+ }
+
+ private NotificationEntry buildOrApply(NotificationEntry target) {
+ final StatusBarNotification sbn = mSbn != null ? mSbn : mSbnBuilder.build();
+ final Ranking ranking = mRankingBuilder.setKey(sbn.getKey()).build();
+ final long creationTime = mCreationTime != -1 ? mCreationTime : mClock.uptimeMillis();
+
+ final NotificationEntry entry;
+ if (target == null) {
+ entry = new NotificationEntry(sbn, ranking, creationTime);
+ } else {
+ entry = target;
+ entry.setSbn(sbn);
+ entry.setRanking(ranking);
+ // Note: we can't modify the creation time as it's immutable
+ }
/* ListEntry properties */
entry.setParent(mParent);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.java
index f54252effdd3..917c049fd578 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.java
@@ -21,9 +21,10 @@ import static android.app.Notification.VISIBILITY_SECRET;
import static android.app.NotificationManager.IMPORTANCE_HIGH;
import static android.app.NotificationManager.IMPORTANCE_MIN;
-import static junit.framework.Assert.assertFalse;
-import static junit.framework.Assert.assertTrue;
+import static com.android.systemui.statusbar.notification.collection.EntryUtilKt.modifyEntry;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -41,6 +42,7 @@ import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.RankingBuilder;
import com.android.systemui.statusbar.notification.collection.GroupEntry;
+import com.android.systemui.statusbar.notification.collection.GroupEntryBuilder;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
@@ -71,13 +73,12 @@ public class KeyguardCoordinatorTest extends SysuiTestCase {
@Mock private NotifPipeline mNotifPipeline;
private NotificationEntry mEntry;
- private KeyguardCoordinator mKeyguardCoordinator;
private NotifFilter mKeyguardFilter;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
- mKeyguardCoordinator = new KeyguardCoordinator(
+ KeyguardCoordinator keyguardCoordinator = new KeyguardCoordinator(
mContext, mMainHandler, mKeyguardStateController, mLockscreenUserManager,
mBroadcastDispatcher, mStatusBarStateController,
mKeyguardUpdateMonitor, mHighPriorityProvider);
@@ -87,7 +88,7 @@ public class KeyguardCoordinatorTest extends SysuiTestCase {
.build();
ArgumentCaptor<NotifFilter> filterCaptor = ArgumentCaptor.forClass(NotifFilter.class);
- mKeyguardCoordinator.attach(mNotifPipeline);
+ keyguardCoordinator.attach(mNotifPipeline);
verify(mNotifPipeline, times(1)).addFinalizeFilter(filterCaptor.capture());
mKeyguardFilter = filterCaptor.getValue();
}
@@ -186,12 +187,18 @@ public class KeyguardCoordinatorTest extends SysuiTestCase {
public void summaryExceedsThresholdToShow() {
// GIVEN the notification doesn't exceed the threshold to show on the lockscreen
// but it's part of a group (has a parent)
- final GroupEntry parent = new GroupEntry("test_group_key");
final NotificationEntry entryWithParent = new NotificationEntryBuilder()
- .setParent(parent)
.setUser(new UserHandle(NOTIF_USER_ID))
.build();
+ final GroupEntry parent = new GroupEntryBuilder()
+ .setKey("test_group_key")
+ .setSummary(new NotificationEntryBuilder()
+ .setImportance(IMPORTANCE_HIGH)
+ .build())
+ .addChild(entryWithParent)
+ .build();
+
setupUnfilteredState(entryWithParent);
entryWithParent.setRanking(new RankingBuilder()
.setKey(entryWithParent.getKey())
@@ -200,18 +207,15 @@ public class KeyguardCoordinatorTest extends SysuiTestCase {
// WHEN its parent does exceed threshold tot show on the lockscreen
when(mHighPriorityProvider.isHighPriority(parent)).thenReturn(true);
- parent.setSummary(new NotificationEntryBuilder()
- .setImportance(IMPORTANCE_HIGH)
- .build());
// THEN don't filter out the entry
assertFalse(mKeyguardFilter.shouldFilterOut(entryWithParent, 0));
// WHEN its parent doesn't exceed threshold to show on lockscreen
when(mHighPriorityProvider.isHighPriority(parent)).thenReturn(false);
- parent.setSummary(new NotificationEntryBuilder()
+ modifyEntry(parent.getSummary(), builder -> builder
.setImportance(IMPORTANCE_MIN)
- .build());
+ .done());
// THEN filter out the entry
assertTrue(mKeyguardFilter.shouldFilterOut(entryWithParent, 0));
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorTest.java
index faf9da3aca8b..bec5174aceba 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorTest.java
@@ -16,6 +16,8 @@
package com.android.systemui.statusbar.notification.collection.coordinator;
+import static com.android.systemui.statusbar.notification.collection.GroupEntry.ROOT_ENTRY;
+
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
@@ -25,6 +27,8 @@ import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
+import static java.util.Objects.requireNonNull;
+
import android.os.RemoteException;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
@@ -34,15 +38,16 @@ import androidx.test.filters.SmallTest;
import com.android.internal.statusbar.IStatusBarService;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.statusbar.notification.collection.GroupEntry;
-import com.android.systemui.statusbar.notification.collection.GroupEntryHelper;
-import com.android.systemui.statusbar.notification.collection.NotifInflaterImpl;
+import com.android.systemui.statusbar.notification.collection.GroupEntryBuilder;
+import com.android.systemui.statusbar.notification.collection.ListEntry;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
-import com.android.systemui.statusbar.notification.collection.NotifViewBarn;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
+import com.android.systemui.statusbar.notification.collection.inflation.NotifInflater;
import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeFinalizeFilterListener;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
+import com.android.systemui.statusbar.notification.collection.render.NotifViewBarn;
import com.android.systemui.statusbar.notification.row.NotifInflationErrorManager;
import org.junit.Before;
@@ -52,19 +57,17 @@ import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import org.mockito.Spy;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
@SmallTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
public class PreparationCoordinatorTest extends SysuiTestCase {
- private static final String TEST_MESSAGE = "TEST_MESSAGE";
- private static final String TEST_GROUP_KEY = "TEST_GROUP_KEY";
- private static final int TEST_CHILD_BIND_CUTOFF = 9;
-
- private PreparationCoordinator mCoordinator;
private NotifCollectionListener mCollectionListener;
private OnBeforeFinalizeFilterListener mBeforeFilterListener;
private NotifFilter mUninflatedFilter;
@@ -75,30 +78,31 @@ public class PreparationCoordinatorTest extends SysuiTestCase {
@Captor private ArgumentCaptor<NotifCollectionListener> mCollectionListenerCaptor;
@Captor private ArgumentCaptor<OnBeforeFinalizeFilterListener> mBeforeFilterListenerCaptor;
- @Captor private ArgumentCaptor<NotifInflaterImpl.InflationCallback> mCallbackCaptor;
+ @Captor private ArgumentCaptor<NotifInflater.InflationCallback> mCallbackCaptor;
@Mock private NotifPipeline mNotifPipeline;
@Mock private IStatusBarService mService;
- @Mock private NotifInflaterImpl mNotifInflater;
+ @Spy private FakeNotifInflater mNotifInflater = new FakeNotifInflater();
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
- mEntry = new NotificationEntryBuilder().build();
+ mEntry = new NotificationEntryBuilder().setParent(ROOT_ENTRY).build();
mInflationError = new Exception(TEST_MESSAGE);
mErrorManager = new NotifInflationErrorManager();
- mCoordinator = new PreparationCoordinator(
+ PreparationCoordinator coordinator = new PreparationCoordinator(
mock(PreparationCoordinatorLogger.class),
mNotifInflater,
mErrorManager,
mock(NotifViewBarn.class),
mService,
- TEST_CHILD_BIND_CUTOFF);
+ TEST_CHILD_BIND_CUTOFF,
+ TEST_MAX_GROUP_DELAY);
ArgumentCaptor<NotifFilter> filterCaptor = ArgumentCaptor.forClass(NotifFilter.class);
- mCoordinator.attach(mNotifPipeline);
+ coordinator.attach(mNotifPipeline);
verify(mNotifPipeline, times(2)).addFinalizeFilter(filterCaptor.capture());
List<NotifFilter> filters = filterCaptor.getAllValues();
mInflationErrorFilter = filters.get(0);
@@ -127,7 +131,7 @@ public class PreparationCoordinatorTest extends SysuiTestCase {
eq(mEntry.getSbn().getUid()),
eq(mEntry.getSbn().getInitialPid()),
eq(mInflationError.getMessage()),
- eq(mEntry.getSbn().getUserId()));
+ eq(mEntry.getSbn().getUser().getIdentifier()));
}
@Test
@@ -199,7 +203,11 @@ public class PreparationCoordinatorTest extends SysuiTestCase {
.build();
children.add(child);
}
- GroupEntry groupEntry = GroupEntryHelper.createGroup(TEST_GROUP_KEY, summary, children);
+ GroupEntry groupEntry = new GroupEntryBuilder()
+ .setKey(TEST_GROUP_KEY)
+ .setSummary(summary)
+ .setChildren(children)
+ .build();
mCollectionListener.onEntryInit(summary);
for (NotificationEntry entry : children) {
@@ -222,4 +230,139 @@ public class PreparationCoordinatorTest extends SysuiTestCase {
}
}
}
+
+ @Test
+ public void testPartiallyInflatedGroupsAreFilteredOut() {
+ // GIVEN a newly-posted group with a summary and two children
+ final GroupEntry group = new GroupEntryBuilder()
+ .setCreationTime(400)
+ .setSummary(new NotificationEntryBuilder().setId(1).build())
+ .addChild(new NotificationEntryBuilder().setId(2).build())
+ .addChild(new NotificationEntryBuilder().setId(3).build())
+ .build();
+ fireAddEvents(List.of(group));
+ final NotificationEntry child0 = group.getChildren().get(0);
+ mBeforeFilterListener.onBeforeFinalizeFilter(List.of(group));
+
+ // WHEN one of this children finishes inflating
+ mNotifInflater.getInflateCallback(child0).onInflationFinished(child0);
+
+ // THEN the inflated child is still filtered out
+ assertTrue(mUninflatedFilter.shouldFilterOut(child0, 401));
+ }
+
+ @Test
+ public void testPartiallyInflatedGroupsAreFilteredOutSummaryVersion() {
+ // GIVEN a newly-posted group with a summary and two children
+ final GroupEntry group = new GroupEntryBuilder()
+ .setCreationTime(400)
+ .setSummary(new NotificationEntryBuilder().setId(1).build())
+ .addChild(new NotificationEntryBuilder().setId(2).build())
+ .addChild(new NotificationEntryBuilder().setId(3).build())
+ .build();
+ fireAddEvents(List.of(group));
+ final NotificationEntry summary = group.getSummary();
+ final NotificationEntry child0 = group.getChildren().get(0);
+ final NotificationEntry child1 = group.getChildren().get(1);
+ mBeforeFilterListener.onBeforeFinalizeFilter(List.of(group));
+
+ // WHEN all of the children (but not the summary) finish inflating
+ mNotifInflater.getInflateCallback(child0).onInflationFinished(child0);
+ mNotifInflater.getInflateCallback(child1).onInflationFinished(child1);
+
+ // THEN the entire group is still filtered out
+ assertTrue(mUninflatedFilter.shouldFilterOut(summary, 401));
+ assertTrue(mUninflatedFilter.shouldFilterOut(child0, 401));
+ assertTrue(mUninflatedFilter.shouldFilterOut(child1, 401));
+ }
+
+ @Test
+ public void testCompletedInflatedGroupsAreReleased() {
+ // GIVEN a newly-posted group with a summary and two children
+ final GroupEntry group = new GroupEntryBuilder()
+ .setCreationTime(400)
+ .setSummary(new NotificationEntryBuilder().setId(1).build())
+ .addChild(new NotificationEntryBuilder().setId(2).build())
+ .addChild(new NotificationEntryBuilder().setId(3).build())
+ .build();
+ fireAddEvents(List.of(group));
+ final NotificationEntry summary = group.getSummary();
+ final NotificationEntry child0 = group.getChildren().get(0);
+ final NotificationEntry child1 = group.getChildren().get(1);
+ mBeforeFilterListener.onBeforeFinalizeFilter(List.of(group));
+
+ // WHEN all of the children (and the summary) finish inflating
+ mNotifInflater.getInflateCallback(child0).onInflationFinished(child0);
+ mNotifInflater.getInflateCallback(child1).onInflationFinished(child1);
+ mNotifInflater.getInflateCallback(summary).onInflationFinished(summary);
+
+ // THEN the entire group is still filtered out
+ assertFalse(mUninflatedFilter.shouldFilterOut(summary, 401));
+ assertFalse(mUninflatedFilter.shouldFilterOut(child0, 401));
+ assertFalse(mUninflatedFilter.shouldFilterOut(child1, 401));
+ }
+
+ @Test
+ public void testPartiallyInflatedGroupsAreReleasedAfterTimeout() {
+ // GIVEN a newly-posted group with a summary and two children
+ final GroupEntry group = new GroupEntryBuilder()
+ .setCreationTime(400)
+ .setSummary(new NotificationEntryBuilder().setId(1).build())
+ .addChild(new NotificationEntryBuilder().setId(2).build())
+ .addChild(new NotificationEntryBuilder().setId(3).build())
+ .build();
+ fireAddEvents(List.of(group));
+ final NotificationEntry child0 = group.getChildren().get(0);
+ mBeforeFilterListener.onBeforeFinalizeFilter(List.of(group));
+
+ // WHEN one of this children finishes inflating and enough time passes
+ mNotifInflater.getInflateCallback(child0).onInflationFinished(child0);
+
+ // THEN the inflated child is not filtered out even though the rest of the group hasn't
+ // finished inflating yet
+ assertTrue(mUninflatedFilter.shouldFilterOut(child0, TEST_MAX_GROUP_DELAY + 1));
+ }
+
+ private static class FakeNotifInflater implements NotifInflater {
+ private Map<NotificationEntry, InflationCallback> mInflateCallbacks = new HashMap<>();
+
+ @Override
+ public void inflateViews(NotificationEntry entry, InflationCallback callback) {
+ mInflateCallbacks.put(entry, callback);
+ }
+
+ @Override
+ public void rebindViews(NotificationEntry entry, InflationCallback callback) {
+ }
+
+ @Override
+ public void abortInflation(NotificationEntry entry) {
+ }
+
+ public InflationCallback getInflateCallback(NotificationEntry entry) {
+ return requireNonNull(mInflateCallbacks.get(entry));
+ }
+ }
+
+ private void fireAddEvents(List<? extends ListEntry> entries) {
+ for (ListEntry entry : entries) {
+ if (entry instanceof GroupEntry) {
+ GroupEntry ge = (GroupEntry) entry;
+ fireAddEvents(ge.getSummary());
+ fireAddEvents(ge.getChildren());
+ } else {
+ fireAddEvents((NotificationEntry) entry);
+ }
+ }
+ }
+
+ private void fireAddEvents(NotificationEntry entry) {
+ mCollectionListener.onEntryInit(entry);
+ mCollectionListener.onEntryAdded(entry);
+ }
+
+ private static final String TEST_MESSAGE = "TEST_MESSAGE";
+ private static final String TEST_GROUP_KEY = "TEST_GROUP_KEY";
+ private static final int TEST_CHILD_BIND_CUTOFF = 9;
+ private static final int TEST_MAX_GROUP_DELAY = 100;
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java
index 601df2cb4fc7..a90af87064b5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java
@@ -40,6 +40,7 @@ import android.testing.TestableLooper;
import androidx.asynclayoutinflater.view.AsyncLayoutInflater;
import androidx.test.filters.SmallTest;
+import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.util.NotificationMessagingUtil;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
@@ -185,8 +186,7 @@ public class NotificationEntryManagerInflationTest extends SysuiTestCase {
() -> mRemoteInputManager,
mLeakDetector,
mock(ForegroundServiceDismissalFeatureController.class),
- mock(HeadsUpManager.class),
- mock(StatusBarStateController.class)
+ mock(IStatusBarService.class)
);
NotifRemoteViewCache cache = new NotifRemoteViewCacheImpl(mEntryManager);
@@ -252,7 +252,6 @@ public class NotificationEntryManagerInflationTest extends SysuiTestCase {
mLockscreenUserManager,
pipeline,
mRowContentBindStage,
- mNotificationInterruptionStateProvider,
RowInflaterTask::new,
mExpandableNotificationRowComponentBuilder,
new IconManager(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java
index 243503d1d8a6..7ca24789a29b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java
@@ -380,7 +380,7 @@ public class NotificationSectionsManagerTest extends SysuiTestCase {
setupMockStack(
PEOPLE_HEADER,
- ALERTING.headsUp(),
+ ALERTING,
PERSON,
ALERTING_HEADER,
GENTLE_HEADER,
@@ -403,9 +403,9 @@ public class NotificationSectionsManagerTest extends SysuiTestCase {
enablePeopleFiltering();
setupMockStack(
- PERSON.headsUp(),
+ PERSON,
INCOMING_HEADER,
- ALERTING.headsUp(),
+ ALERTING,
PEOPLE_HEADER,
PERSON
);
@@ -425,7 +425,7 @@ public class NotificationSectionsManagerTest extends SysuiTestCase {
enablePeopleFiltering();
setupMockStack(
- PERSON.headsUp(),
+ PERSON,
PEOPLE_HEADER,
PERSON
);
@@ -443,8 +443,8 @@ public class NotificationSectionsManagerTest extends SysuiTestCase {
enablePeopleFiltering();
setupMockStack(
- ALERTING.headsUp(),
- PERSON.headsUp()
+ ALERTING,
+ PERSON
);
mSectionsManager.updateSectionBoundaries();
verifyMockStack(
@@ -461,7 +461,7 @@ public class NotificationSectionsManagerTest extends SysuiTestCase {
setupMockStack(
INCOMING_HEADER,
- ALERTING.headsUp(),
+ ALERTING,
PEOPLE_HEADER,
FSN,
PERSON,
@@ -502,9 +502,9 @@ public class NotificationSectionsManagerTest extends SysuiTestCase {
public void testMediaControls_AddWhenEnterKeyguardWithHeadsUp() {
enableMediaControls();
- // GIVEN a stack that doesn't include media controls but includes HEADS_UP
+ // GIVEN a stack that doesn't include media
setupMockStack(
- ALERTING.headsUp(),
+ ALERTING,
ALERTING,
GENTLE_HEADER,
GENTLE);
@@ -584,6 +584,27 @@ public class NotificationSectionsManagerTest extends SysuiTestCase {
);
}
+ @Test
+ public void testIgnoreGoneView() {
+ enablePeopleFiltering();
+
+ setupMockStack(
+ PERSON.gone(),
+ ALERTING,
+ GENTLE
+ );
+
+ mSectionsManager.updateSectionBoundaries();
+
+ verifyMockStack(
+ ChildType.ALERTING_HEADER,
+ ChildType.PERSON,
+ ChildType.ALERTING,
+ ChildType.GENTLE_HEADER,
+ ChildType.GENTLE
+ );
+ }
+
private void enablePeopleFiltering() {
when(mSectionsFeatureManager.isFilteringEnabled()).thenReturn(true);
}
@@ -619,16 +640,16 @@ public class NotificationSectionsManagerTest extends SysuiTestCase {
child = mSectionsManager.getSilentHeaderView();
break;
case FSN:
- child = mockNotification(BUCKET_FOREGROUND_SERVICE, entry.mIsHeadsUp);
+ child = mockNotification(BUCKET_FOREGROUND_SERVICE, entry.mIsGone);
break;
case PERSON:
- child = mockNotification(BUCKET_PEOPLE, entry.mIsHeadsUp);
+ child = mockNotification(BUCKET_PEOPLE, entry.mIsGone);
break;
case ALERTING:
- child = mockNotification(BUCKET_ALERTING, entry.mIsHeadsUp);
+ child = mockNotification(BUCKET_ALERTING, entry.mIsGone);
break;
case GENTLE:
- child = mockNotification(BUCKET_SILENT, entry.mIsHeadsUp);
+ child = mockNotification(BUCKET_SILENT, entry.mIsGone);
break;
case OTHER:
child = mock(View.class);
@@ -643,7 +664,7 @@ public class NotificationSectionsManagerTest extends SysuiTestCase {
}
}
- private View mockNotification(int bucket, boolean headsUp) {
+ private View mockNotification(int bucket, boolean isGone) {
ExpandableNotificationRow notifRow =
mock(ExpandableNotificationRow.class, RETURNS_DEEP_STUBS);
when(notifRow.getVisibility()).thenReturn(View.VISIBLE);
@@ -659,8 +680,7 @@ public class NotificationSectionsManagerTest extends SysuiTestCase {
return null;
}).when(mockEntry).setBucket(anyInt());
- when(notifRow.isHeadsUp()).thenReturn(headsUp);
- when(mockEntry.isRowHeadsUp()).thenReturn(headsUp);
+ when(notifRow.getVisibility()).thenReturn(isGone ? View.GONE : View.VISIBLE);
return notifRow;
}
@@ -767,16 +787,16 @@ public class NotificationSectionsManagerTest extends SysuiTestCase {
child = mSectionsManager.getSilentHeaderView();
break;
case FSN:
- child = mockNotification(BUCKET_FOREGROUND_SERVICE, entry.mIsHeadsUp);
+ child = mockNotification(BUCKET_FOREGROUND_SERVICE, entry.mIsGone);
break;
case PERSON:
- child = mockNotification(BUCKET_PEOPLE, entry.mIsHeadsUp);
+ child = mockNotification(BUCKET_PEOPLE, entry.mIsGone);
break;
case ALERTING:
- child = mockNotification(BUCKET_ALERTING, entry.mIsHeadsUp);
+ child = mockNotification(BUCKET_ALERTING, entry.mIsGone);
break;
case GENTLE:
- child = mockNotification(BUCKET_SILENT, entry.mIsHeadsUp);
+ child = mockNotification(BUCKET_SILENT, entry.mIsGone);
break;
case OTHER:
child = mock(View.class);
@@ -796,36 +816,25 @@ public class NotificationSectionsManagerTest extends SysuiTestCase {
private static final StackEntry ALERTING_HEADER = new StackEntry(ChildType.ALERTING_HEADER);
private static final StackEntry GENTLE_HEADER = new StackEntry(ChildType.GENTLE_HEADER);
private static final StackEntry FSN = new StackEntry(ChildType.FSN);
- private static final StackEntry.Hunnable PERSON = new StackEntry.Hunnable(ChildType.PERSON);
- private static final StackEntry.Hunnable ALERTING = new StackEntry.Hunnable(ChildType.ALERTING);
+ private static final StackEntry PERSON = new StackEntry(ChildType.PERSON);
+ private static final StackEntry ALERTING = new StackEntry(ChildType.ALERTING);
private static final StackEntry GENTLE = new StackEntry(ChildType.GENTLE);
private static class StackEntry {
final ChildType mChildType;
- final boolean mIsHeadsUp;
+ final boolean mIsGone;
StackEntry(ChildType childType) {
this(childType, false);
}
- StackEntry(ChildType childType, boolean isHeadsUp) {
+ StackEntry(ChildType childType, boolean isGone) {
mChildType = childType;
- mIsHeadsUp = isHeadsUp;
+ mIsGone = isGone;
}
- static class Hunnable extends StackEntry {
-
- Hunnable(ChildType childType) {
- super(childType, false);
- }
-
- Hunnable(ChildType childType, boolean isHeadsUp) {
- super(childType, isHeadsUp);
- }
-
- public Hunnable headsUp() {
- return new Hunnable(mChildType, true);
- }
+ public StackEntry gone() {
+ return new StackEntry(mChildType, true);
}
}
}
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 6d411333b220..ddac2ecbd6eb 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
@@ -49,13 +49,13 @@ import androidx.test.filters.SmallTest;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto;
import com.android.internal.logging.testing.UiEventLoggerFake;
+import com.android.internal.statusbar.IStatusBarService;
import com.android.systemui.ExpandHelper;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.classifier.FalsingManagerFake;
import com.android.systemui.media.KeyguardMediaController;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
-import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.EmptyShadeView;
import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
@@ -93,7 +93,6 @@ import com.android.systemui.statusbar.phone.NotificationIconAreaController;
import com.android.systemui.statusbar.phone.ScrimController;
import com.android.systemui.statusbar.phone.ShadeController;
import com.android.systemui.statusbar.phone.StatusBar;
-import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.statusbar.policy.ZenModeController;
import com.android.systemui.util.leak.LeakDetector;
@@ -193,8 +192,7 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
() -> mRemoteInputManager,
mock(LeakDetector.class),
mock(ForegroundServiceDismissalFeatureController.class),
- mock(HeadsUpManager.class),
- mock(StatusBarStateController.class)
+ mock(IStatusBarService.class)
);
mEntryManager.setUpWithPresenter(mock(NotificationPresenter.class));
when(mFeatureFlags.isNewNotifPipelineRenderingEnabled()).thenReturn(false);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
index a927c8011b8f..64907eef2dd0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
@@ -136,6 +136,8 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase {
anyFloat());
assertThat(mBiometricUnlockController.getMode())
.isEqualTo(BiometricUnlockController.MODE_SHOW_BOUNCER);
+ assertThat(mBiometricUnlockController.getBiometricType())
+ .isEqualTo(BiometricSourceType.FINGERPRINT);
}
@Test
@@ -268,6 +270,8 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase {
verify(mStatusBarKeyguardViewManager).notifyKeyguardAuthenticated(eq(false));
assertThat(mBiometricUnlockController.getMode())
.isEqualTo(BiometricUnlockController.MODE_DISMISS_BOUNCER);
+ assertThat(mBiometricUnlockController.getBiometricType())
+ .isEqualTo(BiometricSourceType.FACE);
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
index b0b66b87d421..c7434f6fd95f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
@@ -51,6 +51,7 @@ import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.testing.UiEventLoggerFake;
import com.android.internal.util.LatencyTracker;
import com.android.keyguard.KeyguardClockSwitch;
+import com.android.keyguard.KeyguardClockSwitchController;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
@@ -183,6 +184,8 @@ public class NotificationPanelViewTest extends SysuiTestCase {
private BiometricUnlockController mBiometricUnlockController;
@Mock
private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
+ @Mock
+ private KeyguardClockSwitchController mKeyguardClockSwitchController;
private FlingAnimationUtils.Builder mFlingAnimationUtilsBuilder;
private NotificationPanelViewController mNotificationPanelViewController;
@@ -240,7 +243,8 @@ public class NotificationPanelViewTest extends SysuiTestCase {
mMetricsLogger, mActivityManager, mZenModeController, mConfigurationController,
mFlingAnimationUtilsBuilder, mStatusBarTouchableRegionManager,
mConversationNotificationManager, mMediaHiearchyManager,
- mBiometricUnlockController, mStatusBarKeyguardViewManager);
+ mBiometricUnlockController, mStatusBarKeyguardViewManager,
+ () -> mKeyguardClockSwitchController);
mNotificationPanelViewController.initDependencies(mStatusBar, mGroupManager,
mNotificationShelf, mNotificationAreaController, mScrimController);
mNotificationPanelViewController.setHeadsUpManager(mHeadsUpManager);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
index acdb2c59dc0c..33067343ba40 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
@@ -73,6 +73,7 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.NotificationTestHelper;
+import com.android.systemui.statusbar.notification.row.OnDismissCallback;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.concurrency.FakeExecutor;
import com.android.systemui.util.time.FakeSystemClock;
@@ -131,6 +132,8 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase {
@Mock
private Intent mContentIntentInner;
@Mock
+ private OnDismissCallback mOnDismissCallback;
+ @Mock
private NotificationActivityStarter mNotificationActivityStarter;
private FakeExecutor mUiBgExecutor = new FakeExecutor(new FakeSystemClock());
@@ -207,7 +210,8 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase {
mFeatureFlags,
mock(MetricsLogger.class),
- mock(StatusBarNotificationActivityStarterLogger.class))
+ mock(StatusBarNotificationActivityStarterLogger.class),
+ mOnDismissCallback)
.setStatusBar(mStatusBar)
.setNotificationPresenter(mock(NotificationPresenter.class))
.setNotificationPanelViewController(mock(NotificationPanelViewController.class))
@@ -266,8 +270,8 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase {
verify(mClickNotifier).onNotificationClick(
eq(sbn.getKey()), any(NotificationVisibility.class));
- // Notification is removed due to FLAG_AUTO_CANCEL
- verify(mEntryManager).performRemoveNotification(eq(sbn), eq(REASON_CLICK));
+ // Notification calls dismiss callback to remove notification due to FLAG_AUTO_CANCEL
+ verify(mOnDismissCallback).onDismiss(mNotificationRow.getEntry(), REASON_CLICK);
}
@Test
@@ -296,7 +300,7 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase {
verifyZeroInteractions(mContentIntent);
// Notification should not be cancelled.
- verify(mEntryManager, never()).performRemoveNotification(eq(sbn), anyInt());
+ verify(mOnDismissCallback, never()).onDismiss(eq(mNotificationRow.getEntry()), anyInt());
}
@Test
@@ -326,7 +330,7 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase {
verifyZeroInteractions(mContentIntent);
// Notification should not be cancelled.
- verify(mEntryManager, never()).performRemoveNotification(eq(sbn), anyInt());
+ verify(mEntryManager, never()).performRemoveNotification(eq(sbn), any(), anyInt());
}
@Test
@@ -358,6 +362,6 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase {
verifyNoMoreInteractions(mContentIntent);
// Notification should not be cancelled.
- verify(mEntryManager, never()).performRemoveNotification(eq(sbn), anyInt());
+ verify(mEntryManager, never()).performRemoveNotification(eq(sbn), any(), anyInt());
}
}
diff --git a/packages/Tethering/Android.bp b/packages/Tethering/Android.bp
index a8cd63d90676..915c2f6087b8 100644
--- a/packages/Tethering/Android.bp
+++ b/packages/Tethering/Android.bp
@@ -32,6 +32,7 @@ java_defaults {
"android.hardware.tetheroffload.config-V1.0-java",
"android.hardware.tetheroffload.control-V1.0-java",
"net-utils-framework-common",
+ "net-utils-device-common",
],
libs: [
"framework-statsd.stubs.module_lib",
diff --git a/packages/Tethering/AndroidManifest.xml b/packages/Tethering/AndroidManifest.xml
index 2b2fe4534c3e..e6444f3ead5c 100644
--- a/packages/Tethering/AndroidManifest.xml
+++ b/packages/Tethering/AndroidManifest.xml
@@ -24,7 +24,7 @@
<!-- Permissions must be defined here, and not in the base manifest, as the tethering
running in the system server process does not need any permission, and having
privileged permissions added would cause crashes on startup unless they are also
- added to the privileged permissions whitelist for that package. -->
+ added to the privileged permissions allowlist for that package. -->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_PRIVILEGED" />
diff --git a/packages/Tethering/proguard.flags b/packages/Tethering/proguard.flags
index 051fbd19fc6c..86b903353cf5 100644
--- a/packages/Tethering/proguard.flags
+++ b/packages/Tethering/proguard.flags
@@ -1,5 +1,5 @@
# Keep class's integer static field for MessageUtils to parsing their name.
--keep class com.android.networkstack.tethering.Tethering$TetherMasterSM {
+-keep class com.android.networkstack.tethering.Tethering$TetherMainSM {
static final int CMD_*;
static final int EVENT_*;
}
diff --git a/packages/Tethering/src/android/net/ip/IpServer.java b/packages/Tethering/src/android/net/ip/IpServer.java
index 8af1797a9dd7..673cbf09d259 100644
--- a/packages/Tethering/src/android/net/ip/IpServer.java
+++ b/packages/Tethering/src/android/net/ip/IpServer.java
@@ -197,15 +197,19 @@ public class IpServer extends StateMachine {
public static final int CMD_TETHER_UNREQUESTED = BASE_IPSERVER + 2;
// notification that this interface is down
public static final int CMD_INTERFACE_DOWN = BASE_IPSERVER + 3;
- // notification from the master SM that it had trouble enabling IP Forwarding
+ // notification from the {@link Tethering.TetherMainSM} that it had trouble enabling IP
+ // Forwarding
public static final int CMD_IP_FORWARDING_ENABLE_ERROR = BASE_IPSERVER + 4;
- // notification from the master SM that it had trouble disabling IP Forwarding
+ // notification from the {@link Tethering.TetherMainSM} SM that it had trouble disabling IP
+ // Forwarding
public static final int CMD_IP_FORWARDING_DISABLE_ERROR = BASE_IPSERVER + 5;
- // notification from the master SM that it had trouble starting tethering
+ // notification from the {@link Tethering.TetherMainSM} SM that it had trouble starting
+ // tethering
public static final int CMD_START_TETHERING_ERROR = BASE_IPSERVER + 6;
- // notification from the master SM that it had trouble stopping tethering
+ // notification from the {@link Tethering.TetherMainSM} that it had trouble stopping tethering
public static final int CMD_STOP_TETHERING_ERROR = BASE_IPSERVER + 7;
- // notification from the master SM that it had trouble setting the DNS forwarders
+ // notification from the {@link Tethering.TetherMainSM} that it had trouble setting the DNS
+ // forwarders
public static final int CMD_SET_DNS_FORWARDERS_ERROR = BASE_IPSERVER + 8;
// the upstream connection has changed
public static final int CMD_TETHER_CONNECTION_CHANGED = BASE_IPSERVER + 9;
@@ -423,9 +427,13 @@ public class IpServer extends StateMachine {
getHandler().post(() -> {
// We are on the handler thread: mDhcpServerStartIndex can be read safely.
if (mStartIndex != mDhcpServerStartIndex) {
- // This start request is obsolete. When the |server| binder token goes out of
- // scope, the garbage collector will finalize it, which causes the network stack
- // process garbage collector to collect the server itself.
+ // This start request is obsolete. Explicitly stop the DHCP server to shut
+ // down its thread. When the |server| binder token goes out of scope, the
+ // garbage collector will finalize it, which causes the network stack process
+ // garbage collector to collect the server itself.
+ try {
+ server.stop(null);
+ } catch (RemoteException e) { }
return;
}
@@ -1316,7 +1324,7 @@ public class IpServer extends StateMachine {
/**
* This state is terminal for the per interface state machine. At this
- * point, the master state machine should have removed this interface
+ * point, the tethering main state machine should have removed this interface
* specific state machine from its list of possible recipients of
* tethering requests. The state machine itself will hang around until
* the garbage collector finds it.
diff --git a/packages/Tethering/src/android/net/util/TetheringMessageBase.java b/packages/Tethering/src/android/net/util/TetheringMessageBase.java
index 1b763ce920da..29c0a817b6f4 100644
--- a/packages/Tethering/src/android/net/util/TetheringMessageBase.java
+++ b/packages/Tethering/src/android/net/util/TetheringMessageBase.java
@@ -19,7 +19,7 @@ package android.net.util;
* This class defines Message.what base addresses for various state machine.
*/
public class TetheringMessageBase {
- public static final int BASE_MASTER = 0;
+ public static final int BASE_MAIN_SM = 0;
public static final int BASE_IPSERVER = 100;
}
diff --git a/packages/Tethering/src/com/android/networkstack/tethering/EntitlementManager.java b/packages/Tethering/src/com/android/networkstack/tethering/EntitlementManager.java
index 9dace709d734..bb7322f2a0d2 100644
--- a/packages/Tethering/src/com/android/networkstack/tethering/EntitlementManager.java
+++ b/packages/Tethering/src/com/android/networkstack/tethering/EntitlementManager.java
@@ -296,16 +296,16 @@ public class EntitlementManager {
* Reference TetheringManager.TETHERING_{@code *} for each tether type.
*
* @param config an object that encapsulates the various tethering configuration elements.
- * Note: this method is only called from TetherMaster on the handler thread.
+ * Note: this method is only called from @{link Tethering.TetherMainSM} on the handler thread.
* If there are new callers from different threads, the logic should move to
- * masterHandler to avoid race conditions.
+ * @{link Tethering.TetherMainSM} handler to avoid race conditions.
*/
public void reevaluateSimCardProvisioning(final TetheringConfiguration config) {
if (DBG) mLog.i("reevaluateSimCardProvisioning");
if (!mHandler.getLooper().isCurrentThread()) {
// Except for test, this log should not appear in normal flow.
- mLog.log("reevaluateSimCardProvisioning() don't run in TetherMaster thread");
+ mLog.log("reevaluateSimCardProvisioning() don't run in TetherMainSM thread");
}
mEntitlementCacheValue.clear();
mCurrentEntitlementResults.clear();
diff --git a/packages/Tethering/src/com/android/networkstack/tethering/Tethering.java b/packages/Tethering/src/com/android/networkstack/tethering/Tethering.java
index 7508a653599d..cfc657587332 100644
--- a/packages/Tethering/src/com/android/networkstack/tethering/Tethering.java
+++ b/packages/Tethering/src/com/android/networkstack/tethering/Tethering.java
@@ -50,7 +50,7 @@ import static android.net.TetheringManager.TETHER_ERROR_UNKNOWN_TYPE;
import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_FAILED;
import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_STARTED;
import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_STOPPED;
-import static android.net.util.TetheringMessageBase.BASE_MASTER;
+import static android.net.util.TetheringMessageBase.BASE_MAIN_SM;
import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_INTERFACE_NAME;
import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_MODE;
import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_STATE;
@@ -159,7 +159,7 @@ public class Tethering {
private static final boolean VDBG = false;
private static final Class[] sMessageClasses = {
- Tethering.class, TetherMasterSM.class, IpServer.class
+ Tethering.class, TetherMainSM.class, IpServer.class
};
private static final SparseArray<String> sMagicDecoderRing =
MessageUtils.findMessageNames(sMessageClasses);
@@ -216,7 +216,7 @@ public class Tethering {
private final ArrayMap<String, TetherState> mTetherStates;
private final BroadcastReceiver mStateReceiver;
private final Looper mLooper;
- private final StateMachine mTetherMasterSM;
+ private final StateMachine mTetherMainSM;
private final OffloadController mOffloadController;
private final UpstreamNetworkMonitor mUpstreamNetworkMonitor;
// TODO: Figure out how to merge this and other downstream-tracking objects
@@ -273,10 +273,10 @@ public class Tethering {
mTetherStates = new ArrayMap<>();
mConnectedClientsTracker = new ConnectedClientsTracker();
- mTetherMasterSM = new TetherMasterSM("TetherMaster", mLooper, deps);
- mTetherMasterSM.start();
+ mTetherMainSM = new TetherMainSM("TetherMain", mLooper, deps);
+ mTetherMainSM.start();
- mHandler = mTetherMasterSM.getHandler();
+ mHandler = mTetherMainSM.getHandler();
mOffloadController = mDeps.getOffloadController(mHandler, mLog,
new OffloadController.Dependencies() {
@@ -285,8 +285,8 @@ public class Tethering {
return mConfig;
}
});
- mUpstreamNetworkMonitor = mDeps.getUpstreamNetworkMonitor(mContext, mTetherMasterSM, mLog,
- TetherMasterSM.EVENT_UPSTREAM_CALLBACK);
+ mUpstreamNetworkMonitor = mDeps.getUpstreamNetworkMonitor(mContext, mTetherMainSM, mLog,
+ TetherMainSM.EVENT_UPSTREAM_CALLBACK);
mForwardedDownstreams = new LinkedHashSet<>();
IntentFilter filter = new IntentFilter();
@@ -294,8 +294,8 @@ public class Tethering {
// EntitlementManager will send EVENT_UPSTREAM_PERMISSION_CHANGED when cellular upstream
// permission is changed according to entitlement check result.
mEntitlementMgr = mDeps.getEntitlementManager(mContext, mHandler, mLog,
- () -> mTetherMasterSM.sendMessage(
- TetherMasterSM.EVENT_UPSTREAM_PERMISSION_CHANGED));
+ () -> mTetherMainSM.sendMessage(
+ TetherMainSM.EVENT_UPSTREAM_PERMISSION_CHANGED));
mEntitlementMgr.setOnUiEntitlementFailedListener((int downstream) -> {
mLog.log("OBSERVED UiEnitlementFailed");
stopTethering(downstream);
@@ -945,7 +945,7 @@ public class Tethering {
}
if (VDBG) Log.d(TAG, "Tethering got CONNECTIVITY_ACTION: " + networkInfo.toString());
- mTetherMasterSM.sendMessage(TetherMasterSM.CMD_UPSTREAM_CHANGED);
+ mTetherMainSM.sendMessage(TetherMainSM.CMD_UPSTREAM_CHANGED);
}
private void handleUsbAction(Intent intent) {
@@ -1170,7 +1170,7 @@ public class Tethering {
private void disableWifiP2pIpServingLockedIfNeeded(String ifname) {
if (TextUtils.isEmpty(ifname)) return;
- disableWifiIpServingLockedCommon(TETHERING_WIFI_P2P, ifname, /* dummy */ 0);
+ disableWifiIpServingLockedCommon(TETHERING_WIFI_P2P, ifname, /* fake */ 0);
}
private void enableWifiIpServingLocked(String ifname, int wifiIpMode) {
@@ -1381,23 +1381,23 @@ public class Tethering {
return false;
}
- class TetherMasterSM extends StateMachine {
+ class TetherMainSM extends StateMachine {
// an interface SM has requested Tethering/Local Hotspot
- static final int EVENT_IFACE_SERVING_STATE_ACTIVE = BASE_MASTER + 1;
+ static final int EVENT_IFACE_SERVING_STATE_ACTIVE = BASE_MAIN_SM + 1;
// an interface SM has unrequested Tethering/Local Hotspot
- static final int EVENT_IFACE_SERVING_STATE_INACTIVE = BASE_MASTER + 2;
+ static final int EVENT_IFACE_SERVING_STATE_INACTIVE = BASE_MAIN_SM + 2;
// upstream connection change - do the right thing
- static final int CMD_UPSTREAM_CHANGED = BASE_MASTER + 3;
+ static final int CMD_UPSTREAM_CHANGED = BASE_MAIN_SM + 3;
// we don't have a valid upstream conn, check again after a delay
- static final int CMD_RETRY_UPSTREAM = BASE_MASTER + 4;
- // Events from NetworkCallbacks that we process on the master state
+ static final int CMD_RETRY_UPSTREAM = BASE_MAIN_SM + 4;
+ // Events from NetworkCallbacks that we process on the main state
// machine thread on behalf of the UpstreamNetworkMonitor.
- static final int EVENT_UPSTREAM_CALLBACK = BASE_MASTER + 5;
+ static final int EVENT_UPSTREAM_CALLBACK = BASE_MAIN_SM + 5;
// we treated the error and want now to clear it
- static final int CMD_CLEAR_ERROR = BASE_MASTER + 6;
- static final int EVENT_IFACE_UPDATE_LINKPROPERTIES = BASE_MASTER + 7;
+ static final int CMD_CLEAR_ERROR = BASE_MAIN_SM + 6;
+ static final int EVENT_IFACE_UPDATE_LINKPROPERTIES = BASE_MAIN_SM + 7;
// Events from EntitlementManager to choose upstream again.
- static final int EVENT_UPSTREAM_PERMISSION_CHANGED = BASE_MASTER + 8;
+ static final int EVENT_UPSTREAM_PERMISSION_CHANGED = BASE_MAIN_SM + 8;
private final State mInitialState;
private final State mTetherModeAliveState;
@@ -1425,7 +1425,7 @@ public class Tethering {
private static final int UPSTREAM_SETTLE_TIME_MS = 10000;
- TetherMasterSM(String name, Looper looper, TetheringDependencies deps) {
+ TetherMainSM(String name, Looper looper, TetheringDependencies deps) {
super(name, looper);
mInitialState = new InitialState();
@@ -1479,7 +1479,7 @@ public class Tethering {
}
}
- protected boolean turnOnMasterTetherSettings() {
+ protected boolean turnOnMainTetherSettings() {
final TetheringConfiguration cfg = mConfig;
try {
mNetd.ipfwdEnableForwarding(TAG);
@@ -1506,11 +1506,11 @@ public class Tethering {
return false;
}
}
- mLog.log("SET master tether settings: ON");
+ mLog.log("SET main tether settings: ON");
return true;
}
- protected boolean turnOffMasterTetherSettings() {
+ protected boolean turnOffMainTetherSettings() {
try {
mNetd.tetherStop();
} catch (RemoteException | ServiceSpecificException e) {
@@ -1526,7 +1526,7 @@ public class Tethering {
return false;
}
transitionTo(mInitialState);
- mLog.log("SET master tether settings: OFF");
+ mLog.log("SET main tether settings: OFF");
return true;
}
@@ -1730,7 +1730,7 @@ public class Tethering {
// TODO: Re-evaluate possible upstreams. Currently upstream
// reevaluation is triggered via received CONNECTIVITY_ACTION
// broadcasts that result in being passed a
- // TetherMasterSM.CMD_UPSTREAM_CHANGED.
+ // TetherMainSM.CMD_UPSTREAM_CHANGED.
handleNewUpstreamNetworkState(null);
break;
default:
@@ -1745,9 +1745,9 @@ public class Tethering {
@Override
public void enter() {
- // If turning on master tether settings fails, we have already
+ // If turning on main tether settings fails, we have already
// transitioned to an error state; exit early.
- if (!turnOnMasterTetherSettings()) {
+ if (!turnOnMainTetherSettings()) {
return;
}
@@ -1819,7 +1819,7 @@ public class Tethering {
if (mNotifyList.isEmpty()) {
// This transitions us out of TetherModeAliveState,
// either to InitialState or an error state.
- turnOffMasterTetherSettings();
+ turnOffMainTetherSettings();
break;
}
@@ -2329,7 +2329,7 @@ public class Tethering {
};
}
- // TODO: Move into TetherMasterSM.
+ // TODO: Move into TetherMainSM.
private void notifyInterfaceStateChange(IpServer who, int state, int error) {
final String iface = who.interfaceName();
synchronized (mPublicSync) {
@@ -2344,27 +2344,27 @@ public class Tethering {
mLog.log(String.format("OBSERVED iface=%s state=%s error=%s", iface, state, error));
- // If TetherMasterSM is in ErrorState, TetherMasterSM stays there.
- // Thus we give a chance for TetherMasterSM to recover to InitialState
+ // If TetherMainSM is in ErrorState, TetherMainSM stays there.
+ // Thus we give a chance for TetherMainSM to recover to InitialState
// by sending CMD_CLEAR_ERROR
if (error == TETHER_ERROR_INTERNAL_ERROR) {
- mTetherMasterSM.sendMessage(TetherMasterSM.CMD_CLEAR_ERROR, who);
+ mTetherMainSM.sendMessage(TetherMainSM.CMD_CLEAR_ERROR, who);
}
int which;
switch (state) {
case IpServer.STATE_UNAVAILABLE:
case IpServer.STATE_AVAILABLE:
- which = TetherMasterSM.EVENT_IFACE_SERVING_STATE_INACTIVE;
+ which = TetherMainSM.EVENT_IFACE_SERVING_STATE_INACTIVE;
break;
case IpServer.STATE_TETHERED:
case IpServer.STATE_LOCAL_ONLY:
- which = TetherMasterSM.EVENT_IFACE_SERVING_STATE_ACTIVE;
+ which = TetherMainSM.EVENT_IFACE_SERVING_STATE_ACTIVE;
break;
default:
Log.wtf(TAG, "Unknown interface state: " + state);
return;
}
- mTetherMasterSM.sendMessage(which, state, 0, who);
+ mTetherMainSM.sendMessage(which, state, 0, who);
sendTetherStateChangedBroadcast();
}
@@ -2384,8 +2384,8 @@ public class Tethering {
mLog.log(String.format(
"OBSERVED LinkProperties update iface=%s state=%s lp=%s",
iface, IpServer.getStateString(state), newLp));
- final int which = TetherMasterSM.EVENT_IFACE_UPDATE_LINKPROPERTIES;
- mTetherMasterSM.sendMessage(which, state, 0, newLp);
+ final int which = TetherMainSM.EVENT_IFACE_UPDATE_LINKPROPERTIES;
+ mTetherMainSM.sendMessage(which, state, 0, newLp);
}
private void maybeTrackNewInterfaceLocked(final String iface) {
diff --git a/packages/Tethering/src/com/android/networkstack/tethering/UpstreamNetworkMonitor.java b/packages/Tethering/src/com/android/networkstack/tethering/UpstreamNetworkMonitor.java
index 320427c393ac..b17065cb7804 100644
--- a/packages/Tethering/src/com/android/networkstack/tethering/UpstreamNetworkMonitor.java
+++ b/packages/Tethering/src/com/android/networkstack/tethering/UpstreamNetworkMonitor.java
@@ -63,7 +63,7 @@ import java.util.Set;
* Calling #registerMobileNetworkRequest() to bring up mobile DUN/HIPRI network.
*
* The methods and data members of this class are only to be accessed and
- * modified from the tethering master state machine thread. Any other
+ * modified from the tethering main state machine thread. Any other
* access semantics would necessitate the addition of locking.
*
* TODO: Move upstream selection logic here.
diff --git a/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java b/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java
index 30a9d2252ea6..3b72b5b47191 100644
--- a/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java
+++ b/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java
@@ -50,6 +50,7 @@ import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.inOrder;
@@ -73,6 +74,7 @@ import android.net.MacAddress;
import android.net.RouteInfo;
import android.net.TetherOffloadRuleParcel;
import android.net.TetherStatsParcel;
+import android.net.dhcp.DhcpServerCallbacks;
import android.net.dhcp.DhcpServingParamsParcel;
import android.net.dhcp.IDhcpEventCallbacks;
import android.net.dhcp.IDhcpServer;
@@ -163,17 +165,6 @@ public class IpServerTest {
private void initStateMachine(int interfaceType, boolean usingLegacyDhcp,
boolean usingBpfOffload) throws Exception {
- doAnswer(inv -> {
- final IDhcpServerCallbacks cb = inv.getArgument(2);
- new Thread(() -> {
- try {
- cb.onDhcpServerCreated(STATUS_SUCCESS, mDhcpServer);
- } catch (RemoteException e) {
- fail(e.getMessage());
- }
- }).run();
- return null;
- }).when(mDependencies).makeDhcpServer(any(), mDhcpParamsCaptor.capture(), any());
when(mDependencies.getRouterAdvertisementDaemon(any())).thenReturn(mRaDaemon);
when(mDependencies.getInterfaceParams(IFACE_NAME)).thenReturn(TEST_IFACE_PARAMS);
@@ -225,6 +216,20 @@ public class IpServerTest {
when(mAddressCoordinator.requestDownstreamAddress(any())).thenReturn(mTestAddress);
}
+ private void setUpDhcpServer() throws Exception {
+ doAnswer(inv -> {
+ final IDhcpServerCallbacks cb = inv.getArgument(2);
+ new Thread(() -> {
+ try {
+ cb.onDhcpServerCreated(STATUS_SUCCESS, mDhcpServer);
+ } catch (RemoteException e) {
+ fail(e.getMessage());
+ }
+ }).run();
+ return null;
+ }).when(mDependencies).makeDhcpServer(any(), mDhcpParamsCaptor.capture(), any());
+ }
+
@Before public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
when(mSharedLog.forSubComponent(anyString())).thenReturn(mSharedLog);
@@ -258,6 +263,8 @@ public class IpServerTest {
return mTetherConfig;
}
}));
+
+ setUpDhcpServer();
}
@Test
@@ -965,6 +972,31 @@ public class IpServerTest {
reset(mRaDaemon);
}
+ @Test
+ public void testStopObsoleteDhcpServer() throws Exception {
+ final ArgumentCaptor<DhcpServerCallbacks> cbCaptor =
+ ArgumentCaptor.forClass(DhcpServerCallbacks.class);
+ doNothing().when(mDependencies).makeDhcpServer(any(), mDhcpParamsCaptor.capture(),
+ cbCaptor.capture());
+ initStateMachine(TETHERING_WIFI);
+ dispatchCommand(IpServer.CMD_TETHER_REQUESTED, STATE_TETHERED);
+ verify(mDhcpServer, never()).startWithCallbacks(any(), any());
+
+ // No stop dhcp server because dhcp server is not created yet.
+ dispatchCommand(IpServer.CMD_TETHER_UNREQUESTED);
+ verify(mDhcpServer, never()).stop(any());
+
+ // Stop obsolete dhcp server.
+ try {
+ final DhcpServerCallbacks cb = cbCaptor.getValue();
+ cb.onDhcpServerCreated(STATUS_SUCCESS, mDhcpServer);
+ mLooper.dispatchAll();
+ } catch (RemoteException e) {
+ fail(e.getMessage());
+ }
+ verify(mDhcpServer).stop(any());
+ }
+
private void assertDhcpServingParams(final DhcpServingParamsParcel params,
final IpPrefix prefix) {
// Last address byte is random
diff --git a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java
index 1b710d00d0c7..46fe5cf093fd 100644
--- a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java
+++ b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java
@@ -337,11 +337,11 @@ public class TetheringTest {
}
public class MockTetheringDependencies extends TetheringDependencies {
- StateMachine mUpstreamNetworkMonitorMasterSM;
+ StateMachine mUpstreamNetworkMonitorSM;
ArrayList<IpServer> mIpv6CoordinatorNotifyList;
public void reset() {
- mUpstreamNetworkMonitorMasterSM = null;
+ mUpstreamNetworkMonitorSM = null;
mIpv6CoordinatorNotifyList = null;
}
@@ -368,7 +368,7 @@ public class TetheringTest {
@Override
public UpstreamNetworkMonitor getUpstreamNetworkMonitor(Context ctx,
StateMachine target, SharedLog log, int what) {
- mUpstreamNetworkMonitorMasterSM = target;
+ mUpstreamNetworkMonitorSM = target;
return mUpstreamNetworkMonitor;
}
@@ -911,8 +911,8 @@ public class TetheringTest {
initTetheringUpstream(upstreamState);
// Upstream LinkProperties changed: UpstreamNetworkMonitor sends EVENT_ON_LINKPROPERTIES.
- mTetheringDependencies.mUpstreamNetworkMonitorMasterSM.sendMessage(
- Tethering.TetherMasterSM.EVENT_UPSTREAM_CALLBACK,
+ mTetheringDependencies.mUpstreamNetworkMonitorSM.sendMessage(
+ Tethering.TetherMainSM.EVENT_UPSTREAM_CALLBACK,
UpstreamNetworkMonitor.EVENT_ON_LINKPROPERTIES,
0,
upstreamState);
@@ -1126,7 +1126,7 @@ public class TetheringTest {
verify(mNetd, times(1)).ipfwdEnableForwarding(TETHERING_NAME);
// This never gets called because of the exception thrown above.
verify(mNetd, times(0)).tetherStartWithConfiguration(any());
- // When the master state machine transitions to an error state it tells
+ // When the main state machine transitions to an error state it tells
// downstream interfaces, which causes us to tell Wi-Fi about the error
// so it can take down AP mode.
verify(mNetd, times(1)).tetherApplyDnsInterfaces();
@@ -1753,8 +1753,8 @@ public class TetheringTest {
@Test
public void testUpstreamNetworkChanged() {
- final Tethering.TetherMasterSM stateMachine = (Tethering.TetherMasterSM)
- mTetheringDependencies.mUpstreamNetworkMonitorMasterSM;
+ final Tethering.TetherMainSM stateMachine = (Tethering.TetherMainSM)
+ mTetheringDependencies.mUpstreamNetworkMonitorSM;
final UpstreamNetworkState upstreamState = buildMobileIPv4UpstreamState();
initTetheringUpstream(upstreamState);
stateMachine.chooseUpstreamType(true);
@@ -1765,8 +1765,8 @@ public class TetheringTest {
@Test
public void testUpstreamCapabilitiesChanged() {
- final Tethering.TetherMasterSM stateMachine = (Tethering.TetherMasterSM)
- mTetheringDependencies.mUpstreamNetworkMonitorMasterSM;
+ final Tethering.TetherMainSM stateMachine = (Tethering.TetherMainSM)
+ mTetheringDependencies.mUpstreamNetworkMonitorSM;
final UpstreamNetworkState upstreamState = buildMobileIPv4UpstreamState();
initTetheringUpstream(upstreamState);
stateMachine.chooseUpstreamType(true);
@@ -1891,8 +1891,8 @@ public class TetheringTest {
any(), any());
reset(mNetd, mUsbManager);
upstreamNetwork = buildV4WifiUpstreamState(ipv4Address, 30, wifiNetwork);
- mTetheringDependencies.mUpstreamNetworkMonitorMasterSM.sendMessage(
- Tethering.TetherMasterSM.EVENT_UPSTREAM_CALLBACK,
+ mTetheringDependencies.mUpstreamNetworkMonitorSM.sendMessage(
+ Tethering.TetherMainSM.EVENT_UPSTREAM_CALLBACK,
UpstreamNetworkMonitor.EVENT_ON_LINKPROPERTIES,
0,
upstreamNetwork);
@@ -1929,8 +1929,8 @@ public class TetheringTest {
final UpstreamNetworkState upstreamNetwork = buildV4WifiUpstreamState(
upstreamAddress, 16, wifiNetwork);
- mTetheringDependencies.mUpstreamNetworkMonitorMasterSM.sendMessage(
- Tethering.TetherMasterSM.EVENT_UPSTREAM_CALLBACK,
+ mTetheringDependencies.mUpstreamNetworkMonitorSM.sendMessage(
+ Tethering.TetherMainSM.EVENT_UPSTREAM_CALLBACK,
UpstreamNetworkMonitor.EVENT_ON_LINKPROPERTIES,
0,
upstreamNetwork);
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java
index a08c2dd4292d..ed2b26f24478 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationManager.java
@@ -384,7 +384,7 @@ public class WindowMagnificationManager implements
synchronized (mLock) {
WindowMagnifier magnifier = mWindowMagnifiers.get(displayId);
if (magnifier == null) {
- return;
+ magnifier = createWindowMagnifier(displayId);
}
if (DBG) {
Slog.i(TAG,
@@ -401,6 +401,15 @@ public class WindowMagnificationManager implements
}
@Override
+ public void onSourceBoundsChanged(int displayId, Rect sourceBounds) {
+ WindowMagnifier magnifier = mWindowMagnifiers.get(displayId);
+ if (magnifier == null) {
+ magnifier = createWindowMagnifier(displayId);
+ }
+ magnifier.onSourceBoundsChanged(sourceBounds);
+ }
+
+ @Override
public void binderDied() {
synchronized (mLock) {
Slog.w(TAG, "binderDied DeathRecipient :" + mExpiredDeathRecipient);
@@ -427,6 +436,8 @@ public class WindowMagnificationManager implements
private final WindowMagnificationManager mWindowMagnificationManager;
//Records the bounds of window magnifier.
private final Rect mBounds = new Rect();
+ //The magnified bounds on the screen.
+ private final Rect mSourceBounds = new Rect();
WindowMagnifier(int displayId, WindowMagnificationManager windowMagnificationManager) {
mDisplayId = displayId;
mWindowMagnificationManager = windowMagnificationManager;
@@ -502,6 +513,10 @@ public class WindowMagnificationManager implements
void reset() {
mEnabled = false;
}
+
+ public void onSourceBoundsChanged(Rect sourceBounds) {
+ mSourceBounds.set(sourceBounds);
+ }
}
private boolean enableWindowMagnification(int displayId, float scale, float centerX,
diff --git a/services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java b/services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java
index 103151dcdda5..7ee607c3eab4 100644
--- a/services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java
+++ b/services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java
@@ -219,7 +219,7 @@ public class AppPredictionPerUserService extends
if (connected) {
synchronized (mLock) {
if (mZombie) {
- // Sanity check - shouldn't happen
+ // Validation check - shouldn't happen
if (mRemoteService == null) {
Slog.w(TAG, "Cannot resurrect sessions because remote service is null");
return;
diff --git a/services/autofill/java/com/android/server/autofill/RemoteFillService.java b/services/autofill/java/com/android/server/autofill/RemoteFillService.java
index 5a9320f61b38..b0755ac836e0 100644
--- a/services/autofill/java/com/android/server/autofill/RemoteFillService.java
+++ b/services/autofill/java/com/android/server/autofill/RemoteFillService.java
@@ -161,8 +161,9 @@ final class RemoteFillService extends ServiceConnector.Impl<IAutoFillService> {
@Override
public void onFailure(int requestId, CharSequence message) {
+ String errorMessage = message == null ? "" : String.valueOf(message);
fillRequest.completeExceptionally(
- new RuntimeException(String.valueOf(message)));
+ new RuntimeException(errorMessage));
}
});
return fillRequest;
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 7ab4369b338a..1970b5774bbb 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -1710,7 +1710,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
if ((state & ViewState.STATE_AUTOFILLED_ONCE) != 0) {
final String datasetId = viewState.getDatasetId();
if (datasetId == null) {
- // Sanity check - should never happen.
+ // Validation check - should never happen.
Slog.w(TAG, "logContextCommitted(): no dataset id on " + viewState);
continue;
}
@@ -1844,7 +1844,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
final ArrayMap<String, String> algorithms = userData.getFieldClassificationAlgorithms();
final ArrayMap<String, Bundle> args = userData.getFieldClassificationArgs();
- // Sanity check
+ // Validation check
if (userValues == null || categoryIds == null || userValues.length != categoryIds.length) {
final int valuesLength = userValues == null ? -1 : userValues.length;
final int idsLength = categoryIds == null ? -1 : categoryIds.length;
@@ -2668,12 +2668,12 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
final String currentUrl = mUrlBar == null ? null
: mUrlBar.getText().toString().trim();
if (currentUrl == null) {
- // Sanity check - shouldn't happen.
+ // Validation check - shouldn't happen.
wtf(null, "URL bar value changed, but current value is null");
return;
}
if (value == null || ! value.isText()) {
- // Sanity check - shouldn't happen.
+ // Validation check - shouldn't happen.
wtf(null, "URL bar value changed to null or non-text: %s", value);
return;
}
diff --git a/services/backup/java/com/android/server/backup/DataChangedJournal.java b/services/backup/java/com/android/server/backup/DataChangedJournal.java
index e75eb731a73e..0e7fc93df7cc 100644
--- a/services/backup/java/com/android/server/backup/DataChangedJournal.java
+++ b/services/backup/java/com/android/server/backup/DataChangedJournal.java
@@ -16,17 +16,21 @@
package com.android.server.backup;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.util.Slog;
import java.io.BufferedInputStream;
import java.io.DataInputStream;
+import java.io.EOFException;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
+import java.io.InputStream;
import java.io.RandomAccessFile;
import java.util.ArrayList;
import java.util.List;
+import java.util.Objects;
import java.util.function.Consumer;
/**
@@ -36,7 +40,7 @@ import java.util.function.Consumer;
* <p>This information is persisted to the filesystem so that it is not lost in the event of a
* reboot.
*/
-public class DataChangedJournal {
+public final class DataChangedJournal {
private static final String TAG = "DataChangedJournal";
private static final String FILE_NAME_PREFIX = "journal";
@@ -50,10 +54,11 @@ public class DataChangedJournal {
/**
* Constructs an instance that reads from and writes to the given file.
*/
- DataChangedJournal(File file) {
- mFile = file;
+ DataChangedJournal(@NonNull File file) {
+ mFile = Objects.requireNonNull(file);
}
+
/**
* Adds the given package to the journal.
*
@@ -75,15 +80,17 @@ public class DataChangedJournal {
*/
public void forEach(Consumer<String> consumer) throws IOException {
try (
- BufferedInputStream bufferedInputStream = new BufferedInputStream(
- new FileInputStream(mFile), BUFFER_SIZE_BYTES);
- DataInputStream dataInputStream = new DataInputStream(bufferedInputStream)
+ InputStream in = new FileInputStream(mFile);
+ InputStream bufferedIn = new BufferedInputStream(in, BUFFER_SIZE_BYTES);
+ DataInputStream dataInputStream = new DataInputStream(bufferedIn)
) {
- while (dataInputStream.available() > 0) {
+ while (true) {
String packageName = dataInputStream.readUTF();
consumer.accept(packageName);
}
- }
+ } catch (EOFException tolerated) {
+ // no more data; we're done
+ } // other kinds of IOExceptions are error conditions and handled in the caller
}
/**
@@ -107,14 +114,15 @@ public class DataChangedJournal {
}
@Override
+ public int hashCode() {
+ return mFile.hashCode();
+ }
+
+ @Override
public boolean equals(@Nullable Object object) {
if (object instanceof DataChangedJournal) {
DataChangedJournal that = (DataChangedJournal) object;
- try {
- return this.mFile.getCanonicalPath().equals(that.mFile.getCanonicalPath());
- } catch (IOException exception) {
- return false;
- }
+ return mFile.equals(that.mFile);
}
return false;
}
@@ -131,9 +139,10 @@ public class DataChangedJournal {
* @return The journal.
* @throws IOException if there is an IO error creating the file.
*/
- static DataChangedJournal newJournal(File journalDirectory) throws IOException {
- return new DataChangedJournal(
- File.createTempFile(FILE_NAME_PREFIX, null, journalDirectory));
+ static DataChangedJournal newJournal(@NonNull File journalDirectory) throws IOException {
+ Objects.requireNonNull(journalDirectory);
+ File file = File.createTempFile(FILE_NAME_PREFIX, null, journalDirectory);
+ return new DataChangedJournal(file);
}
/**
diff --git a/services/backup/java/com/android/server/backup/UserBackupManagerService.java b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
index ff21a733223c..3ab81cbb313f 100644
--- a/services/backup/java/com/android/server/backup/UserBackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
@@ -156,6 +156,7 @@ import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
@@ -1154,23 +1155,30 @@ public class UserBackupManagerService {
private void parseLeftoverJournals() {
ArrayList<DataChangedJournal> journals = DataChangedJournal.listJournals(mJournalDir);
+ journals.removeAll(Collections.singletonList(mJournal));
+ if (!journals.isEmpty()) {
+ Slog.i(TAG, addUserIdToLogMessage(mUserId,
+ "Found " + journals.size() + " stale backup journal(s), scheduling."));
+ }
+ Set<String> packageNames = new LinkedHashSet<>();
for (DataChangedJournal journal : journals) {
- if (!journal.equals(mJournal)) {
- try {
- journal.forEach(packageName -> {
- Slog.i(
- TAG,
- addUserIdToLogMessage(
- mUserId, "Found stale backup journal, scheduling"));
- if (MORE_DEBUG) {
- Slog.i(TAG, addUserIdToLogMessage(mUserId, " " + packageName));
- }
+ try {
+ journal.forEach(packageName -> {
+ if (packageNames.add(packageName)) {
dataChangedImpl(packageName);
- });
- } catch (IOException e) {
- Slog.e(TAG, addUserIdToLogMessage(mUserId, "Can't read " + journal), e);
- }
+ }
+ });
+ } catch (IOException e) {
+ Slog.e(TAG, addUserIdToLogMessage(mUserId, "Can't read " + journal), e);
+ }
+ }
+ if (!packageNames.isEmpty()) {
+ String msg = "Stale backup journals: Scheduled " + packageNames.size()
+ + " package(s) total";
+ if (MORE_DEBUG) {
+ msg += ": " + packageNames;
}
+ Slog.i(TAG, addUserIdToLogMessage(mUserId, msg));
}
}
@@ -2299,7 +2307,7 @@ public class UserBackupManagerService {
public void enqueueFullBackup(String packageName, long lastBackedUp) {
FullBackupEntry newEntry = new FullBackupEntry(packageName, lastBackedUp);
synchronized (mQueueLock) {
- // First, sanity check that we aren't adding a duplicate. Slow but
+ // First, check that we aren't adding a duplicate. Slow but
// straightforward; we'll have at most on the order of a few hundred
// items in this list.
dequeueFullBackupLocked(packageName);
diff --git a/services/backup/java/com/android/server/backup/fullbackup/PerformAdbBackupTask.java b/services/backup/java/com/android/server/backup/fullbackup/PerformAdbBackupTask.java
index a69bd6b62264..0a117746ea3f 100644
--- a/services/backup/java/com/android/server/backup/fullbackup/PerformAdbBackupTask.java
+++ b/services/backup/java/com/android/server/backup/fullbackup/PerformAdbBackupTask.java
@@ -24,8 +24,6 @@ import static com.android.server.backup.UserBackupManagerService.BACKUP_FILE_HEA
import static com.android.server.backup.UserBackupManagerService.BACKUP_FILE_VERSION;
import static com.android.server.backup.UserBackupManagerService.SHARED_BACKUP_AGENT_PACKAGE;
-import android.app.backup.BackupManager;
-import android.app.backup.BackupManager.OperationType;
import android.app.backup.IFullBackupRestoreObserver;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
@@ -143,7 +141,7 @@ public class PerformAdbBackupTask extends FullBackupTask implements BackupRestor
private OutputStream emitAesBackupHeader(StringBuilder headerbuf,
OutputStream ofstream) throws Exception {
- // User key will be used to encrypt the master key.
+ // User key will be used to encrypt the encryption key.
byte[] newUserSalt = mUserBackupManagerService
.randomBytes(PasswordUtils.PBKDF2_SALT_SIZE);
SecretKey userKey = PasswordUtils
@@ -151,16 +149,16 @@ public class PerformAdbBackupTask extends FullBackupTask implements BackupRestor
newUserSalt,
PasswordUtils.PBKDF2_HASH_ROUNDS);
- // the master key is random for each backup
- byte[] masterPw = new byte[256 / 8];
- mUserBackupManagerService.getRng().nextBytes(masterPw);
+ // the encryption key is random for each backup
+ byte[] encryptionKey = new byte[256 / 8];
+ mUserBackupManagerService.getRng().nextBytes(encryptionKey);
byte[] checksumSalt = mUserBackupManagerService
.randomBytes(PasswordUtils.PBKDF2_SALT_SIZE);
- // primary encryption of the datastream with the random key
+ // primary encryption of the datastream with the encryption key
Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding");
- SecretKeySpec masterKeySpec = new SecretKeySpec(masterPw, "AES");
- c.init(Cipher.ENCRYPT_MODE, masterKeySpec);
+ SecretKeySpec encryptionKeySpec = new SecretKeySpec(encryptionKey, "AES");
+ c.init(Cipher.ENCRYPT_MODE, encryptionKeySpec);
OutputStream finalOutput = new CipherOutputStream(ofstream, c);
// line 4: name of encryption algorithm
@@ -169,7 +167,7 @@ public class PerformAdbBackupTask extends FullBackupTask implements BackupRestor
// line 5: user password salt [hex]
headerbuf.append(PasswordUtils.byteArrayToHex(newUserSalt));
headerbuf.append('\n');
- // line 6: master key checksum salt [hex]
+ // line 6: encryption key checksum salt [hex]
headerbuf.append(PasswordUtils.byteArrayToHex(checksumSalt));
headerbuf.append('\n');
// line 7: number of PBKDF2 rounds used [decimal]
@@ -184,21 +182,21 @@ public class PerformAdbBackupTask extends FullBackupTask implements BackupRestor
headerbuf.append(PasswordUtils.byteArrayToHex(IV));
headerbuf.append('\n');
- // line 9: master IV + key blob, encrypted by the user key [hex]. Blob format:
+ // line 9: encryption IV + key blob, encrypted by the user key [hex]. Blob format:
// [byte] IV length = Niv
// [array of Niv bytes] IV itself
- // [byte] master key length = Nmk
- // [array of Nmk bytes] master key itself
- // [byte] MK checksum hash length = Nck
- // [array of Nck bytes] master key checksum hash
+ // [byte] encryption key length = Nek
+ // [array of Nek bytes] encryption key itself
+ // [byte] encryption key checksum hash length = Nck
+ // [array of Nck bytes] encryption key checksum hash
//
- // The checksum is the (master key + checksum salt), run through the
+ // The checksum is the (encryption key + checksum salt), run through the
// stated number of PBKDF2 rounds
IV = c.getIV();
- byte[] mk = masterKeySpec.getEncoded();
+ byte[] mk = encryptionKeySpec.getEncoded();
byte[] checksum = PasswordUtils
.makeKeyChecksum(PBKDF_CURRENT,
- masterKeySpec.getEncoded(),
+ encryptionKeySpec.getEncoded(),
checksumSalt, PasswordUtils.PBKDF2_HASH_ROUNDS);
ByteArrayOutputStream blob = new ByteArrayOutputStream(IV.length + mk.length
@@ -347,15 +345,15 @@ public class PerformAdbBackupTask extends FullBackupTask implements BackupRestor
// When line 4 is not "none", then additional header data follows:
//
// line 5: user password salt [hex]
- // line 6: master key checksum salt [hex]
- // line 7: number of PBKDF2 rounds to use (same for user & master) [decimal]
+ // line 6: encryption key checksum salt [hex]
+ // line 7: number of PBKDF2 rounds to use (same for user & encryption key) [decimal]
// line 8: IV of the user key [hex]
- // line 9: master key blob [hex]
- // IV of the master key, master key itself, master key checksum hash
+ // line 9: encryption key blob [hex]
+ // IV of the encryption key, encryption key itself, encryption key checksum hash
//
- // The master key checksum is the master key plus its checksum salt, run through
+ // The encryption key checksum is the encryption key plus its checksum salt, run through
// 10k rounds of PBKDF2. This is used to verify that the user has supplied the
- // correct password for decrypting the archive: the master key decrypted from
+ // correct password for decrypting the archive: the encryption key decrypted from
// the archive using the user-supplied password is also run through PBKDF2 in
// this way, and if the result does not match the checksum as stored in the
// archive, then we know that the user-supplied password does not match the
diff --git a/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java b/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java
index 82bed3b57f16..e42d3bd0e352 100644
--- a/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java
+++ b/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java
@@ -379,7 +379,7 @@ public class FullRestoreEngine extends RestoreEngine {
}
}
- // Sanity check: make sure we never give data to the wrong app. This
+ // Make sure we never give data to the wrong app. This
// should never happen but a little paranoia here won't go amiss.
if (okay && !pkg.equals(mAgentPackage)) {
Slog.e(TAG, "Restoring data for " + pkg
diff --git a/services/backup/java/com/android/server/backup/restore/PerformAdbRestoreTask.java b/services/backup/java/com/android/server/backup/restore/PerformAdbRestoreTask.java
index 01b40fbff201..923bb086f914 100644
--- a/services/backup/java/com/android/server/backup/restore/PerformAdbRestoreTask.java
+++ b/services/backup/java/com/android/server/backup/restore/PerformAdbRestoreTask.java
@@ -212,10 +212,9 @@ public class PerformAdbRestoreTask implements Runnable {
return buffer.toString();
}
- private static InputStream attemptMasterKeyDecryption(String decryptPassword, String algorithm,
- byte[] userSalt, byte[] ckSalt,
- int rounds, String userIvHex, String masterKeyBlobHex, InputStream rawInStream,
- boolean doLog) {
+ private static InputStream attemptEncryptionKeyDecryption(String decryptPassword,
+ String algorithm, byte[] userSalt, byte[] ckSalt, int rounds, String userIvHex,
+ String encryptionKeyBlobHex, InputStream rawInStream, boolean doLog) {
InputStream result = null;
try {
@@ -228,31 +227,31 @@ public class PerformAdbRestoreTask implements Runnable {
c.init(Cipher.DECRYPT_MODE,
new SecretKeySpec(userKey.getEncoded(), "AES"),
ivSpec);
- byte[] mkCipher = PasswordUtils.hexToByteArray(masterKeyBlobHex);
+ byte[] mkCipher = PasswordUtils.hexToByteArray(encryptionKeyBlobHex);
byte[] mkBlob = c.doFinal(mkCipher);
- // first, the master key IV
+ // first, the encryption key IV
int offset = 0;
int len = mkBlob[offset++];
IV = Arrays.copyOfRange(mkBlob, offset, offset + len);
offset += len;
- // then the master key itself
+ // then the encryption key itself
len = mkBlob[offset++];
- byte[] mk = Arrays.copyOfRange(mkBlob,
+ byte[] encryptionKey = Arrays.copyOfRange(mkBlob,
offset, offset + len);
offset += len;
- // and finally the master key checksum hash
+ // and finally the encryption key checksum hash
len = mkBlob[offset++];
byte[] mkChecksum = Arrays.copyOfRange(mkBlob,
offset, offset + len);
- // now validate the decrypted master key against the checksum
- byte[] calculatedCk = PasswordUtils.makeKeyChecksum(algorithm, mk, ckSalt,
+ // now validate the decrypted encryption key against the checksum
+ byte[] calculatedCk = PasswordUtils.makeKeyChecksum(algorithm, encryptionKey, ckSalt,
rounds);
if (Arrays.equals(calculatedCk, mkChecksum)) {
ivSpec = new IvParameterSpec(IV);
c.init(Cipher.DECRYPT_MODE,
- new SecretKeySpec(mk, "AES"),
+ new SecretKeySpec(encryptionKey, "AES"),
ivSpec);
// Only if all of the above worked properly will 'result' be assigned
result = new CipherInputStream(rawInStream, c);
@@ -265,7 +264,7 @@ public class PerformAdbRestoreTask implements Runnable {
}
} catch (BadPaddingException e) {
// This case frequently occurs when the wrong password is used to decrypt
- // the master key. Use the identical "incorrect password" log text as is
+ // the encryption key. Use the identical "incorrect password" log text as is
// used in the checksum failure log in order to avoid providing additional
// information to an attacker.
if (doLog) {
@@ -273,7 +272,7 @@ public class PerformAdbRestoreTask implements Runnable {
}
} catch (IllegalBlockSizeException e) {
if (doLog) {
- Slog.w(TAG, "Invalid block size in master key");
+ Slog.w(TAG, "Invalid block size in encryption key");
}
} catch (NoSuchAlgorithmException e) {
if (doLog) {
@@ -309,15 +308,15 @@ public class PerformAdbRestoreTask implements Runnable {
int rounds = Integer.parseInt(readHeaderLine(rawInStream)); // 7
String userIvHex = readHeaderLine(rawInStream); // 8
- String masterKeyBlobHex = readHeaderLine(rawInStream); // 9
+ String encryptionKeyBlobHex = readHeaderLine(rawInStream); // 9
- // decrypt the master key blob
- result = attemptMasterKeyDecryption(decryptPassword, PBKDF_CURRENT,
- userSalt, ckSalt, rounds, userIvHex, masterKeyBlobHex, rawInStream, false);
+ // decrypt the encryption key blob
+ result = attemptEncryptionKeyDecryption(decryptPassword, PBKDF_CURRENT, userSalt,
+ ckSalt, rounds, userIvHex, encryptionKeyBlobHex, rawInStream, false);
if (result == null && pbkdf2Fallback) {
- result = attemptMasterKeyDecryption(
+ result = attemptEncryptionKeyDecryption(
decryptPassword, PBKDF_FALLBACK, userSalt, ckSalt,
- rounds, userIvHex, masterKeyBlobHex, rawInStream, true);
+ rounds, userIvHex, encryptionKeyBlobHex, rawInStream, true);
}
} else {
Slog.w(TAG, "Unsupported encryption method: " + encryptionName);
diff --git a/services/backup/java/com/android/server/backup/utils/BackupEligibilityRules.java b/services/backup/java/com/android/server/backup/utils/BackupEligibilityRules.java
index 162921528e95..ee05c2b9ea3b 100644
--- a/services/backup/java/com/android/server/backup/utils/BackupEligibilityRules.java
+++ b/services/backup/java/com/android/server/backup/utils/BackupEligibilityRules.java
@@ -37,7 +37,6 @@ import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.backup.IBackupTransport;
import com.android.internal.util.ArrayUtils;
-import com.android.server.LocalServices;
import com.android.server.backup.transport.TransportClient;
import com.google.android.collect.Sets;
@@ -49,8 +48,8 @@ import java.util.Set;
*/
public class BackupEligibilityRules {
private static final boolean DEBUG = false;
- // Whitelist of system packages that are eligible for backup in non-system users.
- private static final Set<String> systemPackagesWhitelistedForAllUsers =
+ // List of system packages that are eligible for backup in non-system users.
+ private static final Set<String> systemPackagesAllowedForAllUsers =
Sets.newArraySet(PACKAGE_MANAGER_SENTINEL, PLATFORM_PACKAGE_NAME);
private final PackageManager mPackageManager;
@@ -97,9 +96,10 @@ public class BackupEligibilityRules {
// 2. they run as a system-level uid
if (UserHandle.isCore(app.uid)) {
- // and the backup is happening for non-system user on a non-whitelisted package.
+ // and the backup is happening for a non-system user on a package that is not explicitly
+ // allowed.
if (mUserId != UserHandle.USER_SYSTEM
- && !systemPackagesWhitelistedForAllUsers.contains(app.packageName)) {
+ && !systemPackagesAllowedForAllUsers.contains(app.packageName)) {
return false;
}
diff --git a/services/core/Android.bp b/services/core/Android.bp
index 64d0e911652e..1093515ac525 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -128,6 +128,7 @@ java_library_static {
"android.hidl.manager-V1.2-java",
"capture_state_listener-aidl-java",
"dnsresolver_aidl_interface-java",
+ "icu4j_calendar_astronomer",
"netd_aidl_interfaces-platform-java",
"overlayable_policy_aidl-java",
"SurfaceFlingerProperties",
diff --git a/services/core/java/com/android/server/BinderCallsStatsService.java b/services/core/java/com/android/server/BinderCallsStatsService.java
index f1d74bb08b85..a3c04be02c6f 100644
--- a/services/core/java/com/android/server/BinderCallsStatsService.java
+++ b/services/core/java/com/android/server/BinderCallsStatsService.java
@@ -59,16 +59,16 @@ public class BinderCallsStatsService extends Binder {
/** Resolves the work source of an incoming binder transaction. */
static class AuthorizedWorkSourceProvider implements BinderInternal.WorkSourceProvider {
- private ArraySet<Integer> mAppIdWhitelist;
+ private ArraySet<Integer> mAppIdTrustlist;
AuthorizedWorkSourceProvider() {
- mAppIdWhitelist = new ArraySet<>();
+ mAppIdTrustlist = new ArraySet<>();
}
public int resolveWorkSourceUid(int untrustedWorkSourceUid) {
final int callingUid = getCallingUid();
final int appId = UserHandle.getAppId(callingUid);
- if (mAppIdWhitelist.contains(appId)) {
+ if (mAppIdTrustlist.contains(appId)) {
final int workSource = untrustedWorkSourceUid;
final boolean isWorkSourceSet = workSource != Binder.UNSET_WORKSOURCE;
return isWorkSourceSet ? workSource : callingUid;
@@ -77,13 +77,13 @@ public class BinderCallsStatsService extends Binder {
}
public void systemReady(Context context) {
- mAppIdWhitelist = createAppidWhitelist(context);
+ mAppIdTrustlist = createAppidTrustlist(context);
}
public void dump(PrintWriter pw, AppIdToPackageMap packageMap) {
pw.println("AppIds of apps that can set the work source:");
- final ArraySet<Integer> whitelist = mAppIdWhitelist;
- for (Integer appId : whitelist) {
+ final ArraySet<Integer> trustlist = mAppIdTrustlist;
+ for (Integer appId : trustlist) {
pw.println("\t- " + packageMap.mapAppId(appId));
}
}
@@ -92,12 +92,12 @@ public class BinderCallsStatsService extends Binder {
return Binder.getCallingUid();
}
- private ArraySet<Integer> createAppidWhitelist(Context context) {
- // Use a local copy instead of mAppIdWhitelist to prevent concurrent read access.
- final ArraySet<Integer> whitelist = new ArraySet<>();
+ private ArraySet<Integer> createAppidTrustlist(Context context) {
+ // Use a local copy instead of mAppIdTrustlist to prevent concurrent read access.
+ final ArraySet<Integer> trustlist = new ArraySet<>();
// We trust our own process.
- whitelist.add(UserHandle.getAppId(Process.myUid()));
+ trustlist.add(UserHandle.getAppId(Process.myUid()));
// We only need to initialize it once. UPDATE_DEVICE_STATS is a system permission.
final PackageManager pm = context.getPackageManager();
final String[] permissions = { android.Manifest.permission.UPDATE_DEVICE_STATS };
@@ -110,12 +110,12 @@ public class BinderCallsStatsService extends Binder {
try {
final int uid = pm.getPackageUid(pkgInfo.packageName, queryFlags);
final int appId = UserHandle.getAppId(uid);
- whitelist.add(appId);
+ trustlist.add(appId);
} catch (NameNotFoundException e) {
Slog.e(TAG, "Cannot find uid for package name " + pkgInfo.packageName, e);
}
}
- return whitelist;
+ return trustlist;
}
}
diff --git a/services/core/java/com/android/server/GestureLauncherService.java b/services/core/java/com/android/server/GestureLauncherService.java
index c87dcd7874f8..b3d4085288dd 100644
--- a/services/core/java/com/android/server/GestureLauncherService.java
+++ b/services/core/java/com/android/server/GestureLauncherService.java
@@ -38,6 +38,7 @@ import android.os.SystemProperties;
import android.os.Trace;
import android.os.UserHandle;
import android.provider.Settings;
+import android.telecom.TelecomManager;
import android.util.MutableBoolean;
import android.util.Slog;
import android.view.KeyEvent;
@@ -457,6 +458,8 @@ public class GestureLauncherService extends SystemService {
}
} else if (launchPanic) {
Slog.i(TAG, "Panic gesture detected, launching panic.");
+ launchPanic = handlePanicButtonGesture();
+ // TODO(b/160006048): Add logging
}
mMetricsLogger.histogram("power_consecutive_short_tap_count",
mPowerButtonSlowConsecutiveTaps);
@@ -501,6 +504,46 @@ public class GestureLauncherService extends SystemService {
}
}
+ /**
+ * @return true if panic ui was launched, false otherwise.
+ */
+ @VisibleForTesting
+ boolean handlePanicButtonGesture() {
+ // TODO(b/160006048): This is the wrong way to launch panic ui. Rewrite this to go
+ // through SysUI
+ Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
+ "GestureLauncher:handlePanicButtonGesture");
+ try {
+ boolean userSetupComplete = Settings.Secure.getIntForUser(mContext.getContentResolver(),
+ Settings.Secure.USER_SETUP_COMPLETE, 0, UserHandle.USER_CURRENT) != 0;
+ if (!userSetupComplete) {
+ if (DBG) {
+ Slog.d(TAG, String.format(
+ "userSetupComplete = %s, ignoring panic gesture.",
+ userSetupComplete));
+ }
+ return false;
+ }
+ if (DBG) {
+ Slog.d(TAG, String.format(
+ "userSetupComplete = %s, performing panic gesture.",
+ userSetupComplete));
+ }
+ // TODO(b/160006048): Not all devices have telephony. Check system feature first.
+ TelecomManager telecomManager = (TelecomManager) mContext.getSystemService(
+ Context.TELECOM_SERVICE);
+ mContext.startActivity(telecomManager.createLaunchEmergencyDialerIntent(null).addFlags(
+ Intent.FLAG_ACTIVITY_NEW_TASK
+ | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
+ | Intent.FLAG_ACTIVITY_SINGLE_TOP).putExtra(
+ "com.android.phone.EmergencyDialer.extra.ENTRY_TYPE",
+ 2)); // 2 maps to power button, forcing into fast emergency dialer experience.
+ return true;
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
+ }
+ }
+
private final BroadcastReceiver mUserReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
diff --git a/services/core/java/com/android/server/ServiceWatcher.java b/services/core/java/com/android/server/ServiceWatcher.java
index e5d0021a2bdf..0038dc2e8da0 100644
--- a/services/core/java/com/android/server/ServiceWatcher.java
+++ b/services/core/java/com/android/server/ServiceWatcher.java
@@ -80,10 +80,16 @@ public class ServiceWatcher implements ServiceConnection {
default void onError() {}
}
+ /** Function to run on binder interface when first bound. */
+ public interface OnBindRunner {
+ /** Called to run client code with the binder. */
+ void run(IBinder binder, ComponentName service) throws RemoteException;
+ }
+
/**
* Information on the service ServiceWatcher has selected as the best option for binding.
*/
- public static final class ServiceInfo implements Comparable<ServiceInfo> {
+ private static final class ServiceInfo implements Comparable<ServiceInfo> {
public static final ServiceInfo NONE = new ServiceInfo(Integer.MIN_VALUE, null,
UserHandle.USER_NULL, false);
@@ -179,25 +185,25 @@ public class ServiceWatcher implements ServiceConnection {
private final Handler mHandler;
private final Intent mIntent;
- @Nullable private final BinderRunner mOnBind;
+ @Nullable private final OnBindRunner mOnBind;
@Nullable private final Runnable mOnUnbind;
// read/write from handler thread only
private int mCurrentUserId;
// write from handler thread only, read anywhere
- private volatile ServiceInfo mServiceInfo;
+ private volatile ServiceInfo mTargetService;
private volatile IBinder mBinder;
public ServiceWatcher(Context context, String action,
- @Nullable BinderRunner onBind, @Nullable Runnable onUnbind,
+ @Nullable OnBindRunner onBind, @Nullable Runnable onUnbind,
@BoolRes int enableOverlayResId, @StringRes int nonOverlayPackageResId) {
this(context, FgThread.getHandler(), action, onBind, onUnbind, enableOverlayResId,
nonOverlayPackageResId);
}
public ServiceWatcher(Context context, Handler handler, String action,
- @Nullable BinderRunner onBind, @Nullable Runnable onUnbind,
+ @Nullable OnBindRunner onBind, @Nullable Runnable onUnbind,
@BoolRes int enableOverlayResId, @StringRes int nonOverlayPackageResId) {
mContext = context;
mHandler = handler;
@@ -214,7 +220,7 @@ public class ServiceWatcher implements ServiceConnection {
mCurrentUserId = UserHandle.USER_NULL;
- mServiceInfo = ServiceInfo.NONE;
+ mTargetService = ServiceInfo.NONE;
mBinder = null;
}
@@ -304,7 +310,7 @@ public class ServiceWatcher implements ServiceConnection {
}
}
- if (forceRebind || !bestServiceInfo.equals(mServiceInfo)) {
+ if (forceRebind || !bestServiceInfo.equals(mTargetService)) {
rebind(bestServiceInfo);
}
}
@@ -312,32 +318,32 @@ public class ServiceWatcher implements ServiceConnection {
private void rebind(ServiceInfo newServiceInfo) {
Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
- if (!mServiceInfo.equals(ServiceInfo.NONE)) {
+ if (!mTargetService.equals(ServiceInfo.NONE)) {
if (D) {
- Log.i(TAG, "[" + mIntent.getAction() + "] unbinding from " + mServiceInfo);
+ Log.i(TAG, "[" + mIntent.getAction() + "] unbinding from " + mTargetService);
}
mContext.unbindService(this);
- onServiceDisconnected(mServiceInfo.component);
- mServiceInfo = ServiceInfo.NONE;
+ onServiceDisconnected(mTargetService.component);
+ mTargetService = ServiceInfo.NONE;
}
- mServiceInfo = newServiceInfo;
- if (mServiceInfo.equals(ServiceInfo.NONE)) {
+ mTargetService = newServiceInfo;
+ if (mTargetService.equals(ServiceInfo.NONE)) {
return;
}
- Preconditions.checkState(mServiceInfo.component != null);
+ Preconditions.checkState(mTargetService.component != null);
if (D) {
- Log.i(TAG, getLogPrefix() + " binding to " + mServiceInfo);
+ Log.i(TAG, getLogPrefix() + " binding to " + mTargetService);
}
- Intent bindIntent = new Intent(mIntent).setComponent(mServiceInfo.component);
+ Intent bindIntent = new Intent(mIntent).setComponent(mTargetService.component);
if (!mContext.bindServiceAsUser(bindIntent, this,
BIND_AUTO_CREATE | BIND_NOT_FOREGROUND | BIND_NOT_VISIBLE,
- mHandler, UserHandle.of(mServiceInfo.userId))) {
- mServiceInfo = ServiceInfo.NONE;
+ mHandler, UserHandle.of(mTargetService.userId))) {
+ mTargetService = ServiceInfo.NONE;
Log.e(TAG, getLogPrefix() + " unexpected bind failure - retrying later");
mHandler.postDelayed(() -> onBestServiceChanged(false), RETRY_DELAY_MS);
}
@@ -355,11 +361,11 @@ public class ServiceWatcher implements ServiceConnection {
mBinder = binder;
if (mOnBind != null) {
try {
- mOnBind.run(binder);
+ mOnBind.run(binder, component);
} catch (RuntimeException | RemoteException e) {
// binders may propagate some specific non-RemoteExceptions from the other side
// through the binder as well - we cannot allow those to crash the system server
- Log.e(TAG, getLogPrefix() + " exception running on " + mServiceInfo, e);
+ Log.e(TAG, getLogPrefix() + " exception running on " + component, e);
}
}
}
@@ -406,7 +412,7 @@ public class ServiceWatcher implements ServiceConnection {
void onPackageChanged(String packageName) {
// force a rebind if the changed package was the currently connected package
- onBestServiceChanged(packageName.equals(mServiceInfo.getPackageName()));
+ onBestServiceChanged(packageName.equals(mTargetService.getPackageName()));
}
/**
@@ -425,7 +431,7 @@ public class ServiceWatcher implements ServiceConnection {
} catch (RuntimeException | RemoteException e) {
// binders may propagate some specific non-RemoteExceptions from the other side
// through the binder as well - we cannot allow those to crash the system server
- Log.e(TAG, getLogPrefix() + " exception running on " + mServiceInfo, e);
+ Log.e(TAG, getLogPrefix() + " exception running on " + mTargetService, e);
runner.onError();
}
});
@@ -437,14 +443,14 @@ public class ServiceWatcher implements ServiceConnection {
@Override
public String toString() {
- return mServiceInfo.toString();
+ return mTargetService.toString();
}
/**
* Dump for debugging.
*/
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- pw.println("service=" + mServiceInfo);
+ pw.println("target service=" + mTargetService);
pw.println("connected=" + (mBinder != null));
}
}
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 676b76704b81..7381da1676f5 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -63,7 +63,6 @@ import android.telephony.CellSignalStrengthLte;
import android.telephony.CellSignalStrengthNr;
import android.telephony.CellSignalStrengthTdscdma;
import android.telephony.CellSignalStrengthWcdma;
-import android.telephony.DataFailCause;
import android.telephony.DisconnectCause;
import android.telephony.LocationAccessPolicy;
import android.telephony.PhoneCapability;
@@ -112,11 +111,11 @@ import java.util.NoSuchElementException;
* Change-Id: I450c968bda93767554b5188ee63e10c9f43c5aa4 fixes bugs 16148026
* and 15973975 by saving the phoneId of the registrant and then using the
* phoneId when deciding to to make a callback. This is necessary because
- * a subId changes from to a dummy value when a SIM is removed and thus won't
+ * a subId changes from to a placeholder value when a SIM is removed and thus won't
* compare properly. Because getPhoneIdFromSubId(int subId) handles
- * the dummy value conversion we properly do the callbacks.
+ * the placeholder value conversion we properly do the callbacks.
*
- * Eventually we may want to remove the notion of dummy value but for now this
+ * Eventually we may want to remove the notion of placeholder value but for now this
* looks like the best approach.
*/
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
@@ -1800,11 +1799,11 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
if (validatePhoneId(phoneId)) {
mPreciseDataConnectionStates.get(phoneId).put(
apnType,
- new PreciseDataConnectionState(
- TelephonyManager.DATA_UNKNOWN,
- TelephonyManager.NETWORK_TYPE_UNKNOWN,
- apnType, null, null,
- DataFailCause.NONE, null));
+ new PreciseDataConnectionState.Builder()
+ .setApnSetting(new ApnSetting.Builder()
+ .setApnTypeBitmask(apnType)
+ .build())
+ .build());
for (Record r : mRecords) {
if (r.matchPhoneStateListenerEvent(
PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE)
@@ -1986,11 +1985,12 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
if (validatePhoneId(phoneId)) {
mPreciseDataConnectionStates.get(phoneId).put(
apnType,
- new PreciseDataConnectionState(
- TelephonyManager.DATA_UNKNOWN,
- TelephonyManager.NETWORK_TYPE_UNKNOWN,
- apnType, null, null,
- failCause, null));
+ new PreciseDataConnectionState.Builder()
+ .setApnSetting(new ApnSetting.Builder()
+ .setApnTypeBitmask(apnType)
+ .build())
+ .setFailCause(failCause)
+ .build());
for (Record r : mRecords) {
if (r.matchPhoneStateListenerEvent(
PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE)
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index bd51c7a1773d..1680963e26d1 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -2559,12 +2559,12 @@ public final class ActiveServices {
private int getAllowMode(Intent service, @Nullable String callingPackage) {
if (callingPackage == null || service.getComponent() == null) {
- return ActivityManagerInternal.ALLOW_NON_FULL_IN_PROFILE;
+ return ActivityManagerInternal.ALLOW_NON_FULL_IN_PROFILE_OR_FULL;
}
if (callingPackage.equals(service.getComponent().getPackageName())) {
- return ActivityManagerInternal.ALLOW_ALL_PROFILE_PERMISSIONS_IN_PROFILE;
+ return ActivityManagerInternal.ALLOW_ACROSS_PROFILES_IN_PROFILE_OR_FULL;
} else {
- return ActivityManagerInternal.ALLOW_NON_FULL_IN_PROFILE;
+ return ActivityManagerInternal.ALLOW_NON_FULL_IN_PROFILE_OR_FULL;
}
}
@@ -4881,12 +4881,9 @@ public final class ActiveServices {
if (instr != null && instr.mHasBackgroundActivityStartsPermission) {
return true;
}
- }
-
- final boolean hasAllowBackgroundActivityStartsToken = r.app != null
- ? !r.app.mAllowBackgroundActivityStartsTokens.isEmpty() : false;
- if (hasAllowBackgroundActivityStartsToken) {
- return true;
+ if (r.app.areBackgroundActivityStartsAllowedByToken()) {
+ return true;
+ }
}
if (mAm.checkPermission(START_ACTIVITIES_FROM_BACKGROUND, callingPid, callingUid)
diff --git a/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java b/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java
index f872c6bd1b8b..171b20c03689 100644
--- a/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java
+++ b/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java
@@ -81,7 +81,6 @@ class ActivityManagerDebugConfig {
static final String POSTFIX_PROCESS_OBSERVERS = (APPEND_CATEGORY_NAME)
? "_ProcessObservers" : "";
static final String POSTFIX_PROCESSES = (APPEND_CATEGORY_NAME) ? "_Processes" : "";
- static final String POSTFIX_PROVIDER = (APPEND_CATEGORY_NAME) ? "_Provider" : "";
static final String POSTFIX_PSS = (APPEND_CATEGORY_NAME) ? "_Pss" : "";
static final String POSTFIX_SERVICE = (APPEND_CATEGORY_NAME) ? "_Service" : "";
static final String POSTFIX_SERVICE_EXECUTING =
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index cfd2bf913b9c..2f7d105e7a48 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -21,20 +21,16 @@ import static android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST;
import static android.Manifest.permission.FILTER_EVENTS;
import static android.Manifest.permission.INTERACT_ACROSS_USERS;
import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
-import static android.Manifest.permission.REMOVE_TASKS;
import static android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND;
import static android.app.ActivityManager.INSTR_FLAG_DISABLE_HIDDEN_API_CHECKS;
import static android.app.ActivityManager.INSTR_FLAG_DISABLE_ISOLATED_STORAGE;
import static android.app.ActivityManager.INSTR_FLAG_DISABLE_TEST_API_CHECKS;
-import static android.app.ActivityManager.PROCESS_STATE_LAST_ACTIVITY;
import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT;
import static android.app.ActivityManager.PROCESS_STATE_TOP;
import static android.app.ActivityManagerInternal.ALLOW_FULL_ONLY;
import static android.app.ActivityManagerInternal.ALLOW_NON_FULL;
import static android.app.AppOpsManager.OP_NONE;
-import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static android.content.pm.ApplicationInfo.HIDDEN_API_ENFORCEMENT_DEFAULT;
-import static android.content.pm.PackageManager.GET_PROVIDERS;
import static android.content.pm.PackageManager.GET_SHARED_LIBRARY_FILES;
import static android.content.pm.PackageManager.MATCH_ALL;
import static android.content.pm.PackageManager.MATCH_ANY_USER;
@@ -54,9 +50,7 @@ import static android.os.Process.FIRST_APPLICATION_UID;
import static android.os.Process.NETWORK_STACK_UID;
import static android.os.Process.NFC_UID;
import static android.os.Process.PHONE_UID;
-import static android.os.Process.PROC_CHAR;
import static android.os.Process.PROC_OUT_LONG;
-import static android.os.Process.PROC_PARENS;
import static android.os.Process.PROC_SPACE_TERM;
import static android.os.Process.ROOT_UID;
import static android.os.Process.SCHED_FIFO;
@@ -98,11 +92,9 @@ import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BROADCAST_L
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_MU;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_NETWORK;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_OOM_ADJ;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PERMISSIONS_REVIEW;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_POWER;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PROCESSES;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PROCESS_OBSERVERS;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PROVIDER;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PSS;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SERVICE;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_UID_OBSERVERS;
@@ -117,7 +109,6 @@ import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_OOM_ADJ;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_POWER;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_PROCESSES;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_PROCESS_OBSERVERS;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_PROVIDER;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_PSS;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_SERVICE;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_UID_OBSERVERS;
@@ -195,10 +186,8 @@ import android.content.BroadcastReceiver;
import android.content.ComponentCallbacks2;
import android.content.ComponentName;
import android.content.ContentCaptureOptions;
-import android.content.ContentProvider;
import android.content.ContentResolver;
import android.content.Context;
-import android.content.IContentProvider;
import android.content.IIntentReceiver;
import android.content.IIntentSender;
import android.content.Intent;
@@ -217,7 +206,6 @@ import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.PackageManagerInternal;
import android.content.pm.PackageParser;
import android.content.pm.ParceledListSlice;
-import android.content.pm.PathPermission;
import android.content.pm.PermissionInfo;
import android.content.pm.ProcessInfo;
import android.content.pm.ProviderInfo;
@@ -350,7 +338,6 @@ import com.android.server.LocalServices;
import com.android.server.LockGuard;
import com.android.server.NetworkManagementInternal;
import com.android.server.PackageWatchdog;
-import com.android.server.RescueParty;
import com.android.server.ServiceThread;
import com.android.server.SystemConfig;
import com.android.server.SystemService;
@@ -405,7 +392,6 @@ import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
-import java.util.Objects;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
@@ -431,13 +417,12 @@ public class ActivityManagerService extends IActivityManager.Stub
private static final String TAG_CONFIGURATION = TAG + POSTFIX_CONFIGURATION;
private static final String TAG_LOCKTASK = TAG + POSTFIX_LOCKTASK;
static final String TAG_LRU = TAG + POSTFIX_LRU;
- private static final String TAG_MU = TAG + POSTFIX_MU;
+ static final String TAG_MU = TAG + POSTFIX_MU;
static final String TAG_NETWORK = TAG + POSTFIX_NETWORK;
static final String TAG_OOM_ADJ = TAG + POSTFIX_OOM_ADJ;
private static final String TAG_POWER = TAG + POSTFIX_POWER;
static final String TAG_PROCESS_OBSERVERS = TAG + POSTFIX_PROCESS_OBSERVERS;
static final String TAG_PROCESSES = TAG + POSTFIX_PROCESSES;
- private static final String TAG_PROVIDER = TAG + POSTFIX_PROVIDER;
static final String TAG_PSS = TAG + POSTFIX_PSS;
private static final String TAG_SERVICE = TAG + POSTFIX_SERVICE;
private static final String TAG_SWITCH = TAG + POSTFIX_SWITCH;
@@ -1144,53 +1129,10 @@ public class ActivityManagerService extends IActivityManager.Stub
@GuardedBy("this")
final SparseArray<BackupRecord> mBackupTargets = new SparseArray<>();
- final ProviderMap mProviderMap;
-
- /**
- * List of content providers who have clients waiting for them. The
- * application is currently being launched and the provider will be
- * removed from this list once it is published.
- */
- final ArrayList<ContentProviderRecord> mLaunchingProviders = new ArrayList<>();
-
- boolean mSystemProvidersInstalled;
+ final ContentProviderHelper mCpHelper;
CoreSettingsObserver mCoreSettingsObserver;
- DevelopmentSettingsObserver mDevelopmentSettingsObserver;
-
- private final class DevelopmentSettingsObserver extends ContentObserver {
- private final Uri mUri = Settings.Global
- .getUriFor(Settings.Global.DEVELOPMENT_SETTINGS_ENABLED);
-
- private final ComponentName mBugreportStorageProvider = new ComponentName(
- "com.android.shell", "com.android.shell.BugreportStorageProvider");
-
- public DevelopmentSettingsObserver() {
- super(mHandler);
- mContext.getContentResolver().registerContentObserver(mUri, false, this,
- UserHandle.USER_ALL);
- // Always kick once to ensure that we match current state
- onChange();
- }
-
- @Override
- public void onChange(boolean selfChange, Uri uri, @UserIdInt int userId) {
- if (mUri.equals(uri)) {
- onChange();
- }
- }
-
- public void onChange() {
- final boolean enabled = Settings.Global.getInt(mContext.getContentResolver(),
- Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, Build.IS_ENG ? 1 : 0) != 0;
- mContext.getPackageManager().setComponentEnabledSetting(mBugreportStorageProvider,
- enabled ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED
- : PackageManager.COMPONENT_ENABLED_STATE_DEFAULT,
- 0);
- }
- }
-
/**
* Thread-local storage used to carry caller permissions over through
* indirect content-provider access.
@@ -1827,7 +1769,7 @@ public class ActivityManagerService extends IActivityManager.Stub
case CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG: {
ProcessRecord app = (ProcessRecord)msg.obj;
synchronized (ActivityManagerService.this) {
- processContentProviderPublishTimedOutLocked(app);
+ mCpHelper.processContentProviderPublishTimedOutLocked(app);
}
} break;
case KILL_APPLICATION_MSG: {
@@ -2570,7 +2512,7 @@ public class ActivityManagerService extends IActivityManager.Stub
? new IntentFirewall(new IntentFirewallInterface(), mHandler) : null;
mProcessCpuThread = null;
mProcessStats = null;
- mProviderMap = null;
+ mCpHelper = new ContentProviderHelper(this, false);
// For the usage of {@link ActiveServices#cleanUpServices} that may be invoked from
// {@link ActivityStackSupervisor#cleanUpRemovedTaskLocked}.
mServices = hasHandlerThread ? new ActiveServices(this) : null;
@@ -2651,7 +2593,7 @@ public class ActivityManagerService extends IActivityManager.Stub
mBroadcastQueues[2] = mOffloadBroadcastQueue;
mServices = new ActiveServices(this);
- mProviderMap = new ProviderMap(this);
+ mCpHelper = new ContentProviderHelper(this, true);
mPackageWatchdog = PackageWatchdog.getInstance(mUiContext);
mAppErrors = new AppErrors(mUiContext, this, mPackageWatchdog);
@@ -4325,11 +4267,11 @@ public class ActivityManagerService extends IActivityManager.Stub
intent.putExtra(Intent.EXTRA_PACKAGE_NAME, packageName);
broadcastIntentInPackage("android", null, SYSTEM_UID, uid, pid, intent,
null, null, 0, null, null, permission.ACCESS_INSTANT_APPS, null,
- false, false, resolvedUserId, false);
+ false, false, resolvedUserId, false, null);
} else {
broadcastIntentInPackage("android", null, SYSTEM_UID, uid, pid, intent,
null, null, 0, null, null, null, null, false, false, resolvedUserId,
- false);
+ false, null);
}
if (observer != null) {
@@ -4854,10 +4796,10 @@ public class ActivityManagerService extends IActivityManager.Stub
// Clean-up disabled providers.
ArrayList<ContentProviderRecord> providers = new ArrayList<>();
- mProviderMap.collectPackageProvidersLocked(
+ mCpHelper.getProviderMap().collectPackageProvidersLocked(
packageName, disabledClasses, true, false, userId, providers);
for (int i = providers.size() - 1; i >= 0; i--) {
- removeDyingProviderLocked(null, providers.get(i), true);
+ mCpHelper.removeDyingProviderLocked(null, providers.get(i), true);
}
// Clean-up disabled broadcast receivers.
@@ -4951,15 +4893,15 @@ public class ActivityManagerService extends IActivityManager.Stub
}
ArrayList<ContentProviderRecord> providers = new ArrayList<>();
- if (mProviderMap.collectPackageProvidersLocked(packageName, null, doit, evenPersistent,
- userId, providers)) {
+ if (mCpHelper.getProviderMap().collectPackageProvidersLocked(packageName, null, doit,
+ evenPersistent, userId, providers)) {
if (!doit) {
return true;
}
didSomething = true;
}
for (i = providers.size() - 1; i >= 0; i--) {
- removeDyingProviderLocked(null, providers.get(i), true);
+ mCpHelper.removeDyingProviderLocked(null, providers.get(i), true);
}
// Remove transient permissions granted from/to this package/user
@@ -4993,15 +4935,6 @@ public class ActivityManagerService extends IActivityManager.Stub
}
@GuardedBy("this")
- private final void processContentProviderPublishTimedOutLocked(ProcessRecord app) {
- cleanupAppInLaunchingProvidersLocked(app, true);
- mProcessList.removeProcessLocked(app, false, true,
- ApplicationExitInfo.REASON_INITIALIZATION_FAILURE,
- ApplicationExitInfo.SUBREASON_UNKNOWN,
- "timeout publishing content providers");
- }
-
- @GuardedBy("this")
private final void processStartTimedOutLocked(ProcessRecord app) {
final int pid = app.pid;
boolean gone = removePidIfNoThread(app);
@@ -5013,7 +4946,7 @@ public class ActivityManagerService extends IActivityManager.Stub
mAtmInternal.clearHeavyWeightProcessIfEquals(app.getWindowProcessController());
mBatteryStatsService.noteProcessFinish(app.processName, app.info.uid);
// Take care of any launching providers waiting for this process.
- cleanupAppInLaunchingProvidersLocked(app, true);
+ mCpHelper.cleanupAppInLaunchingProvidersLocked(app, true);
// Take care of any services that are waiting for the process.
mServices.processStartTimedOutLocked(app);
app.kill("start timeout", ApplicationExitInfo.REASON_INITIALIZATION_FAILURE, true);
@@ -5161,9 +5094,11 @@ public class ActivityManagerService extends IActivityManager.Stub
mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
boolean normalMode = mProcessesReady || isAllowedWhileBooting(app.info);
- List<ProviderInfo> providers = normalMode ? generateApplicationProvidersLocked(app) : null;
+ List<ProviderInfo> providers = normalMode
+ ? mCpHelper.generateApplicationProvidersLocked(app)
+ : null;
- if (providers != null && checkAppInLaunchingProvidersLocked(app)) {
+ if (providers != null && mCpHelper.checkAppInLaunchingProvidersLocked(app)) {
Message msg = mHandler.obtainMessage(CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG);
msg.obj = app;
mHandler.sendMessageDelayed(msg,
@@ -5483,6 +5418,14 @@ public class ActivityManagerService extends IActivityManager.Stub
}
}
+ void checkTime(long startTime, String where) {
+ long now = SystemClock.uptimeMillis();
+ if ((now - startTime) > 50) {
+ // If we are taking more than 50ms, log about it.
+ Slog.w(TAG, "Slow operation: " + (now - startTime) + "ms so far, now at " + where);
+ }
+ }
+
@Override
public void showBootMessage(final CharSequence msg, final boolean always) {
if (Binder.getCallingUid() != myUid()) {
@@ -6467,22 +6410,6 @@ public class ActivityManagerService extends IActivityManager.Stub
return ptw != null ? ptw.tag : null;
}
- private ProviderInfo getProviderInfoLocked(String authority, @UserIdInt int userId,
- int pmFlags) {
- ProviderInfo pi = null;
- ContentProviderRecord cpr = mProviderMap.getProviderByName(authority, userId);
- if (cpr != null) {
- pi = cpr.info;
- } else {
- try {
- pi = AppGlobals.getPackageManager().resolveContentProvider(
- authority, PackageManager.GET_URI_PERMISSION_PATTERNS | pmFlags, userId);
- } catch (RemoteException ex) {
- }
- }
- return pi;
- }
-
@VisibleForTesting
public void grantImplicitAccess(int userId, Intent intent, int visibleUid, int recipientAppId) {
getPackageManagerInternalLocked().
@@ -6574,7 +6501,7 @@ public class ActivityManagerService extends IActivityManager.Stub
}
final String authority = uri.getAuthority();
- final ProviderInfo pi = getProviderInfoLocked(authority, userId,
+ final ProviderInfo pi = mCpHelper.getProviderInfoLocked(authority, userId,
MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE);
if (pi == null) {
Slog.w(TAG, "No content provider found for permission revoke: "
@@ -6752,803 +6679,6 @@ public class ActivityManagerService extends IActivityManager.Stub
mActivityTaskManager.startSystemLockTaskMode(taskId);
}
- // =========================================================
- // CONTENT PROVIDERS
- // =========================================================
-
- private final List<ProviderInfo> generateApplicationProvidersLocked(ProcessRecord app) {
- List<ProviderInfo> providers = null;
- try {
- providers = AppGlobals.getPackageManager()
- .queryContentProviders(app.processName, app.uid,
- STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS
- | MATCH_DEBUG_TRIAGED_MISSING, /*metadastaKey=*/ null)
- .getList();
- } catch (RemoteException ex) {
- }
- if (DEBUG_MU) Slog.v(TAG_MU,
- "generateApplicationProvidersLocked, app.info.uid = " + app.uid);
- int userId = app.userId;
- if (providers != null) {
- int N = providers.size();
- app.pubProviders.ensureCapacity(N + app.pubProviders.size());
- for (int i=0; i<N; i++) {
- // TODO: keep logic in sync with installEncryptionUnawareProviders
- ProviderInfo cpi =
- (ProviderInfo)providers.get(i);
- boolean singleton = isSingleton(cpi.processName, cpi.applicationInfo,
- cpi.name, cpi.flags);
- if (singleton && UserHandle.getUserId(app.uid) != UserHandle.USER_SYSTEM) {
- // This is a singleton provider, but a user besides the
- // default user is asking to initialize a process it runs
- // in... well, no, it doesn't actually run in this process,
- // it runs in the process of the default user. Get rid of it.
- providers.remove(i);
- N--;
- i--;
- continue;
- }
-
- ComponentName comp = new ComponentName(cpi.packageName, cpi.name);
- ContentProviderRecord cpr = mProviderMap.getProviderByClass(comp, userId);
- if (cpr == null) {
- cpr = new ContentProviderRecord(this, cpi, app.info, comp, singleton);
- mProviderMap.putProviderByClass(comp, cpr);
- }
- if (DEBUG_MU) Slog.v(TAG_MU,
- "generateApplicationProvidersLocked, cpi.uid = " + cpr.uid);
- app.pubProviders.put(cpi.name, cpr);
- if (!cpi.multiprocess || !"android".equals(cpi.packageName)) {
- // Don't add this if it is a platform component that is marked
- // to run in multiple processes, because this is actually
- // part of the framework so doesn't make sense to track as a
- // separate apk in the process.
- app.addPackage(cpi.applicationInfo.packageName,
- cpi.applicationInfo.longVersionCode, mProcessStats);
- }
- notifyPackageUse(cpi.applicationInfo.packageName,
- PackageManager.NOTIFY_PACKAGE_USE_CONTENT_PROVIDER);
- }
- }
- return providers;
- }
-
- /**
- * Check if the calling UID has a possible chance at accessing the provider
- * at the given authority and user.
- */
- public String checkContentProviderAccess(String authority, int userId) {
- if (userId == UserHandle.USER_ALL) {
- mContext.enforceCallingOrSelfPermission(
- Manifest.permission.INTERACT_ACROSS_USERS_FULL, TAG);
- userId = UserHandle.getCallingUserId();
- }
-
- ProviderInfo cpi = null;
- try {
- cpi = AppGlobals.getPackageManager().resolveContentProvider(authority,
- STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS
- | PackageManager.MATCH_DISABLED_COMPONENTS
- | PackageManager.MATCH_DIRECT_BOOT_AWARE
- | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
- userId);
- } catch (RemoteException ignored) {
- }
- if (cpi == null) {
- return "Failed to find provider " + authority + " for user " + userId
- + "; expected to find a valid ContentProvider for this authority";
- }
-
- ProcessRecord r = null;
- synchronized (mPidsSelfLocked) {
- r = mPidsSelfLocked.get(Binder.getCallingPid());
- }
- if (r == null) {
- return "Failed to find PID " + Binder.getCallingPid();
- }
-
- synchronized (this) {
- return checkContentProviderPermissionLocked(cpi, r, userId, true);
- }
- }
-
- /**
- * Check if {@link ProcessRecord} has a possible chance at accessing the
- * given {@link ProviderInfo}. Final permission checking is always done
- * in {@link ContentProvider}.
- */
- private final String checkContentProviderPermissionLocked(
- ProviderInfo cpi, ProcessRecord r, int userId, boolean checkUser) {
- final int callingPid = (r != null) ? r.pid : Binder.getCallingPid();
- final int callingUid = (r != null) ? r.uid : Binder.getCallingUid();
- boolean checkedGrants = false;
- if (checkUser) {
- // Looking for cross-user grants before enforcing the typical cross-users permissions
- int tmpTargetUserId = mUserController.unsafeConvertIncomingUser(userId);
- if (tmpTargetUserId != UserHandle.getUserId(callingUid)) {
- if (mUgmInternal.checkAuthorityGrants(
- callingUid, cpi, tmpTargetUserId, checkUser)) {
- return null;
- }
- checkedGrants = true;
- }
- userId = mUserController.handleIncomingUser(callingPid, callingUid, userId, false,
- ALLOW_NON_FULL, "checkContentProviderPermissionLocked " + cpi.authority, null);
- if (userId != tmpTargetUserId) {
- // When we actually went to determine the final targer user ID, this ended
- // up different than our initial check for the authority. This is because
- // they had asked for USER_CURRENT_OR_SELF and we ended up switching to
- // SELF. So we need to re-check the grants again.
- checkedGrants = false;
- }
- }
- if (checkComponentPermission(cpi.readPermission, callingPid, callingUid,
- cpi.applicationInfo.uid, cpi.exported)
- == PackageManager.PERMISSION_GRANTED) {
- return null;
- }
- if (checkComponentPermission(cpi.writePermission, callingPid, callingUid,
- cpi.applicationInfo.uid, cpi.exported)
- == PackageManager.PERMISSION_GRANTED) {
- return null;
- }
-
- PathPermission[] pps = cpi.pathPermissions;
- if (pps != null) {
- int i = pps.length;
- while (i > 0) {
- i--;
- PathPermission pp = pps[i];
- String pprperm = pp.getReadPermission();
- if (pprperm != null && checkComponentPermission(pprperm, callingPid, callingUid,
- cpi.applicationInfo.uid, cpi.exported)
- == PackageManager.PERMISSION_GRANTED) {
- return null;
- }
- String ppwperm = pp.getWritePermission();
- if (ppwperm != null && checkComponentPermission(ppwperm, callingPid, callingUid,
- cpi.applicationInfo.uid, cpi.exported)
- == PackageManager.PERMISSION_GRANTED) {
- return null;
- }
- }
- }
- if (!checkedGrants
- && mUgmInternal.checkAuthorityGrants(callingUid, cpi, userId, checkUser)) {
- return null;
- }
-
- final String suffix;
- if (!cpi.exported) {
- suffix = " that is not exported from UID " + cpi.applicationInfo.uid;
- } else if (android.Manifest.permission.MANAGE_DOCUMENTS.equals(cpi.readPermission)) {
- suffix = " requires that you obtain access using ACTION_OPEN_DOCUMENT or related APIs";
- } else {
- suffix = " requires " + cpi.readPermission + " or " + cpi.writePermission;
- }
- final String msg = "Permission Denial: opening provider " + cpi.name
- + " from " + (r != null ? r : "(null)") + " (pid=" + callingPid
- + ", uid=" + callingUid + ")" + suffix;
- Slog.w(TAG, msg);
- return msg;
- }
-
- @GuardedBy("this")
- private ContentProviderConnection incProviderCountLocked(ProcessRecord r,
- final ContentProviderRecord cpr, IBinder externalProcessToken, int callingUid,
- String callingPackage, String callingTag, boolean stable,
- boolean updateLru, long startTime) {
- if (r != null) {
- for (int i=0; i<r.conProviders.size(); i++) {
- ContentProviderConnection conn = r.conProviders.get(i);
- if (conn.provider == cpr) {
- conn.incrementCount(stable);
- return conn;
- }
- }
-
- // Create a new ContentProviderConnection. The reference count
- // is known to be 1.
- ContentProviderConnection conn = new ContentProviderConnection(cpr, r, callingPackage);
- conn.startAssociationIfNeeded();
- conn.initializeCount(stable);
- cpr.connections.add(conn);
- r.conProviders.add(conn);
- startAssociationLocked(r.uid, r.processName, r.getCurProcState(),
- cpr.uid, cpr.appInfo.longVersionCode, cpr.name, cpr.info.processName);
- if (updateLru && cpr.proc != null
- && r != null && r.setAdj <= ProcessList.PERCEPTIBLE_LOW_APP_ADJ) {
- // If this is a perceptible app accessing the provider, make
- // sure to count it as being accessed and thus back up on
- // the LRU list. This is good because content providers are
- // often expensive to start. The calls to checkTime() use
- // the "getContentProviderImpl" tag here, because it's part
- // of the checktime log in getContentProviderImpl().
- checkTime(startTime, "getContentProviderImpl: before updateLruProcess");
- mProcessList.updateLruProcessLocked(cpr.proc, false, null);
- checkTime(startTime, "getContentProviderImpl: after updateLruProcess");
- }
- return conn;
- }
- cpr.addExternalProcessHandleLocked(externalProcessToken, callingUid, callingTag);
- return null;
- }
-
- @GuardedBy("this")
- private boolean decProviderCountLocked(ContentProviderConnection conn,
- ContentProviderRecord cpr, IBinder externalProcessToken, boolean stable) {
- if (conn != null) {
- cpr = conn.provider;
- final int referenceCount = conn.decrementCount(stable);
- if (referenceCount == 0) {
- conn.stopAssociation();
- cpr.connections.remove(conn);
- conn.client.conProviders.remove(conn);
- if (conn.client.setProcState < PROCESS_STATE_LAST_ACTIVITY) {
- // The client is more important than last activity -- note the time this
- // is happening, so we keep the old provider process around a bit as last
- // activity to avoid thrashing it.
- if (cpr.proc != null) {
- cpr.proc.lastProviderTime = SystemClock.uptimeMillis();
- }
- }
- stopAssociationLocked(conn.client.uid, conn.client.processName, cpr.uid,
- cpr.appInfo.longVersionCode, cpr.name, cpr.info.processName);
- return true;
- }
- return false;
- }
- cpr.removeExternalProcessHandleLocked(externalProcessToken);
- return false;
- }
-
- void checkTime(long startTime, String where) {
- long now = SystemClock.uptimeMillis();
- if ((now-startTime) > 50) {
- // If we are taking more than 50ms, log about it.
- Slog.w(TAG, "Slow operation: " + (now-startTime) + "ms so far, now at " + where);
- }
- }
-
- private static final int[] PROCESS_STATE_STATS_FORMAT = new int[] {
- PROC_SPACE_TERM,
- PROC_SPACE_TERM|PROC_PARENS,
- PROC_SPACE_TERM|PROC_CHAR|PROC_OUT_LONG, // 3: process state
- };
-
- private final long[] mProcessStateStatsLongs = new long[1];
-
- boolean isProcessAliveLocked(ProcessRecord proc) {
- if (proc.pid <= 0) {
- if (DEBUG_OOM_ADJ) Slog.d(TAG, "Process hasn't started yet: " + proc);
- return false;
- }
- if (proc.procStatFile == null) {
- proc.procStatFile = "/proc/" + proc.pid + "/stat";
- }
- mProcessStateStatsLongs[0] = 0;
- if (!readProcFile(proc.procStatFile, PROCESS_STATE_STATS_FORMAT, null,
- mProcessStateStatsLongs, null)) {
- if (DEBUG_OOM_ADJ) Slog.d(TAG, "UNABLE TO RETRIEVE STATE FOR " + proc.procStatFile);
- return false;
- }
- final long state = mProcessStateStatsLongs[0];
- if (DEBUG_OOM_ADJ) Slog.d(TAG, "RETRIEVED STATE FOR " + proc.procStatFile + ": "
- + (char)state);
- if (state != 'Z' && state != 'X' && state != 'x' && state != 'K') {
- return Process.getUidForPid(proc.pid) == proc.uid;
- }
- return false;
- }
-
- private String checkContentProviderAssociation(ProcessRecord callingApp, int callingUid,
- ProviderInfo cpi) {
- if (callingApp == null) {
- return validateAssociationAllowedLocked(cpi.packageName, cpi.applicationInfo.uid,
- null, callingUid) ? null : "<null>";
- }
- for (int i = callingApp.pkgList.size() - 1; i >= 0; i--) {
- if (!validateAssociationAllowedLocked(callingApp.pkgList.keyAt(i), callingApp.uid,
- cpi.packageName, cpi.applicationInfo.uid)) {
- return cpi.packageName;
- }
- }
- return null;
- }
-
- private ContentProviderHolder getContentProviderImpl(IApplicationThread caller,
- String name, IBinder token, int callingUid, String callingPackage, String callingTag,
- boolean stable, int userId) {
- ContentProviderRecord cpr;
- ContentProviderConnection conn = null;
- ProviderInfo cpi = null;
- boolean providerRunning = false;
-
- synchronized(this) {
- long startTime = SystemClock.uptimeMillis();
-
- ProcessRecord r = null;
- if (caller != null) {
- r = getRecordForAppLocked(caller);
- if (r == null) {
- throw new SecurityException(
- "Unable to find app for caller " + caller
- + " (pid=" + Binder.getCallingPid()
- + ") when getting content provider " + name);
- }
- }
-
- boolean checkCrossUser = true;
-
- checkTime(startTime, "getContentProviderImpl: getProviderByName");
-
- // First check if this content provider has been published...
- cpr = mProviderMap.getProviderByName(name, userId);
- // If that didn't work, check if it exists for user 0 and then
- // verify that it's a singleton provider before using it.
- if (cpr == null && userId != UserHandle.USER_SYSTEM) {
- cpr = mProviderMap.getProviderByName(name, UserHandle.USER_SYSTEM);
- if (cpr != null) {
- cpi = cpr.info;
- if (isSingleton(cpi.processName, cpi.applicationInfo,
- cpi.name, cpi.flags)
- && isValidSingletonCall(r == null ? callingUid : r.uid,
- cpi.applicationInfo.uid)) {
- userId = UserHandle.USER_SYSTEM;
- checkCrossUser = false;
- } else {
- cpr = null;
- cpi = null;
- }
- }
- }
-
- ProcessRecord dyingProc = null;
- if (cpr != null && cpr.proc != null) {
- providerRunning = !cpr.proc.killed;
-
- // Note if killedByAm is also set, this means the provider process has just been
- // killed by AM (in ProcessRecord.kill()), but appDiedLocked() hasn't been called
- // yet. So we need to call appDiedLocked() here and let it clean up.
- // (See the commit message on I2c4ba1e87c2d47f2013befff10c49b3dc337a9a7 to see
- // how to test this case.)
- if (cpr.proc.killed && cpr.proc.killedByAm) {
- Slog.wtf(TAG, cpr.proc.toString() + " was killed by AM but isn't really dead");
- // Now we are going to wait for the death before starting the new process.
- dyingProc = cpr.proc;
- }
- }
-
- if (providerRunning) {
- cpi = cpr.info;
- String msg;
-
- if (r != null && cpr.canRunHere(r)) {
- if ((msg = checkContentProviderAssociation(r, callingUid, cpi)) != null) {
- throw new SecurityException("Content provider lookup "
- + cpr.name.flattenToShortString()
- + " failed: association not allowed with package " + msg);
- }
- checkTime(startTime,
- "getContentProviderImpl: before checkContentProviderPermission");
- if ((msg = checkContentProviderPermissionLocked(cpi, r, userId, checkCrossUser))
- != null) {
- throw new SecurityException(msg);
- }
- checkTime(startTime,
- "getContentProviderImpl: after checkContentProviderPermission");
-
- // This provider has been published or is in the process
- // of being published... but it is also allowed to run
- // in the caller's process, so don't make a connection
- // and just let the caller instantiate its own instance.
- ContentProviderHolder holder = cpr.newHolder(null);
- // don't give caller the provider object, it needs
- // to make its own.
- holder.provider = null;
- return holder;
- }
-
- // Don't expose providers between normal apps and instant apps
- try {
- if (AppGlobals.getPackageManager()
- .resolveContentProvider(name, 0 /*flags*/, userId) == null) {
- return null;
- }
- } catch (RemoteException e) {
- }
-
- if ((msg = checkContentProviderAssociation(r, callingUid, cpi)) != null) {
- throw new SecurityException("Content provider lookup "
- + cpr.name.flattenToShortString()
- + " failed: association not allowed with package " + msg);
- }
- checkTime(startTime,
- "getContentProviderImpl: before checkContentProviderPermission");
- if ((msg = checkContentProviderPermissionLocked(cpi, r, userId, checkCrossUser))
- != null) {
- throw new SecurityException(msg);
- }
- checkTime(startTime,
- "getContentProviderImpl: after checkContentProviderPermission");
-
- final long origId = Binder.clearCallingIdentity();
-
- checkTime(startTime, "getContentProviderImpl: incProviderCountLocked");
-
- // In this case the provider instance already exists, so we can
- // return it right away.
- conn = incProviderCountLocked(r, cpr, token, callingUid, callingPackage,
- callingTag, stable, true, startTime);
-
- checkTime(startTime, "getContentProviderImpl: before updateOomAdj");
- final int verifiedAdj = cpr.proc.verifiedAdj;
- boolean success = updateOomAdjLocked(cpr.proc, true,
- OomAdjuster.OOM_ADJ_REASON_GET_PROVIDER);
- // XXX things have changed so updateOomAdjLocked doesn't actually tell us
- // if the process has been successfully adjusted. So to reduce races with
- // it, we will check whether the process still exists. Note that this doesn't
- // completely get rid of races with LMK killing the process, but should make
- // them much smaller.
- if (success && verifiedAdj != cpr.proc.setAdj && !isProcessAliveLocked(cpr.proc)) {
- success = false;
- }
- maybeUpdateProviderUsageStatsLocked(r, cpr.info.packageName, name);
- checkTime(startTime, "getContentProviderImpl: after updateOomAdj");
- if (DEBUG_PROVIDER) Slog.i(TAG_PROVIDER, "Adjust success: " + success);
- // NOTE: there is still a race here where a signal could be
- // pending on the process even though we managed to update its
- // adj level. Not sure what to do about this, but at least
- // the race is now smaller.
- if (!success) {
- // Uh oh... it looks like the provider's process
- // has been killed on us. We need to wait for a new
- // process to be started, and make sure its death
- // doesn't kill our process.
- Slog.wtf(TAG, "Existing provider " + cpr.name.flattenToShortString()
- + " is crashing; detaching " + r);
- boolean lastRef = decProviderCountLocked(conn, cpr, token, stable);
- if (!lastRef) {
- // This wasn't the last ref our process had on
- // the provider... we will be killed during cleaning up, bail.
- return null;
- }
- // We'll just start a new process to host the content provider
- providerRunning = false;
- conn = null;
- dyingProc = cpr.proc;
- } else {
- cpr.proc.verifiedAdj = cpr.proc.setAdj;
- }
-
- Binder.restoreCallingIdentity(origId);
- }
-
- if (!providerRunning) {
- try {
- checkTime(startTime, "getContentProviderImpl: before resolveContentProvider");
- cpi = AppGlobals.getPackageManager().
- resolveContentProvider(name,
- STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS, userId);
- checkTime(startTime, "getContentProviderImpl: after resolveContentProvider");
- } catch (RemoteException ex) {
- }
- if (cpi == null) {
- return null;
- }
- // If the provider is a singleton AND
- // (it's a call within the same user || the provider is a
- // privileged app)
- // Then allow connecting to the singleton provider
- boolean singleton = isSingleton(cpi.processName, cpi.applicationInfo,
- cpi.name, cpi.flags)
- && isValidSingletonCall(r == null ? callingUid : r.uid,
- cpi.applicationInfo.uid);
- if (singleton) {
- userId = UserHandle.USER_SYSTEM;
- }
- cpi.applicationInfo = getAppInfoForUser(cpi.applicationInfo, userId);
- checkTime(startTime, "getContentProviderImpl: got app info for user");
-
- String msg;
- if ((msg = checkContentProviderAssociation(r, callingUid, cpi)) != null) {
- throw new SecurityException("Content provider lookup " + name
- + " failed: association not allowed with package " + msg);
- }
- checkTime(startTime, "getContentProviderImpl: before checkContentProviderPermission");
- if ((msg = checkContentProviderPermissionLocked(cpi, r, userId, !singleton))
- != null) {
- throw new SecurityException(msg);
- }
- checkTime(startTime, "getContentProviderImpl: after checkContentProviderPermission");
-
- if (!mProcessesReady
- && !cpi.processName.equals("system")) {
- // If this content provider does not run in the system
- // process, and the system is not yet ready to run other
- // processes, then fail fast instead of hanging.
- throw new IllegalArgumentException(
- "Attempt to launch content provider before system ready");
- }
-
- // If system providers are not installed yet we aggressively crash to avoid
- // creating multiple instance of these providers and then bad things happen!
- if (!mSystemProvidersInstalled && cpi.applicationInfo.isSystemApp()
- && "system".equals(cpi.processName)) {
- throw new IllegalStateException("Cannot access system provider: '"
- + cpi.authority + "' before system providers are installed!");
- }
-
- // Make sure that the user who owns this provider is running. If not,
- // we don't want to allow it to run.
- if (!mUserController.isUserRunning(userId, 0)) {
- Slog.w(TAG, "Unable to launch app "
- + cpi.applicationInfo.packageName + "/"
- + cpi.applicationInfo.uid + " for provider "
- + name + ": user " + userId + " is stopped");
- return null;
- }
-
- ComponentName comp = new ComponentName(cpi.packageName, cpi.name);
- checkTime(startTime, "getContentProviderImpl: before getProviderByClass");
- cpr = mProviderMap.getProviderByClass(comp, userId);
- checkTime(startTime, "getContentProviderImpl: after getProviderByClass");
- boolean firstClass = cpr == null;
- if (firstClass) {
- final long ident = Binder.clearCallingIdentity();
-
- // If permissions need a review before any of the app components can run,
- // we return no provider and launch a review activity if the calling app
- // is in the foreground.
- if (!requestTargetProviderPermissionsReviewIfNeededLocked(cpi, r, userId)) {
- return null;
- }
-
- try {
- checkTime(startTime, "getContentProviderImpl: before getApplicationInfo");
- ApplicationInfo ai =
- AppGlobals.getPackageManager().
- getApplicationInfo(
- cpi.applicationInfo.packageName,
- STOCK_PM_FLAGS, userId);
- checkTime(startTime, "getContentProviderImpl: after getApplicationInfo");
- if (ai == null) {
- Slog.w(TAG, "No package info for content provider "
- + cpi.name);
- return null;
- }
- ai = getAppInfoForUser(ai, userId);
- cpr = new ContentProviderRecord(this, cpi, ai, comp, singleton);
- } catch (RemoteException ex) {
- // pm is in same process, this will never happen.
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- } else if (dyingProc == cpr.proc && dyingProc != null) {
- // The old stable connection's client should be killed during proc cleaning up,
- // so do not re-use the old ContentProviderRecord, otherwise the new clients
- // could get killed unexpectedly.
- cpr = new ContentProviderRecord(cpr);
- // This is sort of "firstClass"
- firstClass = true;
- }
-
- checkTime(startTime, "getContentProviderImpl: now have ContentProviderRecord");
-
- if (r != null && cpr.canRunHere(r)) {
- // If this is a multiprocess provider, then just return its
- // info and allow the caller to instantiate it. Only do
- // this if the provider is the same user as the caller's
- // process, or can run as root (so can be in any process).
- return cpr.newHolder(null);
- }
-
- if (DEBUG_PROVIDER) Slog.w(TAG_PROVIDER, "LAUNCHING REMOTE PROVIDER (myuid "
- + (r != null ? r.uid : null) + " pruid " + cpr.appInfo.uid + "): "
- + cpr.info.name + " callers=" + Debug.getCallers(6));
-
- // This is single process, and our app is now connecting to it.
- // See if we are already in the process of launching this
- // provider.
- final int N = mLaunchingProviders.size();
- int i;
- for (i = 0; i < N; i++) {
- if (mLaunchingProviders.get(i) == cpr) {
- break;
- }
- }
-
- // If the provider is not already being launched, then get it
- // started.
- if (i >= N) {
- final long origId = Binder.clearCallingIdentity();
-
- try {
- // Content provider is now in use, its package can't be stopped.
- try {
- checkTime(startTime, "getContentProviderImpl: before set stopped state");
- AppGlobals.getPackageManager().setPackageStoppedState(
- cpr.appInfo.packageName, false, userId);
- checkTime(startTime, "getContentProviderImpl: after set stopped state");
- } catch (RemoteException e) {
- } catch (IllegalArgumentException e) {
- Slog.w(TAG, "Failed trying to unstop package "
- + cpr.appInfo.packageName + ": " + e);
- }
-
- // Use existing process if already started
- checkTime(startTime, "getContentProviderImpl: looking for process record");
- ProcessRecord proc = getProcessRecordLocked(
- cpi.processName, cpr.appInfo.uid, false);
- if (proc != null && proc.thread != null && !proc.killed) {
- if (DEBUG_PROVIDER) Slog.d(TAG_PROVIDER,
- "Installing in existing process " + proc);
- if (!proc.pubProviders.containsKey(cpi.name)) {
- checkTime(startTime, "getContentProviderImpl: scheduling install");
- proc.pubProviders.put(cpi.name, cpr);
- try {
- proc.thread.scheduleInstallProvider(cpi);
- } catch (RemoteException e) {
- }
- }
- } else {
- checkTime(startTime, "getContentProviderImpl: before start process");
- proc = startProcessLocked(cpi.processName,
- cpr.appInfo, false, 0,
- new HostingRecord("content provider",
- new ComponentName(cpi.applicationInfo.packageName,
- cpi.name)),
- ZYGOTE_POLICY_FLAG_EMPTY, false, false, false);
- checkTime(startTime, "getContentProviderImpl: after start process");
- if (proc == null) {
- Slog.w(TAG, "Unable to launch app "
- + cpi.applicationInfo.packageName + "/"
- + cpi.applicationInfo.uid + " for provider "
- + name + ": process is bad");
- return null;
- }
- }
- cpr.launchingApp = proc;
- mLaunchingProviders.add(cpr);
- } finally {
- Binder.restoreCallingIdentity(origId);
- }
- }
-
- checkTime(startTime, "getContentProviderImpl: updating data structures");
-
- // Make sure the provider is published (the same provider class
- // may be published under multiple names).
- if (firstClass) {
- mProviderMap.putProviderByClass(comp, cpr);
- }
-
- mProviderMap.putProviderByName(name, cpr);
- conn = incProviderCountLocked(r, cpr, token, callingUid,
- callingPackage, callingTag, stable, false, startTime);
- if (conn != null) {
- conn.waiting = true;
- }
- }
- checkTime(startTime, "getContentProviderImpl: done!");
-
- grantImplicitAccess(userId, null /*intent*/, callingUid,
- UserHandle.getAppId(cpi.applicationInfo.uid));
- }
-
- // Wait for the provider to be published...
- final long timeout =
- SystemClock.uptimeMillis() + ContentResolver.CONTENT_PROVIDER_READY_TIMEOUT_MILLIS;
- boolean timedOut = false;
- synchronized (cpr) {
- while (cpr.provider == null) {
- if (cpr.launchingApp == null) {
- Slog.w(TAG, "Unable to launch app "
- + cpi.applicationInfo.packageName + "/"
- + cpi.applicationInfo.uid + " for provider "
- + name + ": launching app became null");
- EventLogTags.writeAmProviderLostProcess(
- UserHandle.getUserId(cpi.applicationInfo.uid),
- cpi.applicationInfo.packageName,
- cpi.applicationInfo.uid, name);
- return null;
- }
- try {
- final long wait = Math.max(0L, timeout - SystemClock.uptimeMillis());
- if (DEBUG_MU) Slog.v(TAG_MU,
- "Waiting to start provider " + cpr
- + " launchingApp=" + cpr.launchingApp + " for " + wait + " ms");
- if (conn != null) {
- conn.waiting = true;
- }
- cpr.wait(wait);
- if (cpr.provider == null) {
- timedOut = true;
- break;
- }
- } catch (InterruptedException ex) {
- } finally {
- if (conn != null) {
- conn.waiting = false;
- }
- }
- }
- }
- if (timedOut) {
- // Note we do it after releasing the lock.
- String callerName = "unknown";
- if (caller != null) {
- synchronized (this) {
- final ProcessRecord record = mProcessList.getLRURecordForAppLocked(caller);
- if (record != null) {
- callerName = record.processName;
- }
- }
- }
-
- Slog.wtf(TAG, "Timeout waiting for provider "
- + cpi.applicationInfo.packageName + "/"
- + cpi.applicationInfo.uid + " for provider "
- + name
- + " providerRunning=" + providerRunning
- + " caller=" + callerName + "/" + Binder.getCallingUid());
- return null;
- }
-
- return cpr.newHolder(conn);
- }
-
- private static final class StartActivityRunnable implements Runnable {
- private final Context mContext;
- private final Intent mIntent;
- private final UserHandle mUserHandle;
-
- StartActivityRunnable(Context context, Intent intent, UserHandle userHandle) {
- this.mContext = context;
- this.mIntent = intent;
- this.mUserHandle = userHandle;
- }
-
- @Override
- public void run() {
- mContext.startActivityAsUser(mIntent, mUserHandle);
- }
- }
-
- private boolean requestTargetProviderPermissionsReviewIfNeededLocked(ProviderInfo cpi,
- ProcessRecord r, final int userId) {
- if (getPackageManagerInternalLocked().isPermissionsReviewRequired(
- cpi.packageName, userId)) {
-
- final boolean callerForeground = r == null || r.setSchedGroup
- != ProcessList.SCHED_GROUP_BACKGROUND;
-
- // Show a permission review UI only for starting from a foreground app
- if (!callerForeground) {
- Slog.w(TAG, "u" + userId + " Instantiating a provider in package"
- + cpi.packageName + " requires a permissions review");
- return false;
- }
-
- final Intent intent = new Intent(Intent.ACTION_REVIEW_PERMISSIONS);
- intent.addFlags(FLAG_ACTIVITY_NEW_TASK
- | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
- intent.putExtra(Intent.EXTRA_PACKAGE_NAME, cpi.packageName);
-
- if (DEBUG_PERMISSIONS_REVIEW) {
- Slog.i(TAG, "u" + userId + " Launching permission review "
- + "for package " + cpi.packageName);
- }
-
- final UserHandle userHandle = new UserHandle(userId);
- mHandler.post(new StartActivityRunnable(mContext, intent, userHandle));
-
- return false;
- }
-
- return true;
- }
-
/**
* Returns the PackageManager. Used by classes hosted by {@link ActivityManagerService}. The
* PackageManager could be unavailable at construction time and therefore needs to be accessed
@@ -7576,71 +6706,65 @@ public class ActivityManagerService extends IActivityManager.Stub
}
@Override
+ public void appNotResponding(final String reason) {
+ final int callingPid = Binder.getCallingPid();
+
+ synchronized (mPidsSelfLocked) {
+ final ProcessRecord app = mPidsSelfLocked.get(callingPid);
+ if (app == null) {
+ throw new SecurityException("Unknown process: " + callingPid);
+ }
+
+ mAnrHelper.appNotResponding(app, null, app.info, null, null, false,
+ "App requested: " + reason);
+ }
+ }
+
+ void startPersistentApps(int matchFlags) {
+ if (mFactoryTest == FactoryTest.FACTORY_TEST_LOW_LEVEL) return;
+
+ synchronized (this) {
+ try {
+ final List<ApplicationInfo> apps = AppGlobals.getPackageManager()
+ .getPersistentApplications(STOCK_PM_FLAGS | matchFlags).getList();
+ for (ApplicationInfo app : apps) {
+ if (!"android".equals(app.packageName)) {
+ addAppLocked(app, null, false, null /* ABI override */,
+ ZYGOTE_POLICY_FLAG_BATCH_LAUNCH);
+ }
+ }
+ } catch (RemoteException ex) {
+ }
+ }
+ }
+
+ // =========================================================
+ // CONTENT PROVIDERS
+ // =========================================================
+
+ public ContentProviderHelper getContentProviderHelper() {
+ return mCpHelper;
+ }
+
+ @Override
public final ContentProviderHolder getContentProvider(
IApplicationThread caller, String callingPackage, String name, int userId,
boolean stable) {
- enforceNotIsolatedCaller("getContentProvider");
- if (caller == null) {
- String msg = "null IApplicationThread when getting content provider "
- + name;
- Slog.w(TAG, msg);
- throw new SecurityException(msg);
- }
- // The incoming user check is now handled in checkContentProviderPermissionLocked() to deal
- // with cross-user grant.
- final int callingUid = Binder.getCallingUid();
- if (callingPackage != null && mAppOpsService.checkPackage(callingUid, callingPackage)
- != AppOpsManager.MODE_ALLOWED) {
- throw new SecurityException("Given calling package " + callingPackage
- + " does not match caller's uid " + callingUid);
- }
- return getContentProviderImpl(caller, name, null, callingUid, callingPackage,
- null, stable, userId);
+ return mCpHelper.getContentProvider(caller, callingPackage, name, userId, stable);
}
+ @Override
public ContentProviderHolder getContentProviderExternal(
String name, int userId, IBinder token, String tag) {
- enforceCallingPermission(android.Manifest.permission.ACCESS_CONTENT_PROVIDERS_EXTERNALLY,
- "Do not have permission in call getContentProviderExternal()");
- userId = mUserController.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
- userId, false, ALLOW_FULL_ONLY, "getContentProvider", null);
- return getContentProviderExternalUnchecked(name, token, Binder.getCallingUid(),
- tag != null ? tag : "*external*", userId);
- }
-
- private ContentProviderHolder getContentProviderExternalUnchecked(String name,
- IBinder token, int callingUid, String callingTag, int userId) {
- return getContentProviderImpl(null, name, token, callingUid, null, callingTag,
- true, userId);
+ return mCpHelper.getContentProviderExternal(name, userId, token, tag);
}
/**
* Drop a content provider from a ProcessRecord's bookkeeping
*/
+ @Override
public void removeContentProvider(IBinder connection, boolean stable) {
- enforceNotIsolatedCaller("removeContentProvider");
- long ident = Binder.clearCallingIdentity();
- try {
- synchronized (this) {
- ContentProviderConnection conn;
- try {
- conn = (ContentProviderConnection)connection;
- } catch (ClassCastException e) {
- String msg ="removeContentProvider: " + connection
- + " not a ContentProviderConnection";
- Slog.w(TAG, msg);
- throw new IllegalArgumentException(msg);
- }
- if (conn == null) {
- throw new NullPointerException("connection is null");
- }
- if (decProviderCountLocked(conn, null, null, stable)) {
- updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_REMOVE_PROVIDER);
- }
- }
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
+ mCpHelper.removeContentProvider(connection, stable);
}
/** @deprecated - Use {@link #removeContentProviderExternalAsUser} which takes a user ID. */
@@ -7652,334 +6776,28 @@ public class ActivityManagerService extends IActivityManager.Stub
@Override
public void removeContentProviderExternalAsUser(String name, IBinder token, int userId) {
- enforceCallingPermission(android.Manifest.permission.ACCESS_CONTENT_PROVIDERS_EXTERNALLY,
- "Do not have permission in call removeContentProviderExternal()");
- long ident = Binder.clearCallingIdentity();
- try {
- removeContentProviderExternalUnchecked(name, token, userId);
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- }
-
- private void removeContentProviderExternalUnchecked(String name, IBinder token, int userId) {
- synchronized (this) {
- ContentProviderRecord cpr = mProviderMap.getProviderByName(name, userId);
- if(cpr == null) {
- //remove from mProvidersByClass
- if(DEBUG_ALL) Slog.v(TAG, name+" content provider not found in providers list");
- return;
- }
-
- //update content provider record entry info
- ComponentName comp = new ComponentName(cpr.info.packageName, cpr.info.name);
- ContentProviderRecord localCpr = mProviderMap.getProviderByClass(comp, userId);
- if (localCpr.hasExternalProcessHandles()) {
- if (localCpr.removeExternalProcessHandleLocked(token)) {
- updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_REMOVE_PROVIDER);
- } else {
- Slog.e(TAG, "Attmpt to remove content provider " + localCpr
- + " with no external reference for token: "
- + token + ".");
- }
- } else {
- Slog.e(TAG, "Attmpt to remove content provider: " + localCpr
- + " with no external references.");
- }
- }
+ mCpHelper.removeContentProviderExternalAsUser(name, token, userId);
}
+ @Override
public final void publishContentProviders(IApplicationThread caller,
List<ContentProviderHolder> providers) {
- if (providers == null) {
- return;
- }
-
- enforceNotIsolatedCaller("publishContentProviders");
- synchronized (this) {
- final ProcessRecord r = getRecordForAppLocked(caller);
- if (DEBUG_MU) Slog.v(TAG_MU, "ProcessRecord uid = " + r.uid);
- if (r == null) {
- throw new SecurityException(
- "Unable to find app for caller " + caller
- + " (pid=" + Binder.getCallingPid()
- + ") when publishing content providers");
- }
-
- final long origId = Binder.clearCallingIdentity();
-
- final int N = providers.size();
- for (int i = 0; i < N; i++) {
- ContentProviderHolder src = providers.get(i);
- if (src == null || src.info == null || src.provider == null) {
- continue;
- }
- ContentProviderRecord dst = r.pubProviders.get(src.info.name);
- if (DEBUG_MU) Slog.v(TAG_MU, "ContentProviderRecord uid = " + dst.uid);
- if (dst != null) {
- ComponentName comp = new ComponentName(dst.info.packageName, dst.info.name);
- mProviderMap.putProviderByClass(comp, dst);
- String names[] = dst.info.authority.split(";");
- for (int j = 0; j < names.length; j++) {
- mProviderMap.putProviderByName(names[j], dst);
- }
-
- int launchingCount = mLaunchingProviders.size();
- int j;
- boolean wasInLaunchingProviders = false;
- for (j = 0; j < launchingCount; j++) {
- if (mLaunchingProviders.get(j) == dst) {
- mLaunchingProviders.remove(j);
- wasInLaunchingProviders = true;
- j--;
- launchingCount--;
- }
- }
- if (wasInLaunchingProviders) {
- mHandler.removeMessages(CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG, r);
- }
- // Make sure the package is associated with the process.
- // XXX We shouldn't need to do this, since we have added the package
- // when we generated the providers in generateApplicationProvidersLocked().
- // But for some reason in some cases we get here with the package no longer
- // added... for now just patch it in to make things happy.
- r.addPackage(dst.info.applicationInfo.packageName,
- dst.info.applicationInfo.longVersionCode, mProcessStats);
- synchronized (dst) {
- dst.provider = src.provider;
- dst.setProcess(r);
- dst.notifyAll();
- }
- dst.mRestartCount = 0;
- updateOomAdjLocked(r, true, OomAdjuster.OOM_ADJ_REASON_GET_PROVIDER);
- maybeUpdateProviderUsageStatsLocked(r, src.info.packageName,
- src.info.authority);
- }
- }
-
- Binder.restoreCallingIdentity(origId);
- }
+ mCpHelper.publishContentProviders(caller, providers);
}
@Override
public boolean refContentProvider(IBinder connection, int stable, int unstable) {
- ContentProviderConnection conn;
- try {
- conn = (ContentProviderConnection)connection;
- } catch (ClassCastException e) {
- String msg ="refContentProvider: " + connection
- + " not a ContentProviderConnection";
- Slog.w(TAG, msg);
- throw new IllegalArgumentException(msg);
- }
- if (conn == null) {
- throw new NullPointerException("connection is null");
- }
-
- conn.adjustCounts(stable, unstable);
- return !conn.dead;
+ return mCpHelper.refContentProvider(connection, stable, unstable);
}
+ @Override
public void unstableProviderDied(IBinder connection) {
- ContentProviderConnection conn;
- try {
- conn = (ContentProviderConnection)connection;
- } catch (ClassCastException e) {
- String msg ="refContentProvider: " + connection
- + " not a ContentProviderConnection";
- Slog.w(TAG, msg);
- throw new IllegalArgumentException(msg);
- }
- if (conn == null) {
- throw new NullPointerException("connection is null");
- }
-
- // Safely retrieve the content provider associated with the connection.
- IContentProvider provider;
- synchronized (this) {
- provider = conn.provider.provider;
- }
-
- if (provider == null) {
- // Um, yeah, we're way ahead of you.
- return;
- }
-
- // Make sure the caller is being honest with us.
- if (provider.asBinder().pingBinder()) {
- // Er, no, still looks good to us.
- synchronized (this) {
- Slog.w(TAG, "unstableProviderDied: caller " + Binder.getCallingUid()
- + " says " + conn + " died, but we don't agree");
- return;
- }
- }
-
- // Well look at that! It's dead!
- synchronized (this) {
- if (conn.provider.provider != provider) {
- // But something changed... good enough.
- return;
- }
-
- ProcessRecord proc = conn.provider.proc;
- if (proc == null || proc.thread == null) {
- // Seems like the process is already cleaned up.
- return;
- }
-
- // As far as we're concerned, this is just like receiving a
- // death notification... just a bit prematurely.
- reportUidInfoMessageLocked(TAG,
- "Process " + proc.processName + " (pid " + proc.pid
- + ") early provider death",
- proc.info.uid);
- final long ident = Binder.clearCallingIdentity();
- try {
- appDiedLocked(proc, "unstable content provider");
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- }
+ mCpHelper.unstableProviderDied(connection);
}
@Override
public void appNotRespondingViaProvider(IBinder connection) {
- enforceCallingPermission(REMOVE_TASKS, "appNotRespondingViaProvider()");
-
- final ContentProviderConnection conn = (ContentProviderConnection) connection;
- if (conn == null) {
- Slog.w(TAG, "ContentProviderConnection is null");
- return;
- }
-
- final ProcessRecord host = conn.provider.proc;
- if (host == null) {
- Slog.w(TAG, "Failed to find hosting ProcessRecord");
- return;
- }
-
- mAnrHelper.appNotResponding(host, "ContentProvider not responding");
- }
-
- @Override
- public void appNotResponding(final String reason) {
- final int callingPid = Binder.getCallingPid();
-
- synchronized (mPidsSelfLocked) {
- final ProcessRecord app = mPidsSelfLocked.get(callingPid);
- if (app == null) {
- throw new SecurityException("Unknown process: " + callingPid);
- }
-
- mAnrHelper.appNotResponding(app, null, app.info, null, null, false,
- "App requested: " + reason);
- }
- }
-
- public final void installSystemProviders() {
- List<ProviderInfo> providers;
- synchronized (this) {
- ProcessRecord app = mProcessList.mProcessNames.get("system", SYSTEM_UID);
- providers = generateApplicationProvidersLocked(app);
- if (providers != null) {
- for (int i=providers.size()-1; i>=0; i--) {
- ProviderInfo pi = (ProviderInfo)providers.get(i);
- if ((pi.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) == 0) {
- Slog.w(TAG, "Not installing system proc provider " + pi.name
- + ": not system .apk");
- providers.remove(i);
- }
- }
- }
- }
- if (providers != null) {
- mSystemThread.installSystemProviders(providers);
- }
-
- synchronized (this) {
- mSystemProvidersInstalled = true;
- }
- mConstants.start(mContext.getContentResolver());
- mCoreSettingsObserver = new CoreSettingsObserver(this);
- mActivityTaskManager.installSystemProviders();
- mDevelopmentSettingsObserver = new DevelopmentSettingsObserver();
- SettingsToPropertiesMapper.start(mContext.getContentResolver());
- mOomAdjuster.initSettings();
-
- // Now that the settings provider is published we can consider sending
- // in a rescue party.
- RescueParty.onSettingsProviderPublished(mContext);
-
- //mUsageStatsService.monitorPackages();
- }
-
- void startPersistentApps(int matchFlags) {
- if (mFactoryTest == FactoryTest.FACTORY_TEST_LOW_LEVEL) return;
-
- synchronized (this) {
- try {
- final List<ApplicationInfo> apps = AppGlobals.getPackageManager()
- .getPersistentApplications(STOCK_PM_FLAGS | matchFlags).getList();
- for (ApplicationInfo app : apps) {
- if (!"android".equals(app.packageName)) {
- addAppLocked(app, null, false, null /* ABI override */,
- ZYGOTE_POLICY_FLAG_BATCH_LAUNCH);
- }
- }
- } catch (RemoteException ex) {
- }
- }
- }
-
- /**
- * When a user is unlocked, we need to install encryption-unaware providers
- * belonging to any running apps.
- */
- void installEncryptionUnawareProviders(int userId) {
- // We're only interested in providers that are encryption unaware, and
- // we don't care about uninstalled apps, since there's no way they're
- // running at this point.
- final int matchFlags = GET_PROVIDERS | MATCH_DIRECT_BOOT_UNAWARE;
-
- synchronized (this) {
- final int NP = mProcessList.mProcessNames.getMap().size();
- for (int ip = 0; ip < NP; ip++) {
- final SparseArray<ProcessRecord> apps = mProcessList.mProcessNames.getMap().valueAt
- (ip);
- final int NA = apps.size();
- for (int ia = 0; ia < NA; ia++) {
- final ProcessRecord app = apps.valueAt(ia);
- if (app.userId != userId || app.thread == null || app.unlocked) continue;
-
- final int NG = app.pkgList.size();
- for (int ig = 0; ig < NG; ig++) {
- try {
- final String pkgName = app.pkgList.keyAt(ig);
- final PackageInfo pkgInfo = AppGlobals.getPackageManager()
- .getPackageInfo(pkgName, matchFlags, userId);
- if (pkgInfo != null && !ArrayUtils.isEmpty(pkgInfo.providers)) {
- for (ProviderInfo pi : pkgInfo.providers) {
- // TODO: keep in sync with generateApplicationProvidersLocked
- final boolean processMatch = Objects.equals(pi.processName,
- app.processName) || pi.multiprocess;
- final boolean userMatch = isSingleton(pi.processName,
- pi.applicationInfo, pi.name, pi.flags)
- ? (app.userId == UserHandle.USER_SYSTEM) : true;
- if (processMatch && userMatch) {
- Log.v(TAG, "Installing " + pi);
- app.thread.scheduleInstallProvider(pi);
- } else {
- Log.v(TAG, "Skipping " + pi);
- }
- }
- }
- } catch (RemoteException ignored) {
- }
- }
- }
- }
- }
+ mCpHelper.appNotRespondingViaProvider(connection);
}
/**
@@ -7996,64 +6814,9 @@ public class ActivityManagerService extends IActivityManager.Stub
* @deprecated -- use getProviderMimeTypeAsync.
*/
@Deprecated
+ @Override
public String getProviderMimeType(Uri uri, int userId) {
- enforceNotIsolatedCaller("getProviderMimeType");
- final String name = uri.getAuthority();
- int callingUid = Binder.getCallingUid();
- int callingPid = Binder.getCallingPid();
- long ident = 0;
- boolean clearedIdentity = false;
- userId = mUserController.unsafeConvertIncomingUser(userId);
- if (canClearIdentity(callingPid, callingUid, userId)) {
- clearedIdentity = true;
- ident = Binder.clearCallingIdentity();
- }
- ContentProviderHolder holder = null;
- try {
- holder = getContentProviderExternalUnchecked(name, null, callingUid,
- "*getmimetype*", userId);
- if (holder != null) {
- final IBinder providerConnection = holder.connection;
- final ComponentName providerName = holder.info.getComponentName();
- // Note: creating a new Runnable instead of using a lambda here since lambdas in
- // java provide no guarantee that there will be a new instance returned every call.
- // Hence, it's possible that a cached copy is returned and the ANR is executed on
- // the incorrect provider.
- final Runnable providerNotResponding = new Runnable() {
- @Override
- public void run() {
- Log.w(TAG, "Provider " + providerName + " didn't return from getType().");
- appNotRespondingViaProvider(providerConnection);
- }
- };
- mHandler.postDelayed(providerNotResponding, 1000);
- try {
- return holder.provider.getType(uri);
- } finally {
- mHandler.removeCallbacks(providerNotResponding);
- }
- }
- } catch (RemoteException e) {
- Log.w(TAG, "Content provider dead retrieving " + uri, e);
- return null;
- } catch (Exception e) {
- Log.w(TAG, "Exception while determining type of " + uri, e);
- return null;
- } finally {
- // We need to clear the identity to call removeContentProviderExternalUnchecked
- if (!clearedIdentity) {
- ident = Binder.clearCallingIdentity();
- }
- try {
- if (holder != null) {
- removeContentProviderExternalUnchecked(name, null, userId);
- }
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- }
-
- return null;
+ return mCpHelper.getProviderMimeType(uri, userId);
}
/**
@@ -8064,82 +6827,7 @@ public class ActivityManagerService extends IActivityManager.Stub
*/
@Override
public void getProviderMimeTypeAsync(Uri uri, int userId, RemoteCallback resultCallback) {
- enforceNotIsolatedCaller("getProviderMimeTypeAsync");
- final String name = uri.getAuthority();
- final int callingUid = Binder.getCallingUid();
- final int callingPid = Binder.getCallingPid();
- final int safeUserId = mUserController.unsafeConvertIncomingUser(userId);
- final long ident = canClearIdentity(callingPid, callingUid, userId)
- ? Binder.clearCallingIdentity() : 0;
- try {
- final ContentProviderHolder holder = getContentProviderExternalUnchecked(name, null,
- callingUid, "*getmimetype*", safeUserId);
- if (holder != null) {
- holder.provider.getTypeAsync(uri, new RemoteCallback(result -> {
- final long identity = Binder.clearCallingIdentity();
- try {
- removeContentProviderExternalUnchecked(name, null, safeUserId);
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
- resultCallback.sendResult(result);
- }));
- } else {
- resultCallback.sendResult(Bundle.EMPTY);
- }
- } catch (RemoteException e) {
- Log.w(TAG, "Content provider dead retrieving " + uri, e);
- resultCallback.sendResult(Bundle.EMPTY);
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- }
-
- int checkContentProviderUriPermission(Uri uri, int userId, int callingUid, int modeFlags) {
- if (Thread.holdsLock(mActivityTaskManager.getGlobalLock())) {
- Slog.wtf(TAG, new IllegalStateException("Unable to check Uri permission"
- + " because caller is holding WM lock; assuming permission denied"));
- return PackageManager.PERMISSION_DENIED;
- }
-
- final String name = uri.getAuthority();
- final long ident = Binder.clearCallingIdentity();
- ContentProviderHolder holder = null;
- try {
- holder = getContentProviderExternalUnchecked(name, null, callingUid,
- "*checkContentProviderUriPermission*", userId);
- if (holder != null) {
- return holder.provider.checkUriPermission(null, null, uri, callingUid, modeFlags);
- }
- } catch (RemoteException e) {
- Log.w(TAG, "Content provider dead retrieving " + uri, e);
- return PackageManager.PERMISSION_DENIED;
- } catch (Exception e) {
- Log.w(TAG, "Exception while determining type of " + uri, e);
- return PackageManager.PERMISSION_DENIED;
- } finally {
- try {
- if (holder != null) {
- removeContentProviderExternalUnchecked(name, null, userId);
- }
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- }
- return PackageManager.PERMISSION_DENIED;
- }
-
- private boolean canClearIdentity(int callingPid, int callingUid, int userId) {
- if (UserHandle.getUserId(callingUid) == userId) {
- return true;
- }
- if (checkComponentPermission(INTERACT_ACROSS_USERS, callingPid,
- callingUid, -1, true) == PackageManager.PERMISSION_GRANTED
- || checkComponentPermission(INTERACT_ACROSS_USERS_FULL, callingPid,
- callingUid, -1, true) == PackageManager.PERMISSION_GRANTED) {
- return true;
- }
- return false;
+ mCpHelper.getProviderMimeTypeAsync(uri, userId, resultCallback);
}
// =========================================================
@@ -8265,12 +6953,13 @@ public class ActivityManagerService extends IActivityManager.Stub
mActivityTaskManager.unhandledBack();
}
+ // TODO: Move to ContentProviderHelper?
public ParcelFileDescriptor openContentUri(String uriString) throws RemoteException {
enforceNotIsolatedCaller("openContentUri");
final int userId = UserHandle.getCallingUserId();
final Uri uri = Uri.parse(uriString);
String name = uri.getAuthority();
- ContentProviderHolder cph = getContentProviderExternalUnchecked(name, null,
+ ContentProviderHolder cph = mCpHelper.getContentProviderExternalUnchecked(name, null,
Binder.getCallingUid(), "*opencontent*", userId);
ParcelFileDescriptor pfd = null;
if (cph != null) {
@@ -8292,7 +6981,7 @@ public class ActivityManagerService extends IActivityManager.Stub
// Ensure that whatever happens, we clean up the identity state
sCallerIdentity.remove();
// Ensure we're done with the provider.
- removeContentProviderExternalUnchecked(name, null, userId);
+ mCpHelper.removeContentProviderExternalUnchecked(name, null, userId);
}
} else {
Slog.d(TAG, "Failed to get provider for authority '" + name + "'");
@@ -10595,7 +9284,7 @@ public class ActivityManagerService extends IActivityManager.Stub
pw.println("-------------------------------------------------------------------------------");
}
}
- dumpProvidersLocked(fd, pw, args, opti, dumpAll, dumpPackage);
+ mCpHelper.dumpProvidersLocked(fd, pw, args, opti, dumpAll, dumpPackage);
pw.println();
if (dumpAll) {
pw.println("-------------------------------------------------------------------------------");
@@ -10787,7 +9476,7 @@ public class ActivityManagerService extends IActivityManager.Stub
if (args.length > 2) System.arraycopy(args, opti, newArgs, 0,
args.length - opti);
}
- if (!dumpProviderProto(fd, pw, name, newArgs)) {
+ if (!mCpHelper.dumpProviderProto(fd, pw, name, newArgs)) {
pw.println("No providers match: " + name);
pw.println("Use -h for help.");
}
@@ -10926,13 +9615,13 @@ public class ActivityManagerService extends IActivityManager.Stub
newArgs = new String[args.length - opti];
if (args.length > 2) System.arraycopy(args, opti, newArgs, 0, args.length - opti);
}
- if (!dumpProvider(fd, pw, name, newArgs, 0, dumpAll)) {
+ if (!mCpHelper.dumpProvider(fd, pw, name, newArgs, 0, dumpAll)) {
pw.println("No providers match: " + name);
pw.println("Use -h for help.");
}
} else if ("providers".equals(cmd) || "prov".equals(cmd)) {
synchronized (this) {
- dumpProvidersLocked(fd, pw, args, opti, true, dumpPackage);
+ mCpHelper.dumpProvidersLocked(fd, pw, args, opti, true, dumpPackage);
}
} else if ("service".equals(cmd)) {
String[] newArgs;
@@ -12167,28 +10856,6 @@ public class ActivityManagerService extends IActivityManager.Stub
reportLmkKillAtOrBelow(pw, ProcessList.FOREGROUND_APP_ADJ);
}
- /**
- * There are three ways to call this:
- * - no provider specified: dump all the providers
- * - a flattened component name that matched an existing provider was specified as the
- * first arg: dump that one provider
- * - the first arg isn't the flattened component name of an existing provider:
- * dump all providers whose component contains the first arg as a substring
- */
- protected boolean dumpProvider(FileDescriptor fd, PrintWriter pw, String name, String[] args,
- int opti, boolean dumpAll) {
- return mProviderMap.dumpProvider(fd, pw, name, args, opti, dumpAll);
- }
-
- /**
- * Similar to the dumpProvider, but only dumps the first matching provider.
- * The provider is responsible for dumping as proto.
- */
- protected boolean dumpProviderProto(FileDescriptor fd, PrintWriter pw, String name,
- String[] args) {
- return mProviderMap.dumpProviderProto(fd, pw, name, args);
- }
-
public static class ItemMatcher {
ArrayList<ComponentName> components;
ArrayList<String> strings;
@@ -12492,43 +11159,6 @@ public class ActivityManagerService extends IActivityManager.Stub
}
}
- void dumpProvidersLocked(FileDescriptor fd, PrintWriter pw, String[] args,
- int opti, boolean dumpAll, String dumpPackage) {
- boolean needSep;
- boolean printedAnything = false;
-
- ItemMatcher matcher = new ItemMatcher();
- matcher.build(args, opti);
-
- pw.println("ACTIVITY MANAGER CONTENT PROVIDERS (dumpsys activity providers)");
-
- needSep = mProviderMap.dumpProvidersLocked(pw, dumpAll, dumpPackage);
- printedAnything |= needSep;
-
- if (mLaunchingProviders.size() > 0) {
- boolean printed = false;
- for (int i=mLaunchingProviders.size()-1; i>=0; i--) {
- ContentProviderRecord r = mLaunchingProviders.get(i);
- if (dumpPackage != null && !dumpPackage.equals(r.name.getPackageName())) {
- continue;
- }
- if (!printed) {
- if (needSep) pw.println();
- needSep = true;
- pw.println(" Launching content providers:");
- printed = true;
- printedAnything = true;
- }
- pw.print(" Launching #"); pw.print(i); pw.print(": ");
- pw.println(r);
- }
- }
-
- if (!printedAnything) {
- pw.println(" (nothing)");
- }
- }
-
@GuardedBy("this")
void dumpPermissionsLocked(FileDescriptor fd, PrintWriter pw, String[] args,
int opti, boolean dumpAll, String dumpPackage) {
@@ -14679,89 +13309,6 @@ public class ActivityManagerService extends IActivityManager.Stub
}
/**
- * Remove the dying provider from known provider map and launching provider map.
- * @param proc The dying process recoder
- * @param cpr The provider to be removed.
- * @param always If true, remove the provider from launching map always, no more restart attempt
- * @return true if the given provider is in launching
- */
- private final boolean removeDyingProviderLocked(ProcessRecord proc,
- ContentProviderRecord cpr, boolean always) {
- boolean inLaunching = mLaunchingProviders.contains(cpr);
- if (inLaunching && !always && ++cpr.mRestartCount > ContentProviderRecord.MAX_RETRY_COUNT) {
- // It's being launched but we've reached maximum attempts, force the removal
- always = true;
- }
-
- if (!inLaunching || always) {
- synchronized (cpr) {
- cpr.launchingApp = null;
- cpr.notifyAll();
- }
- final int userId = UserHandle.getUserId(cpr.uid);
- // Don't remove from provider map if it doesn't match
- // could be a new content provider is starting
- if (mProviderMap.getProviderByClass(cpr.name, userId) == cpr) {
- mProviderMap.removeProviderByClass(cpr.name, userId);
- }
- String names[] = cpr.info.authority.split(";");
- for (int j = 0; j < names.length; j++) {
- // Don't remove from provider map if it doesn't match
- // could be a new content provider is starting
- if (mProviderMap.getProviderByName(names[j], userId) == cpr) {
- mProviderMap.removeProviderByName(names[j], userId);
- }
- }
- }
-
- for (int i = cpr.connections.size() - 1; i >= 0; i--) {
- ContentProviderConnection conn = cpr.connections.get(i);
- if (conn.waiting) {
- // If this connection is waiting for the provider, then we don't
- // need to mess with its process unless we are always removing
- // or for some reason the provider is not currently launching.
- if (inLaunching && !always) {
- continue;
- }
- }
- ProcessRecord capp = conn.client;
- conn.dead = true;
- if (conn.stableCount() > 0) {
- if (!capp.isPersistent() && capp.thread != null
- && capp.pid != 0
- && capp.pid != MY_PID) {
- capp.kill("depends on provider "
- + cpr.name.flattenToShortString()
- + " in dying proc " + (proc != null ? proc.processName : "??")
- + " (adj " + (proc != null ? proc.setAdj : "??") + ")",
- ApplicationExitInfo.REASON_DEPENDENCY_DIED,
- ApplicationExitInfo.SUBREASON_UNKNOWN,
- true);
- }
- } else if (capp.thread != null && conn.provider.provider != null) {
- try {
- capp.thread.unstableProviderDied(conn.provider.provider.asBinder());
- } catch (RemoteException e) {
- }
- // In the protocol here, we don't expect the client to correctly
- // clean up this connection, we'll just remove it.
- cpr.connections.remove(i);
- if (conn.client.conProviders.remove(conn)) {
- stopAssociationLocked(capp.uid, capp.processName, cpr.uid,
- cpr.appInfo.longVersionCode, cpr.name, cpr.info.processName);
- }
- }
- }
-
- if (inLaunching && always) {
- mLaunchingProviders.remove(cpr);
- cpr.mRestartCount = 0;
- inLaunching = false;
- }
- return inLaunching;
- }
-
- /**
* Main code for cleaning up a process when it has gone away. This is
* called both as a result of the process dying, or directly when stopping
* a process when running in single process mode.
@@ -14811,7 +13358,7 @@ public class ActivityManagerService extends IActivityManager.Stub
continue;
}
final boolean alwaysRemove = app.bad || !allowRestart;
- final boolean inLaunching = removeDyingProviderLocked(app, cpr, alwaysRemove);
+ final boolean inLaunching = mCpHelper.removeDyingProviderLocked(app, cpr, alwaysRemove);
if (!alwaysRemove && inLaunching && cpr.hasConnectionOrHandle()) {
// We left the provider in the launching list, need to
// restart it.
@@ -14824,7 +13371,7 @@ public class ActivityManagerService extends IActivityManager.Stub
app.pubProviders.clear();
// Take care of any launching providers waiting for this process.
- if (cleanupAppInLaunchingProvidersLocked(app, false)) {
+ if (mCpHelper.cleanupAppInLaunchingProvidersLocked(app, false)) {
mProcessList.noteProcessDiedLocked(app);
restart = true;
}
@@ -14847,15 +13394,7 @@ public class ActivityManagerService extends IActivityManager.Stub
// XXX Commented out for now. Trying to figure out a way to reproduce
// the actual situation to identify what is actually going on.
if (false) {
- for (int i = mLaunchingProviders.size() - 1; i >= 0; i--) {
- ContentProviderRecord cpr = mLaunchingProviders.get(i);
- if (cpr.connections.size() <= 0 && !cpr.hasExternalProcessHandles()) {
- synchronized (cpr) {
- cpr.launchingApp = null;
- cpr.notifyAll();
- }
- }
- }
+ mCpHelper.cleanupLaunchingProvidersLocked();
}
skipCurrentReceiverLocked(app);
@@ -14975,39 +13514,6 @@ public class ActivityManagerService extends IActivityManager.Stub
return false;
}
- boolean checkAppInLaunchingProvidersLocked(ProcessRecord app) {
- for (int i = mLaunchingProviders.size() - 1; i >= 0; i--) {
- ContentProviderRecord cpr = mLaunchingProviders.get(i);
- if (cpr.launchingApp == app) {
- return true;
- }
- }
- return false;
- }
-
- boolean cleanupAppInLaunchingProvidersLocked(ProcessRecord app, boolean alwaysBad) {
- // Look through the content providers we are waiting to have launched,
- // and if any run in this process then either schedule a restart of
- // the process or kill the client waiting for it if this process has
- // gone bad.
- boolean restart = false;
- for (int i = mLaunchingProviders.size() - 1; i >= 0; i--) {
- ContentProviderRecord cpr = mLaunchingProviders.get(i);
- if (cpr.launchingApp == app) {
- if (++cpr.mRestartCount > ContentProviderRecord.MAX_RETRY_COUNT) {
- // It's being launched but we've reached maximum attempts, mark it as bad
- alwaysBad = true;
- }
- if (!alwaysBad && !app.bad && cpr.hasConnectionOrHandle()) {
- restart = true;
- } else {
- removeDyingProviderLocked(app, cpr, true);
- }
- }
- }
- return restart;
- }
-
// =========================================================
// SERVICES
// =========================================================
@@ -15713,7 +14219,7 @@ public class ActivityManagerService extends IActivityManager.Stub
BroadcastQueue queue = broadcastQueueForIntent(intent);
BroadcastRecord r = new BroadcastRecord(queue, intent, null,
null, null, -1, -1, false, null, null, OP_NONE, null, receivers,
- null, 0, null, null, false, true, true, -1, false,
+ null, 0, null, null, false, true, true, -1, false, null,
false /* only PRE_BOOT_COMPLETED should be exempt, no stickies */);
queue.enqueueParallelBroadcastLocked(r);
queue.scheduleBroadcastsLocked();
@@ -15960,7 +14466,7 @@ public class ActivityManagerService extends IActivityManager.Stub
resolvedType, resultTo, resultCode, resultData, resultExtras, requiredPermissions,
appOp, bOptions, ordered, sticky, callingPid, callingUid, realCallingUid,
realCallingPid, userId, false /* allowBackgroundActivityStarts */,
- null /*broadcastWhitelist*/);
+ null /* tokenNeededForBackgroundActivityStarts */, null /* broadcastWhitelist */);
}
@GuardedBy("this")
@@ -15970,6 +14476,7 @@ public class ActivityManagerService extends IActivityManager.Stub
Bundle resultExtras, String[] requiredPermissions, int appOp, Bundle bOptions,
boolean ordered, boolean sticky, int callingPid, int callingUid, int realCallingUid,
int realCallingPid, int userId, boolean allowBackgroundActivityStarts,
+ @Nullable IBinder backgroundActivityStartsToken,
@Nullable int[] broadcastWhitelist) {
intent = new Intent(intent);
@@ -16060,6 +14567,8 @@ public class ActivityManagerService extends IActivityManager.Stub
throw new SecurityException(msg);
} else {
allowBackgroundActivityStarts = true;
+ // We set the token to null since if it wasn't for it we'd allow anyway here
+ backgroundActivityStartsToken = null;
}
}
}
@@ -16528,7 +15037,8 @@ public class ActivityManagerService extends IActivityManager.Stub
callerFeatureId, callingPid, callingUid, callerInstantApp, resolvedType,
requiredPermissions, appOp, brOptions, registeredReceivers, resultTo,
resultCode, resultData, resultExtras, ordered, sticky, false, userId,
- allowBackgroundActivityStarts, timeoutExempt);
+ allowBackgroundActivityStarts, backgroundActivityStartsToken,
+ timeoutExempt);
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing parallel broadcast " + r);
final boolean replaced = replacePending
&& (queue.replaceParallelBroadcastLocked(r) != null);
@@ -16625,7 +15135,8 @@ public class ActivityManagerService extends IActivityManager.Stub
callerFeatureId, callingPid, callingUid, callerInstantApp, resolvedType,
requiredPermissions, appOp, brOptions, receivers, resultTo, resultCode,
resultData, resultExtras, ordered, sticky, false, userId,
- allowBackgroundActivityStarts, timeoutExempt);
+ allowBackgroundActivityStarts, backgroundActivityStartsToken,
+ timeoutExempt);
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing ordered broadcast " + r);
@@ -16785,7 +15296,8 @@ public class ActivityManagerService extends IActivityManager.Stub
int realCallingUid, int realCallingPid, Intent intent, String resolvedType,
IIntentReceiver resultTo, int resultCode, String resultData, Bundle resultExtras,
String requiredPermission, Bundle bOptions, boolean serialized, boolean sticky,
- int userId, boolean allowBackgroundActivityStarts) {
+ int userId, boolean allowBackgroundActivityStarts,
+ @Nullable IBinder backgroundActivityStartsToken) {
synchronized(this) {
intent = verifyBroadcastLocked(intent);
@@ -16797,6 +15309,7 @@ public class ActivityManagerService extends IActivityManager.Stub
resultTo, resultCode, resultData, resultExtras, requiredPermissions,
OP_NONE, bOptions, serialized, sticky, -1, uid, realCallingUid,
realCallingPid, userId, allowBackgroundActivityStarts,
+ backgroundActivityStartsToken,
null /*broadcastWhitelist*/);
} finally {
Binder.restoreCallingIdentity(origId);
@@ -17877,25 +16390,6 @@ public class ActivityManagerService extends IActivityManager.Stub
}
}
- private void maybeUpdateProviderUsageStatsLocked(ProcessRecord app, String providerPkgName,
- String authority) {
- if (app == null) return;
- if (app.getCurProcState() <= ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND) {
- UserState userState = mUserController.getStartedUserState(app.userId);
- if (userState == null) return;
- final long now = SystemClock.elapsedRealtime();
- Long lastReported = userState.mProviderLastReportedFg.get(authority);
- if (lastReported == null || lastReported < now - 60 * 1000L) {
- if (mSystemReady) {
- // Cannot touch the user stats if not system ready
- mUsageStatsService.reportContentProviderUsage(
- authority, providerPkgName, app.userId);
- }
- userState.mProviderLastReportedFg.put(authority, now);
- }
- }
- }
-
final void setProcessTrackerStateLocked(ProcessRecord proc, int memFactor, long now) {
if (proc.thread != null && proc.baseProcessTracker != null) {
final int procState = proc.getReportedProcState();
@@ -18980,13 +17474,13 @@ public class ActivityManagerService extends IActivityManager.Stub
public final class LocalService extends ActivityManagerInternal {
@Override
public String checkContentProviderAccess(String authority, int userId) {
- return ActivityManagerService.this.checkContentProviderAccess(authority, userId);
+ return mCpHelper.checkContentProviderAccess(authority, userId);
}
@Override
public int checkContentProviderUriPermission(Uri uri, int userId,
int callingUid, int modeFlags) {
- return ActivityManagerService.this.checkContentProviderUriPermission(uri,
+ return mCpHelper.checkContentProviderUriPermission(uri,
userId, callingUid, modeFlags);
}
@@ -19487,12 +17981,14 @@ public class ActivityManagerService extends IActivityManager.Stub
int realCallingUid, int realCallingPid, Intent intent, String resolvedType,
IIntentReceiver resultTo, int resultCode, String resultData, Bundle resultExtras,
String requiredPermission, Bundle bOptions, boolean serialized, boolean sticky,
- int userId, boolean allowBackgroundActivityStarts) {
+ int userId, boolean allowBackgroundActivityStarts,
+ @Nullable IBinder backgroundActivityStartsToken) {
synchronized (ActivityManagerService.this) {
return ActivityManagerService.this.broadcastIntentInPackage(packageName, featureId,
uid, realCallingUid, realCallingPid, intent, resolvedType, resultTo,
resultCode, resultData, resultExtras, requiredPermission, bOptions,
- serialized, sticky, userId, allowBackgroundActivityStarts);
+ serialized, sticky, userId, allowBackgroundActivityStarts,
+ backgroundActivityStartsToken);
}
}
@@ -19514,6 +18010,7 @@ public class ActivityManagerService extends IActivityManager.Stub
null /*resultExtras*/, requiredPermissions, AppOpsManager.OP_NONE,
null /*options*/, serialized, false /*sticky*/, callingPid, callingUid,
callingUid, callingPid, userId, false /*allowBackgroundStarts*/,
+ null /*tokenNeededForBackgroundActivityStarts*/,
appIdWhitelist);
} finally {
Binder.restoreCallingIdentity(origId);
@@ -19525,7 +18022,8 @@ public class ActivityManagerService extends IActivityManager.Stub
@Override
public ComponentName startServiceInPackage(int uid, Intent service, String resolvedType,
boolean fgRequired, String callingPackage, @Nullable String callingFeatureId,
- int userId, boolean allowBackgroundActivityStarts)
+ int userId, boolean allowBackgroundActivityStarts,
+ @Nullable IBinder backgroundActivityStartsToken)
throws TransactionTooLargeException {
synchronized(ActivityManagerService.this) {
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE,
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index 1fa62c6c40ba..12937b988beb 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -1677,7 +1677,7 @@ public final class BroadcastQueue {
// that request - we don't want the token to be swept from under our feet...
mHandler.removeCallbacksAndMessages(msgToken);
// ...then add the token
- proc.addAllowBackgroundActivityStartsToken(r);
+ proc.addAllowBackgroundActivityStartsToken(r, r.mBackgroundActivityStartsToken);
}
final void setBroadcastTimeoutLocked(long timeoutTime) {
diff --git a/services/core/java/com/android/server/am/BroadcastRecord.java b/services/core/java/com/android/server/am/BroadcastRecord.java
index 40743b8be1ea..198ba34e3956 100644
--- a/services/core/java/com/android/server/am/BroadcastRecord.java
+++ b/services/core/java/com/android/server/am/BroadcastRecord.java
@@ -92,6 +92,9 @@ final class BroadcastRecord extends Binder {
// if set to true, app's process will be temporarily allowed to start activities from background
// for the duration of the broadcast dispatch
final boolean allowBackgroundActivityStarts;
+ // token used to trace back the grant for activity starts, optional
+ @Nullable
+ final IBinder mBackgroundActivityStartsToken;
static final int IDLE = 0;
static final int APP_RECEIVE = 1;
@@ -240,7 +243,8 @@ final class BroadcastRecord extends Binder {
String[] _requiredPermissions, int _appOp, BroadcastOptions _options, List _receivers,
IIntentReceiver _resultTo, int _resultCode, String _resultData, Bundle _resultExtras,
boolean _serialized, boolean _sticky, boolean _initialSticky, int _userId,
- boolean _allowBackgroundActivityStarts, boolean _timeoutExempt) {
+ boolean allowBackgroundActivityStarts, @Nullable IBinder backgroundActivityStartsToken,
+ boolean timeoutExempt) {
if (_intent == null) {
throw new NullPointerException("Can't construct with a null intent");
}
@@ -270,8 +274,9 @@ final class BroadcastRecord extends Binder {
userId = _userId;
nextReceiver = 0;
state = IDLE;
- allowBackgroundActivityStarts = _allowBackgroundActivityStarts;
- timeoutExempt = _timeoutExempt;
+ this.allowBackgroundActivityStarts = allowBackgroundActivityStarts;
+ mBackgroundActivityStartsToken = backgroundActivityStartsToken;
+ this.timeoutExempt = timeoutExempt;
}
/**
@@ -317,6 +322,7 @@ final class BroadcastRecord extends Binder {
manifestSkipCount = from.manifestSkipCount;
queue = from.queue;
allowBackgroundActivityStarts = from.allowBackgroundActivityStarts;
+ mBackgroundActivityStartsToken = from.mBackgroundActivityStartsToken;
timeoutExempt = from.timeoutExempt;
}
@@ -352,7 +358,7 @@ final class BroadcastRecord extends Binder {
callerFeatureId, callingPid, callingUid, callerInstantApp, resolvedType,
requiredPermissions, appOp, options, splitReceivers, resultTo, resultCode,
resultData, resultExtras, ordered, sticky, initialSticky, userId,
- allowBackgroundActivityStarts, timeoutExempt);
+ allowBackgroundActivityStarts, mBackgroundActivityStartsToken, timeoutExempt);
split.splitToken = this.splitToken;
return split;
diff --git a/services/core/java/com/android/server/am/CachedAppOptimizer.java b/services/core/java/com/android/server/am/CachedAppOptimizer.java
index 43e3a04ad032..d9fde0f6728a 100644
--- a/services/core/java/com/android/server/am/CachedAppOptimizer.java
+++ b/services/core/java/com/android/server/am/CachedAppOptimizer.java
@@ -16,8 +16,6 @@
package com.android.server.am;
-import static android.os.Process.THREAD_PRIORITY_FOREGROUND;
-
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_COMPACTION;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_FREEZER;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
@@ -256,7 +254,7 @@ public final class CachedAppOptimizer {
ProcessDependencies processDependencies) {
mAm = am;
mCachedAppOptimizerThread = new ServiceThread("CachedAppOptimizerThread",
- THREAD_PRIORITY_FOREGROUND, true);
+ Process.THREAD_GROUP_SYSTEM, true);
mProcStateThrottle = new HashSet<>();
mProcessDependencies = processDependencies;
mTestCallback = callback;
@@ -280,8 +278,6 @@ public final class CachedAppOptimizer {
updateProcStateThrottle();
updateUseFreezer();
}
- Process.setThreadGroupAndCpuset(mCachedAppOptimizerThread.getThreadId(),
- Process.THREAD_GROUP_SYSTEM);
}
/**
@@ -411,12 +407,15 @@ public final class CachedAppOptimizer {
mUseCompaction = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
KEY_USE_COMPACTION, DEFAULT_USE_COMPACTION);
- if (mUseCompaction) {
+ if (mUseCompaction && mCompactionHandler == null) {
if (!mCachedAppOptimizerThread.isAlive()) {
mCachedAppOptimizerThread.start();
}
mCompactionHandler = new MemCompactionHandler();
+
+ Process.setThreadGroupAndCpuset(mCachedAppOptimizerThread.getThreadId(),
+ Process.THREAD_GROUP_SYSTEM);
}
}
@@ -470,13 +469,16 @@ public final class CachedAppOptimizer {
mUseFreezer = isFreezerSupported();
}
- if (mUseFreezer) {
+ if (mUseFreezer && mFreezeHandler == null) {
Slog.d(TAG_AM, "Freezer enabled");
if (!mCachedAppOptimizerThread.isAlive()) {
mCachedAppOptimizerThread.start();
}
mFreezeHandler = new FreezeHandler();
+
+ Process.setThreadGroupAndCpuset(mCachedAppOptimizerThread.getThreadId(),
+ Process.THREAD_GROUP_SYSTEM);
}
}
diff --git a/services/core/java/com/android/server/am/ContentProviderHelper.java b/services/core/java/com/android/server/am/ContentProviderHelper.java
new file mode 100644
index 000000000000..5cc7aba736e1
--- /dev/null
+++ b/services/core/java/com/android/server/am/ContentProviderHelper.java
@@ -0,0 +1,1679 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.am;
+
+import static android.os.Process.PROC_CHAR;
+import static android.os.Process.PROC_OUT_LONG;
+import static android.os.Process.PROC_PARENS;
+import static android.os.Process.PROC_SPACE_TERM;
+import static android.os.Process.SYSTEM_UID;
+
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_MU;
+import static com.android.server.am.ActivityManagerService.TAG_MU;
+
+import android.annotation.UserIdInt;
+import android.app.ActivityManager;
+import android.app.ActivityManagerInternal;
+import android.app.AppGlobals;
+import android.app.AppOpsManager;
+import android.app.ApplicationExitInfo;
+import android.app.ContentProviderHolder;
+import android.app.IApplicationThread;
+import android.content.ComponentName;
+import android.content.ContentProvider;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.IContentProvider;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PathPermission;
+import android.content.pm.ProviderInfo;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.os.Binder;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.Debug;
+import android.os.IBinder;
+import android.os.Process;
+import android.os.RemoteCallback;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.util.Log;
+import android.util.Slog;
+import android.util.SparseArray;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.ArrayUtils;
+import com.android.server.RescueParty;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Activity manager code dealing with content providers.
+ */
+public class ContentProviderHelper {
+ private static final String TAG = "ContentProviderHelper";
+
+ private final ActivityManagerService mService;
+
+ /**
+ * List of content providers who have clients waiting for them. The
+ * application is currently being launched and the provider will be
+ * removed from this list once it is published.
+ */
+ private final ArrayList<ContentProviderRecord> mLaunchingProviders = new ArrayList<>();
+ private final ProviderMap mProviderMap;
+ private boolean mSystemProvidersInstalled;
+
+ ContentProviderHelper(ActivityManagerService service, boolean createProviderMap) {
+ mService = service;
+ mProviderMap = createProviderMap ? new ProviderMap(mService) : null;
+ }
+
+ ProviderMap getProviderMap() {
+ return mProviderMap;
+ }
+
+ ContentProviderHolder getContentProvider(IApplicationThread caller, String callingPackage,
+ String name, int userId, boolean stable) {
+ mService.enforceNotIsolatedCaller("getContentProvider");
+ if (caller == null) {
+ String msg = "null IApplicationThread when getting content provider " + name;
+ Slog.w(TAG, msg);
+ throw new SecurityException(msg);
+ }
+ // The incoming user check is now handled in checkContentProviderPermissionLocked() to deal
+ // with cross-user grant.
+ final int callingUid = Binder.getCallingUid();
+ if (callingPackage != null && mService.mAppOpsService.checkPackage(
+ callingUid, callingPackage) != AppOpsManager.MODE_ALLOWED) {
+ throw new SecurityException("Given calling package " + callingPackage
+ + " does not match caller's uid " + callingUid);
+ }
+ return getContentProviderImpl(caller, name, null, callingUid, callingPackage,
+ null, stable, userId);
+ }
+
+ ContentProviderHolder getContentProviderExternal(
+ String name, int userId, IBinder token, String tag) {
+ mService.enforceCallingPermission(
+ android.Manifest.permission.ACCESS_CONTENT_PROVIDERS_EXTERNALLY,
+ "Do not have permission in call getContentProviderExternal()");
+ userId = mService.mUserController.handleIncomingUser(
+ Binder.getCallingPid(), Binder.getCallingUid(), userId,
+ false, ActivityManagerInternal.ALLOW_FULL_ONLY, "getContentProvider", null);
+ return getContentProviderExternalUnchecked(name, token, Binder.getCallingUid(),
+ tag != null ? tag : "*external*", userId);
+ }
+
+ ContentProviderHolder getContentProviderExternalUnchecked(String name,
+ IBinder token, int callingUid, String callingTag, int userId) {
+ return getContentProviderImpl(null, name, token, callingUid, null, callingTag,
+ true, userId);
+ }
+
+ private ContentProviderHolder getContentProviderImpl(IApplicationThread caller,
+ String name, IBinder token, int callingUid, String callingPackage, String callingTag,
+ boolean stable, int userId) {
+ ContentProviderRecord cpr;
+ ContentProviderConnection conn = null;
+ ProviderInfo cpi = null;
+ boolean providerRunning = false;
+ synchronized (mService) {
+ long startTime = SystemClock.uptimeMillis();
+
+ ProcessRecord r = null;
+ if (caller != null) {
+ r = mService.getRecordForAppLocked(caller);
+ if (r == null) {
+ throw new SecurityException("Unable to find app for caller " + caller
+ + " (pid=" + Binder.getCallingPid() + ") when getting content provider "
+ + name);
+ }
+ }
+
+ boolean checkCrossUser = true;
+
+ checkTime(startTime, "getContentProviderImpl: getProviderByName");
+
+ // First check if this content provider has been published...
+ cpr = mProviderMap.getProviderByName(name, userId);
+ // If that didn't work, check if it exists for user 0 and then
+ // verify that it's a singleton provider before using it.
+ if (cpr == null && userId != UserHandle.USER_SYSTEM) {
+ cpr = mProviderMap.getProviderByName(name, UserHandle.USER_SYSTEM);
+ if (cpr != null) {
+ cpi = cpr.info;
+ if (mService.isSingleton(
+ cpi.processName, cpi.applicationInfo, cpi.name, cpi.flags)
+ && mService.isValidSingletonCall(
+ r == null ? callingUid : r.uid, cpi.applicationInfo.uid)) {
+ userId = UserHandle.USER_SYSTEM;
+ checkCrossUser = false;
+ } else {
+ cpr = null;
+ cpi = null;
+ }
+ }
+ }
+
+ ProcessRecord dyingProc = null;
+ if (cpr != null && cpr.proc != null) {
+ providerRunning = !cpr.proc.killed;
+
+ // Note if killedByAm is also set, this means the provider process has just been
+ // killed by AM (in ProcessRecord.kill()), but appDiedLocked() hasn't been called
+ // yet. So we need to call appDiedLocked() here and let it clean up.
+ // (See the commit message on I2c4ba1e87c2d47f2013befff10c49b3dc337a9a7 to see
+ // how to test this case.)
+ if (cpr.proc.killed && cpr.proc.killedByAm) {
+ Slog.wtf(TAG, cpr.proc.toString() + " was killed by AM but isn't really dead");
+ // Now we are going to wait for the death before starting the new process.
+ dyingProc = cpr.proc;
+ }
+ }
+
+ if (providerRunning) {
+ cpi = cpr.info;
+ String msg;
+
+ if (r != null && cpr.canRunHere(r)) {
+ if ((msg = checkContentProviderAssociation(r, callingUid, cpi)) != null) {
+ throw new SecurityException("Content provider lookup "
+ + cpr.name.flattenToShortString()
+ + " failed: association not allowed with package " + msg);
+ }
+ checkTime(startTime,
+ "getContentProviderImpl: before checkContentProviderPermission");
+ if ((msg = checkContentProviderPermissionLocked(cpi, r, userId, checkCrossUser))
+ != null) {
+ throw new SecurityException(msg);
+ }
+ checkTime(startTime,
+ "getContentProviderImpl: after checkContentProviderPermission");
+
+ // This provider has been published or is in the process
+ // of being published... but it is also allowed to run
+ // in the caller's process, so don't make a connection
+ // and just let the caller instantiate its own instance.
+ ContentProviderHolder holder = cpr.newHolder(null);
+ // don't give caller the provider object, it needs to make its own.
+ holder.provider = null;
+ return holder;
+ }
+
+ // Don't expose providers between normal apps and instant apps
+ try {
+ if (AppGlobals.getPackageManager()
+ .resolveContentProvider(name, /*flags=*/ 0, userId) == null) {
+ return null;
+ }
+ } catch (RemoteException e) {
+ }
+
+ if ((msg = checkContentProviderAssociation(r, callingUid, cpi)) != null) {
+ throw new SecurityException(
+ "Content provider lookup " + cpr.name.flattenToShortString()
+ + " failed: association not allowed with package " + msg);
+ }
+ checkTime(startTime,
+ "getContentProviderImpl: before checkContentProviderPermission");
+ if ((msg = checkContentProviderPermissionLocked(cpi, r, userId, checkCrossUser))
+ != null) {
+ throw new SecurityException(msg);
+ }
+ checkTime(startTime,
+ "getContentProviderImpl: after checkContentProviderPermission");
+
+ final long origId = Binder.clearCallingIdentity();
+
+ checkTime(startTime, "getContentProviderImpl: incProviderCountLocked");
+
+ // In this case the provider instance already exists, so we can
+ // return it right away.
+ conn = incProviderCountLocked(r, cpr, token, callingUid, callingPackage, callingTag,
+ stable, true, startTime, mService.mProcessList);
+
+ checkTime(startTime, "getContentProviderImpl: before updateOomAdj");
+ final int verifiedAdj = cpr.proc.verifiedAdj;
+ boolean success = mService.updateOomAdjLocked(cpr.proc, true,
+ OomAdjuster.OOM_ADJ_REASON_GET_PROVIDER);
+ // XXX things have changed so updateOomAdjLocked doesn't actually tell us
+ // if the process has been successfully adjusted. So to reduce races with
+ // it, we will check whether the process still exists. Note that this doesn't
+ // completely get rid of races with LMK killing the process, but should make
+ // them much smaller.
+ if (success && verifiedAdj != cpr.proc.setAdj && !isProcessAliveLocked(cpr.proc)) {
+ success = false;
+ }
+ maybeUpdateProviderUsageStatsLocked(r, cpr.info.packageName, name);
+ checkTime(startTime, "getContentProviderImpl: after updateOomAdj");
+ if (ActivityManagerDebugConfig.DEBUG_PROVIDER) {
+ Slog.i(TAG, "Adjust success: " + success);
+ }
+ // NOTE: there is still a race here where a signal could be
+ // pending on the process even though we managed to update its
+ // adj level. Not sure what to do about this, but at least
+ // the race is now smaller.
+ if (!success) {
+ // Uh oh... it looks like the provider's process
+ // has been killed on us. We need to wait for a new
+ // process to be started, and make sure its death
+ // doesn't kill our process.
+ Slog.wtf(TAG, "Existing provider " + cpr.name.flattenToShortString()
+ + " is crashing; detaching " + r);
+ boolean lastRef = decProviderCountLocked(conn, cpr, token, stable);
+ if (!lastRef) {
+ // This wasn't the last ref our process had on
+ // the provider... we will be killed during cleaning up, bail.
+ return null;
+ }
+ // We'll just start a new process to host the content provider
+ providerRunning = false;
+ conn = null;
+ dyingProc = cpr.proc;
+ } else {
+ cpr.proc.verifiedAdj = cpr.proc.setAdj;
+ }
+
+ Binder.restoreCallingIdentity(origId);
+ }
+
+ if (!providerRunning) {
+ try {
+ checkTime(startTime, "getContentProviderImpl: before resolveContentProvider");
+ cpi = AppGlobals.getPackageManager().resolveContentProvider(name,
+ ActivityManagerService.STOCK_PM_FLAGS
+ | PackageManager.GET_URI_PERMISSION_PATTERNS,
+ userId);
+ checkTime(startTime, "getContentProviderImpl: after resolveContentProvider");
+ } catch (RemoteException ex) {
+ }
+ if (cpi == null) {
+ return null;
+ }
+ // If the provider is a singleton AND
+ // (it's a call within the same user || the provider is a privileged app)
+ // Then allow connecting to the singleton provider
+ boolean singleton = mService.isSingleton(
+ cpi.processName, cpi.applicationInfo, cpi.name, cpi.flags)
+ && mService.isValidSingletonCall(
+ r == null ? callingUid : r.uid, cpi.applicationInfo.uid);
+ if (singleton) {
+ userId = UserHandle.USER_SYSTEM;
+ }
+ cpi.applicationInfo = mService.getAppInfoForUser(cpi.applicationInfo, userId);
+ checkTime(startTime, "getContentProviderImpl: got app info for user");
+
+ String msg;
+ if ((msg = checkContentProviderAssociation(r, callingUid, cpi)) != null) {
+ throw new SecurityException("Content provider lookup " + name
+ + " failed: association not allowed with package " + msg);
+ }
+ checkTime(startTime,
+ "getContentProviderImpl: before checkContentProviderPermission");
+ if ((msg = checkContentProviderPermissionLocked(cpi, r, userId, !singleton))
+ != null) {
+ throw new SecurityException(msg);
+ }
+ checkTime(startTime,
+ "getContentProviderImpl: after checkContentProviderPermission");
+
+ if (!mService.mProcessesReady && !cpi.processName.equals("system")) {
+ // If this content provider does not run in the system
+ // process, and the system is not yet ready to run other
+ // processes, then fail fast instead of hanging.
+ throw new IllegalArgumentException(
+ "Attempt to launch content provider before system ready");
+ }
+
+ // If system providers are not installed yet we aggressively crash to avoid
+ // creating multiple instance of these providers and then bad things happen!
+ if (!mSystemProvidersInstalled && cpi.applicationInfo.isSystemApp()
+ && "system".equals(cpi.processName)) {
+ throw new IllegalStateException("Cannot access system provider: '"
+ + cpi.authority + "' before system providers are installed!");
+ }
+
+ // Make sure that the user who owns this provider is running. If not,
+ // we don't want to allow it to run.
+ if (!mService.mUserController.isUserRunning(userId, 0)) {
+ Slog.w(TAG, "Unable to launch app "
+ + cpi.applicationInfo.packageName + "/" + cpi.applicationInfo.uid
+ + " for provider " + name + ": user " + userId + " is stopped");
+ return null;
+ }
+
+ ComponentName comp = new ComponentName(cpi.packageName, cpi.name);
+ checkTime(startTime, "getContentProviderImpl: before getProviderByClass");
+ cpr = mProviderMap.getProviderByClass(comp, userId);
+ checkTime(startTime, "getContentProviderImpl: after getProviderByClass");
+ boolean firstClass = cpr == null;
+ if (firstClass) {
+ final long ident = Binder.clearCallingIdentity();
+
+ // If permissions need a review before any of the app components can run,
+ // we return no provider and launch a review activity if the calling app
+ // is in the foreground.
+ if (!requestTargetProviderPermissionsReviewIfNeededLocked(
+ cpi, r, userId, mService.mContext)) {
+ return null;
+ }
+
+ try {
+ checkTime(startTime, "getContentProviderImpl: before getApplicationInfo");
+ ApplicationInfo ai = AppGlobals.getPackageManager().getApplicationInfo(
+ cpi.applicationInfo.packageName,
+ ActivityManagerService.STOCK_PM_FLAGS, userId);
+ checkTime(startTime, "getContentProviderImpl: after getApplicationInfo");
+ if (ai == null) {
+ Slog.w(TAG, "No package info for content provider " + cpi.name);
+ return null;
+ }
+ ai = mService.getAppInfoForUser(ai, userId);
+ cpr = new ContentProviderRecord(mService, cpi, ai, comp, singleton);
+ } catch (RemoteException ex) {
+ // pm is in same process, this will never happen.
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ } else if (dyingProc == cpr.proc && dyingProc != null) {
+ // The old stable connection's client should be killed during proc cleaning up,
+ // so do not re-use the old ContentProviderRecord, otherwise the new clients
+ // could get killed unexpectedly.
+ cpr = new ContentProviderRecord(cpr);
+ // This is sort of "firstClass"
+ firstClass = true;
+ }
+
+ checkTime(startTime, "getContentProviderImpl: now have ContentProviderRecord");
+
+ if (r != null && cpr.canRunHere(r)) {
+ // If this is a multiprocess provider, then just return its
+ // info and allow the caller to instantiate it. Only do
+ // this if the provider is the same user as the caller's
+ // process, or can run as root (so can be in any process).
+ return cpr.newHolder(null);
+ }
+
+ if (ActivityManagerDebugConfig.DEBUG_PROVIDER) {
+ Slog.w(TAG, "LAUNCHING REMOTE PROVIDER (myuid " + (r != null ? r.uid : null)
+ + " pruid " + cpr.appInfo.uid + "): " + cpr.info.name
+ + " callers=" + Debug.getCallers(6));
+ }
+
+ // This is single process, and our app is now connecting to it.
+ // See if we are already in the process of launching this provider.
+ final int numLaunchingProviders = mLaunchingProviders.size();
+ int i;
+ for (i = 0; i < numLaunchingProviders; i++) {
+ if (mLaunchingProviders.get(i) == cpr) {
+ break;
+ }
+ }
+
+ // If the provider is not already being launched, then get it started.
+ if (i >= numLaunchingProviders) {
+ final long origId = Binder.clearCallingIdentity();
+
+ try {
+ // Content provider is now in use, its package can't be stopped.
+ try {
+ checkTime(startTime,
+ "getContentProviderImpl: before set stopped state");
+ AppGlobals.getPackageManager().setPackageStoppedState(
+ cpr.appInfo.packageName, false, userId);
+ checkTime(startTime, "getContentProviderImpl: after set stopped state");
+ } catch (RemoteException e) {
+ } catch (IllegalArgumentException e) {
+ Slog.w(TAG, "Failed trying to unstop package "
+ + cpr.appInfo.packageName + ": " + e);
+ }
+
+ // Use existing process if already started
+ checkTime(startTime, "getContentProviderImpl: looking for process record");
+ ProcessRecord proc = mService.getProcessRecordLocked(
+ cpi.processName, cpr.appInfo.uid, false);
+ if (proc != null && proc.thread != null && !proc.killed) {
+ if (ActivityManagerDebugConfig.DEBUG_PROVIDER) {
+ Slog.d(TAG, "Installing in existing process " + proc);
+ }
+ if (!proc.pubProviders.containsKey(cpi.name)) {
+ checkTime(startTime, "getContentProviderImpl: scheduling install");
+ proc.pubProviders.put(cpi.name, cpr);
+ try {
+ proc.thread.scheduleInstallProvider(cpi);
+ } catch (RemoteException e) {
+ }
+ }
+ } else {
+ checkTime(startTime, "getContentProviderImpl: before start process");
+ proc = mService.startProcessLocked(
+ cpi.processName, cpr.appInfo, false, 0,
+ new HostingRecord("content provider",
+ new ComponentName(
+ cpi.applicationInfo.packageName, cpi.name)),
+ Process.ZYGOTE_POLICY_FLAG_EMPTY, false, false, false);
+ checkTime(startTime, "getContentProviderImpl: after start process");
+ if (proc == null) {
+ Slog.w(TAG, "Unable to launch app "
+ + cpi.applicationInfo.packageName + "/"
+ + cpi.applicationInfo.uid + " for provider " + name
+ + ": process is bad");
+ return null;
+ }
+ }
+ cpr.launchingApp = proc;
+ mLaunchingProviders.add(cpr);
+ } finally {
+ Binder.restoreCallingIdentity(origId);
+ }
+ }
+
+ checkTime(startTime, "getContentProviderImpl: updating data structures");
+
+ // Make sure the provider is published (the same provider class
+ // may be published under multiple names).
+ if (firstClass) {
+ mProviderMap.putProviderByClass(comp, cpr);
+ }
+
+ mProviderMap.putProviderByName(name, cpr);
+ conn = incProviderCountLocked(r, cpr, token, callingUid, callingPackage, callingTag,
+ stable, false, startTime, mService.mProcessList);
+ if (conn != null) {
+ conn.waiting = true;
+ }
+ }
+ checkTime(startTime, "getContentProviderImpl: done!");
+
+ mService.grantImplicitAccess(userId, null, callingUid,
+ UserHandle.getAppId(cpi.applicationInfo.uid));
+ }
+
+ // Wait for the provider to be published...
+ final long timeout =
+ SystemClock.uptimeMillis() + ContentResolver.CONTENT_PROVIDER_READY_TIMEOUT_MILLIS;
+ boolean timedOut = false;
+ synchronized (cpr) {
+ while (cpr.provider == null) {
+ if (cpr.launchingApp == null) {
+ Slog.w(TAG, "Unable to launch app "
+ + cpi.applicationInfo.packageName + "/" + cpi.applicationInfo.uid
+ + " for provider " + name + ": launching app became null");
+ EventLogTags.writeAmProviderLostProcess(
+ UserHandle.getUserId(cpi.applicationInfo.uid),
+ cpi.applicationInfo.packageName, cpi.applicationInfo.uid, name);
+ return null;
+ }
+ try {
+ final long wait = Math.max(0L, timeout - SystemClock.uptimeMillis());
+ if (DEBUG_MU) {
+ Slog.v(TAG_MU, "Waiting to start provider " + cpr
+ + " launchingApp=" + cpr.launchingApp + " for " + wait + " ms");
+ }
+ if (conn != null) {
+ conn.waiting = true;
+ }
+ cpr.wait(wait);
+ if (cpr.provider == null) {
+ timedOut = true;
+ break;
+ }
+ } catch (InterruptedException ex) {
+ } finally {
+ if (conn != null) {
+ conn.waiting = false;
+ }
+ }
+ }
+ }
+ if (timedOut) {
+ // Note we do it after releasing the lock.
+ String callerName = "unknown";
+ if (caller != null) {
+ synchronized (mService) {
+ final ProcessRecord record =
+ mService.mProcessList.getLRURecordForAppLocked(caller);
+ if (record != null) {
+ callerName = record.processName;
+ }
+ }
+ }
+
+ Slog.wtf(TAG, "Timeout waiting for provider "
+ + cpi.applicationInfo.packageName + "/" + cpi.applicationInfo.uid
+ + " for provider " + name + " providerRunning=" + providerRunning
+ + " caller=" + callerName + "/" + Binder.getCallingUid());
+ return null;
+ }
+ return cpr.newHolder(conn);
+ }
+
+ void publishContentProviders(IApplicationThread caller, List<ContentProviderHolder> providers) {
+ if (providers == null) {
+ return;
+ }
+
+ mService.enforceNotIsolatedCaller("publishContentProviders");
+ synchronized (mService) {
+ final ProcessRecord r = mService.getRecordForAppLocked(caller);
+ if (DEBUG_MU) {
+ Slog.v(TAG_MU, "ProcessRecord uid = " + r.uid);
+ }
+ if (r == null) {
+ throw new SecurityException("Unable to find app for caller " + caller
+ + " (pid=" + Binder.getCallingPid()
+ + ") when publishing content providers");
+ }
+
+ final long origId = Binder.clearCallingIdentity();
+
+ for (int i = 0, size = providers.size(); i < size; i++) {
+ ContentProviderHolder src = providers.get(i);
+ if (src == null || src.info == null || src.provider == null) {
+ continue;
+ }
+ ContentProviderRecord dst = r.pubProviders.get(src.info.name);
+ if (dst == null) {
+ continue;
+ }
+ if (DEBUG_MU) {
+ Slog.v(TAG_MU, "ContentProviderRecord uid = " + dst.uid);
+ }
+
+ ComponentName comp = new ComponentName(dst.info.packageName, dst.info.name);
+ mProviderMap.putProviderByClass(comp, dst);
+ String[] names = dst.info.authority.split(";");
+ for (int j = 0; j < names.length; j++) {
+ mProviderMap.putProviderByName(names[j], dst);
+ }
+
+ boolean wasInLaunchingProviders = false;
+ for (int j = 0, numLaunching = mLaunchingProviders.size(); j < numLaunching; j++) {
+ if (mLaunchingProviders.get(j) == dst) {
+ mLaunchingProviders.remove(j);
+ wasInLaunchingProviders = true;
+ j--;
+ numLaunching--;
+ }
+ }
+ if (wasInLaunchingProviders) {
+ mService.mHandler.removeMessages(
+ ActivityManagerService.CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG, r);
+ }
+ // Make sure the package is associated with the process.
+ // XXX We shouldn't need to do this, since we have added the package
+ // when we generated the providers in generateApplicationProvidersLocked().
+ // But for some reason in some cases we get here with the package no longer
+ // added... for now just patch it in to make things happy.
+ r.addPackage(dst.info.applicationInfo.packageName,
+ dst.info.applicationInfo.longVersionCode, mService.mProcessStats);
+ synchronized (dst) {
+ dst.provider = src.provider;
+ dst.setProcess(r);
+ dst.notifyAll();
+ }
+ dst.mRestartCount = 0;
+ mService.updateOomAdjLocked(r, true, OomAdjuster.OOM_ADJ_REASON_GET_PROVIDER);
+ maybeUpdateProviderUsageStatsLocked(r, src.info.packageName, src.info.authority);
+ }
+
+ Binder.restoreCallingIdentity(origId);
+ }
+ }
+
+ /**
+ * Drop a content provider from a ProcessRecord's bookkeeping
+ */
+ void removeContentProvider(IBinder connection, boolean stable) {
+ mService.enforceNotIsolatedCaller("removeContentProvider");
+ long ident = Binder.clearCallingIdentity();
+ try {
+ synchronized (mService) {
+ ContentProviderConnection conn;
+ try {
+ conn = (ContentProviderConnection) connection;
+ } catch (ClassCastException e) {
+ String msg = "removeContentProvider: " + connection
+ + " not a ContentProviderConnection";
+ Slog.w(TAG, msg);
+ throw new IllegalArgumentException(msg);
+ }
+ if (conn == null) {
+ throw new NullPointerException("connection is null");
+ }
+ if (decProviderCountLocked(conn, null, null, stable)) {
+ mService.updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_REMOVE_PROVIDER);
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ void removeContentProviderExternalAsUser(String name, IBinder token, int userId) {
+ mService.enforceCallingPermission(
+ android.Manifest.permission.ACCESS_CONTENT_PROVIDERS_EXTERNALLY,
+ "Do not have permission in call removeContentProviderExternal()");
+ long ident = Binder.clearCallingIdentity();
+ try {
+ removeContentProviderExternalUnchecked(name, token, userId);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ void removeContentProviderExternalUnchecked(String name, IBinder token, int userId) {
+ synchronized (mService) {
+ ContentProviderRecord cpr = mProviderMap.getProviderByName(name, userId);
+ if (cpr == null) {
+ //remove from mProvidersByClass
+ if (ActivityManagerDebugConfig.DEBUG_ALL) {
+ Slog.v(TAG, name + " content provider not found in providers list");
+ }
+ return;
+ }
+
+ // update content provider record entry info
+ ComponentName comp = new ComponentName(cpr.info.packageName, cpr.info.name);
+ ContentProviderRecord localCpr = mProviderMap.getProviderByClass(comp, userId);
+ if (localCpr.hasExternalProcessHandles()) {
+ if (localCpr.removeExternalProcessHandleLocked(token)) {
+ mService.updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_REMOVE_PROVIDER);
+ } else {
+ Slog.e(TAG, "Attempt to remove content provider " + localCpr
+ + " with no external reference for token: " + token + ".");
+ }
+ } else {
+ Slog.e(TAG, "Attempt to remove content provider: " + localCpr
+ + " with no external references.");
+ }
+ }
+ }
+
+ boolean refContentProvider(IBinder connection, int stable, int unstable) {
+ ContentProviderConnection conn;
+ try {
+ conn = (ContentProviderConnection) connection;
+ } catch (ClassCastException e) {
+ String msg = "refContentProvider: " + connection + " not a ContentProviderConnection";
+ Slog.w(TAG, msg);
+ throw new IllegalArgumentException(msg);
+ }
+ if (conn == null) {
+ throw new NullPointerException("connection is null");
+ }
+
+ conn.adjustCounts(stable, unstable);
+ return !conn.dead;
+ }
+
+ void unstableProviderDied(IBinder connection) {
+ ContentProviderConnection conn;
+ try {
+ conn = (ContentProviderConnection) connection;
+ } catch (ClassCastException e) {
+ String msg = "refContentProvider: " + connection + " not a ContentProviderConnection";
+ Slog.w(TAG, msg);
+ throw new IllegalArgumentException(msg);
+ }
+ if (conn == null) {
+ throw new NullPointerException("connection is null");
+ }
+
+ // Safely retrieve the content provider associated with the connection.
+ IContentProvider provider;
+ synchronized (mService) {
+ provider = conn.provider.provider;
+ }
+
+ if (provider == null) {
+ // Um, yeah, we're way ahead of you.
+ return;
+ }
+
+ // Make sure the caller is being honest with us.
+ if (provider.asBinder().pingBinder()) {
+ // Er, no, still looks good to us.
+ synchronized (mService) {
+ Slog.w(TAG, "unstableProviderDied: caller " + Binder.getCallingUid()
+ + " says " + conn + " died, but we don't agree");
+ return;
+ }
+ }
+
+ // Well look at that! It's dead!
+ synchronized (mService) {
+ if (conn.provider.provider != provider) {
+ // But something changed... good enough.
+ return;
+ }
+
+ ProcessRecord proc = conn.provider.proc;
+ if (proc == null || proc.thread == null) {
+ // Seems like the process is already cleaned up.
+ return;
+ }
+
+ // As far as we're concerned, this is just like receiving a
+ // death notification... just a bit prematurely.
+ mService.reportUidInfoMessageLocked(TAG, "Process " + proc.processName
+ + " (pid " + proc.pid + ") early provider death", proc.info.uid);
+ final long token = Binder.clearCallingIdentity();
+ try {
+ mService.appDiedLocked(proc, "unstable content provider");
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+ }
+
+ void appNotRespondingViaProvider(IBinder connection) {
+ mService.enforceCallingPermission(android.Manifest.permission.REMOVE_TASKS,
+ "appNotRespondingViaProvider()");
+
+ final ContentProviderConnection conn = (ContentProviderConnection) connection;
+ if (conn == null) {
+ Slog.w(TAG, "ContentProviderConnection is null");
+ return;
+ }
+
+ final ProcessRecord host = conn.provider.proc;
+ if (host == null) {
+ Slog.w(TAG, "Failed to find hosting ProcessRecord");
+ return;
+ }
+
+ mService.mAnrHelper.appNotResponding(host, "ContentProvider not responding");
+ }
+
+ /**
+ * Allows apps to retrieve the MIME type of a URI.
+ * If an app is in the same user as the ContentProvider, or if it is allowed to interact across
+ * users, then it does not need permission to access the ContentProvider.
+ * Either, it needs cross-user uri grants.
+ *
+ * CTS tests for this functionality can be run with "runtest cts-appsecurity".
+ *
+ * Test cases are at cts/tests/appsecurity-tests/test-apps/UsePermissionDiffCert/
+ * src/com/android/cts/usespermissiondiffcertapp/AccessPermissionWithDiffSigTest.java
+ *
+ * @deprecated -- use getProviderMimeTypeAsync.
+ */
+ @Deprecated
+ String getProviderMimeType(Uri uri, int userId) {
+ mService.enforceNotIsolatedCaller("getProviderMimeType");
+ final String name = uri.getAuthority();
+ int callingUid = Binder.getCallingUid();
+ int callingPid = Binder.getCallingPid();
+ long ident = 0;
+ boolean clearedIdentity = false;
+ userId = mService.mUserController.unsafeConvertIncomingUser(userId);
+ if (canClearIdentity(callingPid, callingUid, userId)) {
+ clearedIdentity = true;
+ ident = Binder.clearCallingIdentity();
+ }
+ ContentProviderHolder holder = null;
+ try {
+ holder = getContentProviderExternalUnchecked(name, null, callingUid,
+ "*getmimetype*", userId);
+ if (holder != null) {
+ final IBinder providerConnection = holder.connection;
+ final ComponentName providerName = holder.info.getComponentName();
+ // Note: creating a new Runnable instead of using a lambda here since lambdas in
+ // java provide no guarantee that there will be a new instance returned every call.
+ // Hence, it's possible that a cached copy is returned and the ANR is executed on
+ // the incorrect provider.
+ final Runnable providerNotResponding = new Runnable() {
+ @Override
+ public void run() {
+ Log.w(TAG, "Provider " + providerName + " didn't return from getType().");
+ appNotRespondingViaProvider(providerConnection);
+ }
+ };
+ mService.mHandler.postDelayed(providerNotResponding, 1000);
+ try {
+ return holder.provider.getType(uri);
+ } finally {
+ mService.mHandler.removeCallbacks(providerNotResponding);
+ }
+ }
+ } catch (RemoteException e) {
+ Log.w(TAG, "Content provider dead retrieving " + uri, e);
+ return null;
+ } catch (Exception e) {
+ Log.w(TAG, "Exception while determining type of " + uri, e);
+ return null;
+ } finally {
+ // We need to clear the identity to call removeContentProviderExternalUnchecked
+ if (!clearedIdentity) {
+ ident = Binder.clearCallingIdentity();
+ }
+ try {
+ if (holder != null) {
+ removeContentProviderExternalUnchecked(name, null, userId);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Allows apps to retrieve the MIME type of a URI.
+ * If an app is in the same user as the ContentProvider, or if it is allowed to interact across
+ * users, then it does not need permission to access the ContentProvider.
+ * Either way, it needs cross-user uri grants.
+ */
+ void getProviderMimeTypeAsync(Uri uri, int userId, RemoteCallback resultCallback) {
+ mService.enforceNotIsolatedCaller("getProviderMimeTypeAsync");
+ final String name = uri.getAuthority();
+ final int callingUid = Binder.getCallingUid();
+ final int callingPid = Binder.getCallingPid();
+ final int safeUserId = mService.mUserController.unsafeConvertIncomingUser(userId);
+ final long ident = canClearIdentity(callingPid, callingUid, userId)
+ ? Binder.clearCallingIdentity() : 0;
+ try {
+ final ContentProviderHolder holder = getContentProviderExternalUnchecked(name, null,
+ callingUid, "*getmimetype*", safeUserId);
+ if (holder != null) {
+ holder.provider.getTypeAsync(uri, new RemoteCallback(result -> {
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ removeContentProviderExternalUnchecked(name, null, safeUserId);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ resultCallback.sendResult(result);
+ }));
+ } else {
+ resultCallback.sendResult(Bundle.EMPTY);
+ }
+ } catch (RemoteException e) {
+ Log.w(TAG, "Content provider dead retrieving " + uri, e);
+ resultCallback.sendResult(Bundle.EMPTY);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ private boolean canClearIdentity(int callingPid, int callingUid, int userId) {
+ if (UserHandle.getUserId(callingUid) == userId) {
+ return true;
+ }
+ return ActivityManagerService.checkComponentPermission(
+ android.Manifest.permission.INTERACT_ACROSS_USERS, callingPid,
+ callingUid, -1, true) == PackageManager.PERMISSION_GRANTED
+ || ActivityManagerService.checkComponentPermission(
+ android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, callingPid,
+ callingUid, -1, true) == PackageManager.PERMISSION_GRANTED;
+ }
+
+ /**
+ * Check if the calling UID has a possible chance at accessing the provider
+ * at the given authority and user.
+ */
+ String checkContentProviderAccess(String authority, int userId) {
+ if (userId == UserHandle.USER_ALL) {
+ mService.mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, TAG);
+ userId = UserHandle.getCallingUserId();
+ }
+
+ ProviderInfo cpi = null;
+ try {
+ cpi = AppGlobals.getPackageManager().resolveContentProvider(authority,
+ ActivityManagerService.STOCK_PM_FLAGS
+ | PackageManager.GET_URI_PERMISSION_PATTERNS
+ | PackageManager.MATCH_DISABLED_COMPONENTS
+ | PackageManager.MATCH_DIRECT_BOOT_AWARE
+ | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
+ userId);
+ } catch (RemoteException ignored) {
+ }
+ if (cpi == null) {
+ return "Failed to find provider " + authority + " for user " + userId
+ + "; expected to find a valid ContentProvider for this authority";
+ }
+
+ ProcessRecord r;
+ synchronized (mService.mPidsSelfLocked) {
+ r = mService.mPidsSelfLocked.get(Binder.getCallingPid());
+ }
+ if (r == null) {
+ return "Failed to find PID " + Binder.getCallingPid();
+ }
+
+ synchronized (mService) {
+ return checkContentProviderPermissionLocked(cpi, r, userId, true);
+ }
+ }
+
+ int checkContentProviderUriPermission(Uri uri, int userId, int callingUid, int modeFlags) {
+ if (Thread.holdsLock(mService.mActivityTaskManager.getGlobalLock())) {
+ Slog.wtf(TAG, new IllegalStateException("Unable to check Uri permission"
+ + " because caller is holding WM lock; assuming permission denied"));
+ return PackageManager.PERMISSION_DENIED;
+ }
+
+ final String name = uri.getAuthority();
+ final long ident = Binder.clearCallingIdentity();
+ ContentProviderHolder holder = null;
+ try {
+ holder = getContentProviderExternalUnchecked(name, null, callingUid,
+ "*checkContentProviderUriPermission*", userId);
+ if (holder != null) {
+ return holder.provider.checkUriPermission(null, null, uri, callingUid, modeFlags);
+ }
+ } catch (RemoteException e) {
+ Log.w(TAG, "Content provider dead retrieving " + uri, e);
+ return PackageManager.PERMISSION_DENIED;
+ } catch (Exception e) {
+ Log.w(TAG, "Exception while determining type of " + uri, e);
+ return PackageManager.PERMISSION_DENIED;
+ } finally {
+ try {
+ if (holder != null) {
+ removeContentProviderExternalUnchecked(name, null, userId);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+ return PackageManager.PERMISSION_DENIED;
+ }
+
+ @GuardedBy("mService")
+ void processContentProviderPublishTimedOutLocked(ProcessRecord app) {
+ cleanupAppInLaunchingProvidersLocked(app, true);
+ mService.mProcessList.removeProcessLocked(app, false, true,
+ ApplicationExitInfo.REASON_INITIALIZATION_FAILURE,
+ ApplicationExitInfo.SUBREASON_UNKNOWN,
+ "timeout publishing content providers");
+ }
+
+ List<ProviderInfo> generateApplicationProvidersLocked(ProcessRecord app) {
+ final List<ProviderInfo> providers;
+ try {
+ providers = AppGlobals.getPackageManager().queryContentProviders(
+ app.processName, app.uid, ActivityManagerService.STOCK_PM_FLAGS
+ | PackageManager.GET_URI_PERMISSION_PATTERNS
+ | PackageManager.MATCH_DIRECT_BOOT_AUTO, /*metaDataKey=*/ null)
+ .getList();
+ } catch (RemoteException ex) {
+ return null;
+ }
+ if (providers == null) {
+ return null;
+ }
+
+ if (DEBUG_MU) {
+ Slog.v(TAG_MU, "generateApplicationProvidersLocked, app.info.uid = " + app.uid);
+ }
+
+ int numProviders = providers.size();
+ app.pubProviders.ensureCapacity(numProviders + app.pubProviders.size());
+ for (int i = 0; i < numProviders; i++) {
+ // NOTE: keep logic in sync with installEncryptionUnawareProviders
+ ProviderInfo cpi = providers.get(i);
+ boolean singleton = mService.isSingleton(cpi.processName, cpi.applicationInfo,
+ cpi.name, cpi.flags);
+ if (singleton && app.userId != UserHandle.USER_SYSTEM) {
+ // This is a singleton provider, but a user besides the
+ // default user is asking to initialize a process it runs
+ // in... well, no, it doesn't actually run in this process,
+ // it runs in the process of the default user. Get rid of it.
+ providers.remove(i);
+ numProviders--;
+ i--;
+ continue;
+ }
+
+ ComponentName comp = new ComponentName(cpi.packageName, cpi.name);
+ ContentProviderRecord cpr = mProviderMap.getProviderByClass(comp, app.userId);
+ if (cpr == null) {
+ cpr = new ContentProviderRecord(mService, cpi, app.info, comp, singleton);
+ mProviderMap.putProviderByClass(comp, cpr);
+ }
+ if (DEBUG_MU) {
+ Slog.v(TAG_MU, "generateApplicationProvidersLocked, cpi.uid = " + cpr.uid);
+ }
+ app.pubProviders.put(cpi.name, cpr);
+ if (!cpi.multiprocess || !"android".equals(cpi.packageName)) {
+ // Don't add this if it is a platform component that is marked
+ // to run in multiple processes, because this is actually
+ // part of the framework so doesn't make sense to track as a
+ // separate apk in the process.
+ app.addPackage(cpi.applicationInfo.packageName, cpi.applicationInfo.longVersionCode,
+ mService.mProcessStats);
+ }
+ mService.notifyPackageUse(cpi.applicationInfo.packageName,
+ PackageManager.NOTIFY_PACKAGE_USE_CONTENT_PROVIDER);
+ }
+ return providers;
+ }
+
+ private final class DevelopmentSettingsObserver extends ContentObserver {
+ private final Uri mUri = Settings.Global.getUriFor(
+ Settings.Global.DEVELOPMENT_SETTINGS_ENABLED);
+
+ private final ComponentName mBugreportStorageProvider = new ComponentName(
+ "com.android.shell", "com.android.shell.BugreportStorageProvider");
+
+ DevelopmentSettingsObserver() {
+ super(mService.mHandler);
+ mService.mContext.getContentResolver().registerContentObserver(mUri, false, this,
+ UserHandle.USER_ALL);
+ // Always kick once to ensure that we match current state
+ onChange();
+ }
+
+ @Override
+ public void onChange(boolean selfChange, Uri uri, @UserIdInt int userId) {
+ if (mUri.equals(uri)) {
+ onChange();
+ }
+ }
+
+ private void onChange() {
+ final boolean enabled = Settings.Global.getInt(mService.mContext.getContentResolver(),
+ Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, Build.IS_ENG ? 1 : 0) != 0;
+ mService.mContext.getPackageManager().setComponentEnabledSetting(
+ mBugreportStorageProvider,
+ enabled ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED
+ : PackageManager.COMPONENT_ENABLED_STATE_DEFAULT,
+ 0);
+ }
+ }
+
+ public final void installSystemProviders() {
+ List<ProviderInfo> providers;
+ synchronized (mService) {
+ ProcessRecord app = mService.mProcessList.mProcessNames.get("system", SYSTEM_UID);
+ providers = generateApplicationProvidersLocked(app);
+ if (providers != null) {
+ for (int i = providers.size() - 1; i >= 0; i--) {
+ ProviderInfo pi = providers.get(i);
+ if ((pi.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
+ Slog.w(TAG, "Not installing system proc provider " + pi.name
+ + ": not system .apk");
+ providers.remove(i);
+ }
+ }
+ }
+ }
+ if (providers != null) {
+ mService.mSystemThread.installSystemProviders(providers);
+ }
+
+ synchronized (mService) {
+ mSystemProvidersInstalled = true;
+ }
+ mService.mConstants.start(mService.mContext.getContentResolver());
+ mService.mCoreSettingsObserver = new CoreSettingsObserver(mService);
+ mService.mActivityTaskManager.installSystemProviders();
+ new DevelopmentSettingsObserver(); // init to observe developer settings enable/disable
+ SettingsToPropertiesMapper.start(mService.mContext.getContentResolver());
+ mService.mOomAdjuster.initSettings();
+
+ // Now that the settings provider is published we can consider sending in a rescue party.
+ RescueParty.onSettingsProviderPublished(mService.mContext);
+ }
+
+ /**
+ * When a user is unlocked, we need to install encryption-unaware providers
+ * belonging to any running apps.
+ */
+ void installEncryptionUnawareProviders(int userId) {
+ // We're only interested in providers that are encryption unaware, and
+ // we don't care about uninstalled apps, since there's no way they're
+ // running at this point.
+ final int matchFlags =
+ PackageManager.GET_PROVIDERS | PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
+
+ synchronized (mService) {
+ final int numProc = mService.mProcessList.mProcessNames.getMap().size();
+ for (int iProc = 0; iProc < numProc; iProc++) {
+ final SparseArray<ProcessRecord> apps =
+ mService.mProcessList.mProcessNames.getMap().valueAt(iProc);
+ for (int iApp = 0, numApps = apps.size(); iApp < numApps; iApp++) {
+ final ProcessRecord app = apps.valueAt(iApp);
+ if (app.userId != userId || app.thread == null || app.unlocked) continue;
+
+ for (int iPkg = 0, numPkgs = app.pkgList.size(); iPkg < numPkgs; iPkg++) {
+ try {
+ final String pkgName = app.pkgList.keyAt(iPkg);
+ final PackageInfo pkgInfo = AppGlobals.getPackageManager()
+ .getPackageInfo(pkgName, matchFlags, userId);
+ if (pkgInfo != null && !ArrayUtils.isEmpty(pkgInfo.providers)) {
+ for (ProviderInfo pi : pkgInfo.providers) {
+ // NOTE: keep in sync with generateApplicationProvidersLocked
+ final boolean processMatch =
+ Objects.equals(pi.processName, app.processName)
+ || pi.multiprocess;
+ final boolean userMatch = !mService.isSingleton(
+ pi.processName, pi.applicationInfo, pi.name, pi.flags)
+ || app.userId == UserHandle.USER_SYSTEM;
+ if (processMatch && userMatch) {
+ Log.v(TAG, "Installing " + pi);
+ app.thread.scheduleInstallProvider(pi);
+ } else {
+ Log.v(TAG, "Skipping " + pi);
+ }
+ }
+ }
+ } catch (RemoteException ignored) {
+ }
+ }
+ }
+ }
+ }
+ }
+
+ @GuardedBy("mService")
+ private ContentProviderConnection incProviderCountLocked(ProcessRecord r,
+ final ContentProviderRecord cpr, IBinder externalProcessToken, int callingUid,
+ String callingPackage, String callingTag, boolean stable, boolean updateLru,
+ long startTime, ProcessList processList) {
+ if (r == null) {
+ cpr.addExternalProcessHandleLocked(externalProcessToken, callingUid, callingTag);
+ return null;
+ }
+
+
+ for (int i = 0, size = r.conProviders.size(); i < size; i++) {
+ ContentProviderConnection conn = r.conProviders.get(i);
+ if (conn.provider == cpr) {
+ conn.incrementCount(stable);
+ return conn;
+ }
+ }
+
+ // Create a new ContentProviderConnection. The reference count is known to be 1.
+ ContentProviderConnection conn = new ContentProviderConnection(cpr, r, callingPackage);
+ conn.startAssociationIfNeeded();
+ conn.initializeCount(stable);
+ cpr.connections.add(conn);
+ r.conProviders.add(conn);
+ mService.startAssociationLocked(r.uid, r.processName, r.getCurProcState(),
+ cpr.uid, cpr.appInfo.longVersionCode, cpr.name, cpr.info.processName);
+ if (updateLru && cpr.proc != null && r.setAdj <= ProcessList.PERCEPTIBLE_LOW_APP_ADJ) {
+ // If this is a perceptible app accessing the provider, make
+ // sure to count it as being accessed and thus back up on
+ // the LRU list. This is good because content providers are
+ // often expensive to start. The calls to checkTime() use
+ // the "getContentProviderImpl" tag here, because it's part
+ // of the checktime log in getContentProviderImpl().
+ checkTime(startTime, "getContentProviderImpl: before updateLruProcess");
+ processList.updateLruProcessLocked(cpr.proc, false, null);
+ checkTime(startTime, "getContentProviderImpl: after updateLruProcess");
+ }
+ return conn;
+ }
+
+ @GuardedBy("mService")
+ private boolean decProviderCountLocked(ContentProviderConnection conn,
+ ContentProviderRecord cpr, IBinder externalProcessToken, boolean stable) {
+ if (conn == null) {
+ cpr.removeExternalProcessHandleLocked(externalProcessToken);
+ return false;
+ }
+ if (conn.decrementCount(stable) != 0) {
+ return false;
+ }
+
+ cpr = conn.provider;
+ conn.stopAssociation();
+ cpr.connections.remove(conn);
+ conn.client.conProviders.remove(conn);
+ if (conn.client.setProcState < ActivityManager.PROCESS_STATE_LAST_ACTIVITY) {
+ // The client is more important than last activity -- note the time this
+ // is happening, so we keep the old provider process around a bit as last
+ // activity to avoid thrashing it.
+ if (cpr.proc != null) {
+ cpr.proc.lastProviderTime = SystemClock.uptimeMillis();
+ }
+ }
+ mService.stopAssociationLocked(conn.client.uid, conn.client.processName, cpr.uid,
+ cpr.appInfo.longVersionCode, cpr.name, cpr.info.processName);
+ return true;
+ }
+
+ /**
+ * Check if {@link ProcessRecord} has a possible chance at accessing the
+ * given {@link ProviderInfo}. Final permission checking is always done
+ * in {@link ContentProvider}.
+ */
+ private String checkContentProviderPermissionLocked(ProviderInfo cpi, ProcessRecord r,
+ int userId, boolean checkUser) {
+ final int callingPid = (r != null) ? r.pid : Binder.getCallingPid();
+ final int callingUid = (r != null) ? r.uid : Binder.getCallingUid();
+ boolean checkedGrants = false;
+ if (checkUser) {
+ // Looking for cross-user grants before enforcing the typical cross-users permissions
+ int tmpTargetUserId = mService.mUserController.unsafeConvertIncomingUser(userId);
+ if (tmpTargetUserId != UserHandle.getUserId(callingUid)) {
+ if (mService.mUgmInternal.checkAuthorityGrants(
+ callingUid, cpi, tmpTargetUserId, checkUser)) {
+ return null;
+ }
+ checkedGrants = true;
+ }
+ userId = mService.mUserController.handleIncomingUser(callingPid, callingUid, userId,
+ false, ActivityManagerInternal.ALLOW_NON_FULL,
+ "checkContentProviderPermissionLocked " + cpi.authority, null);
+ if (userId != tmpTargetUserId) {
+ // When we actually went to determine the final target user ID, this ended
+ // up different than our initial check for the authority. This is because
+ // they had asked for USER_CURRENT_OR_SELF and we ended up switching to
+ // SELF. So we need to re-check the grants again.
+ checkedGrants = false;
+ }
+ }
+ if (ActivityManagerService.checkComponentPermission(cpi.readPermission,
+ callingPid, callingUid, cpi.applicationInfo.uid, cpi.exported)
+ == PackageManager.PERMISSION_GRANTED) {
+ return null;
+ }
+ if (ActivityManagerService.checkComponentPermission(cpi.writePermission,
+ callingPid, callingUid, cpi.applicationInfo.uid, cpi.exported)
+ == PackageManager.PERMISSION_GRANTED) {
+ return null;
+ }
+
+ PathPermission[] pps = cpi.pathPermissions;
+ if (pps != null) {
+ int i = pps.length;
+ while (i > 0) {
+ i--;
+ PathPermission pp = pps[i];
+ String pprperm = pp.getReadPermission();
+ if (pprperm != null && ActivityManagerService.checkComponentPermission(pprperm,
+ callingPid, callingUid, cpi.applicationInfo.uid, cpi.exported)
+ == PackageManager.PERMISSION_GRANTED) {
+ return null;
+ }
+ String ppwperm = pp.getWritePermission();
+ if (ppwperm != null && ActivityManagerService.checkComponentPermission(ppwperm,
+ callingPid, callingUid, cpi.applicationInfo.uid, cpi.exported)
+ == PackageManager.PERMISSION_GRANTED) {
+ return null;
+ }
+ }
+ }
+ if (!checkedGrants
+ && mService.mUgmInternal.checkAuthorityGrants(callingUid, cpi, userId, checkUser)) {
+ return null;
+ }
+
+ final String suffix;
+ if (!cpi.exported) {
+ suffix = " that is not exported from UID " + cpi.applicationInfo.uid;
+ } else if (android.Manifest.permission.MANAGE_DOCUMENTS.equals(cpi.readPermission)) {
+ suffix = " requires that you obtain access using ACTION_OPEN_DOCUMENT or related APIs";
+ } else {
+ suffix = " requires " + cpi.readPermission + " or " + cpi.writePermission;
+ }
+ final String msg = "Permission Denial: opening provider " + cpi.name
+ + " from " + (r != null ? r : "(null)") + " (pid=" + callingPid
+ + ", uid=" + callingUid + ")" + suffix;
+ Slog.w(TAG, msg);
+ return msg;
+ }
+
+ private String checkContentProviderAssociation(ProcessRecord callingApp, int callingUid,
+ ProviderInfo cpi) {
+ if (callingApp == null) {
+ return mService.validateAssociationAllowedLocked(cpi.packageName,
+ cpi.applicationInfo.uid, null, callingUid) ? null : "<null>";
+ }
+ for (int i = callingApp.pkgList.size() - 1; i >= 0; i--) {
+ if (!mService.validateAssociationAllowedLocked(callingApp.pkgList.keyAt(i),
+ callingApp.uid, cpi.packageName, cpi.applicationInfo.uid)) {
+ return cpi.packageName;
+ }
+ }
+ return null;
+ }
+
+ ProviderInfo getProviderInfoLocked(String authority, @UserIdInt int userId, int pmFlags) {
+ ProviderInfo pi = null;
+ ContentProviderRecord cpr = mProviderMap.getProviderByName(authority, userId);
+ if (cpr != null) {
+ pi = cpr.info;
+ } else {
+ try {
+ pi = AppGlobals.getPackageManager().resolveContentProvider(
+ authority, PackageManager.GET_URI_PERMISSION_PATTERNS | pmFlags, userId);
+ } catch (RemoteException ex) {
+ }
+ }
+ return pi;
+ }
+
+ private void maybeUpdateProviderUsageStatsLocked(ProcessRecord app, String providerPkgName,
+ String authority) {
+ if (app == null
+ || app.getCurProcState() > ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND) {
+ return;
+ }
+
+
+ UserState userState = mService.mUserController.getStartedUserState(app.userId);
+ if (userState == null) return;
+ final long now = SystemClock.elapsedRealtime();
+ Long lastReported = userState.mProviderLastReportedFg.get(authority);
+ if (lastReported == null || lastReported < now - 60 * 1000L) {
+ if (mService.mSystemReady) {
+ // Cannot touch the user stats if not system ready
+ mService.mUsageStatsService.reportContentProviderUsage(
+ authority, providerPkgName, app.userId);
+ }
+ userState.mProviderLastReportedFg.put(authority, now);
+ }
+ }
+
+ private static final int[] PROCESS_STATE_STATS_FORMAT = new int[] {
+ PROC_SPACE_TERM,
+ PROC_SPACE_TERM | PROC_PARENS,
+ PROC_SPACE_TERM | PROC_CHAR | PROC_OUT_LONG, // 3: process state
+ };
+
+ private final long[] mProcessStateStatsLongs = new long[1];
+
+ private boolean isProcessAliveLocked(ProcessRecord proc) {
+ if (proc.pid <= 0) {
+ if (ActivityManagerDebugConfig.DEBUG_OOM_ADJ) {
+ Slog.d(ActivityManagerService.TAG, "Process hasn't started yet: " + proc);
+ }
+ return false;
+ }
+ if (proc.procStatFile == null) {
+ proc.procStatFile = "/proc/" + proc.pid + "/stat";
+ }
+ mProcessStateStatsLongs[0] = 0;
+ if (!Process.readProcFile(proc.procStatFile, PROCESS_STATE_STATS_FORMAT, null,
+ mProcessStateStatsLongs, null)) {
+ if (ActivityManagerDebugConfig.DEBUG_OOM_ADJ) {
+ Slog.d(ActivityManagerService.TAG,
+ "UNABLE TO RETRIEVE STATE FOR " + proc.procStatFile);
+ }
+ return false;
+ }
+ final long state = mProcessStateStatsLongs[0];
+ if (ActivityManagerDebugConfig.DEBUG_OOM_ADJ) {
+ Slog.d(ActivityManagerService.TAG,
+ "RETRIEVED STATE FOR " + proc.procStatFile + ": " + (char) state);
+ }
+ if (state != 'Z' && state != 'X' && state != 'x' && state != 'K') {
+ return Process.getUidForPid(proc.pid) == proc.uid;
+ }
+ return false;
+ }
+
+ private static final class StartActivityRunnable implements Runnable {
+ private final Context mContext;
+ private final Intent mIntent;
+ private final UserHandle mUserHandle;
+
+ StartActivityRunnable(Context context, Intent intent, UserHandle userHandle) {
+ this.mContext = context;
+ this.mIntent = intent;
+ this.mUserHandle = userHandle;
+ }
+
+ @Override
+ public void run() {
+ mContext.startActivityAsUser(mIntent, mUserHandle);
+ }
+ }
+
+ private boolean requestTargetProviderPermissionsReviewIfNeededLocked(ProviderInfo cpi,
+ ProcessRecord r, final int userId, Context context) {
+ if (!mService.getPackageManagerInternalLocked().isPermissionsReviewRequired(
+ cpi.packageName, userId)) {
+ return true;
+ }
+
+ final boolean callerForeground = r == null
+ || r.setSchedGroup != ProcessList.SCHED_GROUP_BACKGROUND;
+
+ // Show a permission review UI only for starting from a foreground app
+ if (!callerForeground) {
+ Slog.w(TAG, "u" + userId + " Instantiating a provider in package "
+ + cpi.packageName + " requires a permissions review");
+ return false;
+ }
+
+ final Intent intent = new Intent(Intent.ACTION_REVIEW_PERMISSIONS);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
+ intent.putExtra(Intent.EXTRA_PACKAGE_NAME, cpi.packageName);
+
+ if (ActivityManagerDebugConfig.DEBUG_PERMISSIONS_REVIEW) {
+ Slog.i(TAG, "u" + userId + " Launching permission review "
+ + "for package " + cpi.packageName);
+ }
+
+ final UserHandle userHandle = new UserHandle(userId);
+ mService.mHandler.post(new StartActivityRunnable(context, intent, userHandle));
+
+ return false;
+ }
+
+ /**
+ * Remove the dying provider from known provider map and launching provider map.
+ * @param proc The dying process recoder
+ * @param cpr The provider to be removed.
+ * @param always If true, remove the provider from launching map always, no more restart attempt
+ * @return true if the given provider is in launching
+ */
+ boolean removeDyingProviderLocked(ProcessRecord proc, ContentProviderRecord cpr,
+ boolean always) {
+ boolean inLaunching = mLaunchingProviders.contains(cpr);
+ if (inLaunching && !always && ++cpr.mRestartCount > ContentProviderRecord.MAX_RETRY_COUNT) {
+ // It's being launched but we've reached maximum attempts, force the removal
+ always = true;
+ }
+
+ if (!inLaunching || always) {
+ synchronized (cpr) {
+ cpr.launchingApp = null;
+ cpr.notifyAll();
+ }
+ final int userId = UserHandle.getUserId(cpr.uid);
+ // Don't remove from provider map if it doesn't match
+ // could be a new content provider is starting
+ if (mProviderMap.getProviderByClass(cpr.name, userId) == cpr) {
+ mProviderMap.removeProviderByClass(cpr.name, userId);
+ }
+ String[] names = cpr.info.authority.split(";");
+ for (int j = 0; j < names.length; j++) {
+ // Don't remove from provider map if it doesn't match
+ // could be a new content provider is starting
+ if (mProviderMap.getProviderByName(names[j], userId) == cpr) {
+ mProviderMap.removeProviderByName(names[j], userId);
+ }
+ }
+ }
+
+ for (int i = cpr.connections.size() - 1; i >= 0; i--) {
+ ContentProviderConnection conn = cpr.connections.get(i);
+ if (conn.waiting) {
+ // If this connection is waiting for the provider, then we don't
+ // need to mess with its process unless we are always removing
+ // or for some reason the provider is not currently launching.
+ if (inLaunching && !always) {
+ continue;
+ }
+ }
+ ProcessRecord capp = conn.client;
+ conn.dead = true;
+ if (conn.stableCount() > 0) {
+ if (!capp.isPersistent() && capp.thread != null
+ && capp.pid != 0 && capp.pid != ActivityManagerService.MY_PID) {
+ capp.kill("depends on provider " + cpr.name.flattenToShortString()
+ + " in dying proc " + (proc != null ? proc.processName : "??")
+ + " (adj " + (proc != null ? proc.setAdj : "??") + ")",
+ ApplicationExitInfo.REASON_DEPENDENCY_DIED,
+ ApplicationExitInfo.SUBREASON_UNKNOWN,
+ true);
+ }
+ } else if (capp.thread != null && conn.provider.provider != null) {
+ try {
+ capp.thread.unstableProviderDied(conn.provider.provider.asBinder());
+ } catch (RemoteException e) {
+ }
+ // In the protocol here, we don't expect the client to correctly
+ // clean up this connection, we'll just remove it.
+ cpr.connections.remove(i);
+ if (conn.client.conProviders.remove(conn)) {
+ mService.stopAssociationLocked(capp.uid, capp.processName,
+ cpr.uid, cpr.appInfo.longVersionCode, cpr.name, cpr.info.processName);
+ }
+ }
+ }
+
+ if (inLaunching && always) {
+ mLaunchingProviders.remove(cpr);
+ cpr.mRestartCount = 0;
+ inLaunching = false;
+ }
+ return inLaunching;
+ }
+
+ boolean checkAppInLaunchingProvidersLocked(ProcessRecord app) {
+ for (int i = mLaunchingProviders.size() - 1; i >= 0; i--) {
+ ContentProviderRecord cpr = mLaunchingProviders.get(i);
+ if (cpr.launchingApp == app) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ boolean cleanupAppInLaunchingProvidersLocked(ProcessRecord app, boolean alwaysBad) {
+ // Look through the content providers we are waiting to have launched,
+ // and if any run in this process then either schedule a restart of
+ // the process or kill the client waiting for it if this process has
+ // gone bad.
+ boolean restart = false;
+ for (int i = mLaunchingProviders.size() - 1; i >= 0; i--) {
+ ContentProviderRecord cpr = mLaunchingProviders.get(i);
+ if (cpr.launchingApp != app) {
+ continue;
+ }
+
+ if (++cpr.mRestartCount > ContentProviderRecord.MAX_RETRY_COUNT) {
+ // It's being launched but we've reached maximum attempts, mark it as bad
+ alwaysBad = true;
+ }
+ if (!alwaysBad && !app.bad && cpr.hasConnectionOrHandle()) {
+ restart = true;
+ } else {
+ removeDyingProviderLocked(app, cpr, true);
+ }
+ }
+ return restart;
+ }
+
+ void cleanupLaunchingProvidersLocked() {
+ for (int i = mLaunchingProviders.size() - 1; i >= 0; i--) {
+ ContentProviderRecord cpr = mLaunchingProviders.get(i);
+ if (cpr.connections.size() <= 0 && !cpr.hasExternalProcessHandles()) {
+ synchronized (cpr) {
+ cpr.launchingApp = null;
+ cpr.notifyAll();
+ }
+ }
+ }
+ }
+
+ private void checkTime(long startTime, String where) {
+ long now = SystemClock.uptimeMillis();
+ if ((now - startTime) > 50) {
+ // If we are taking more than 50ms, log about it.
+ Slog.w(TAG, "Slow operation: " + (now - startTime) + "ms so far, now at " + where);
+ }
+ }
+
+ void dumpProvidersLocked(FileDescriptor fd, PrintWriter pw, String[] args,
+ int opti, boolean dumpAll, String dumpPackage) {
+ ActivityManagerService.ItemMatcher matcher = new ActivityManagerService.ItemMatcher();
+ matcher.build(args, opti);
+
+ pw.println("ACTIVITY MANAGER CONTENT PROVIDERS (dumpsys activity providers)");
+
+ boolean needSep = mProviderMap.dumpProvidersLocked(pw, dumpAll, dumpPackage);
+ boolean printedAnything = needSep;
+
+ if (mLaunchingProviders.size() > 0) {
+ boolean printed = false;
+ for (int i = mLaunchingProviders.size() - 1; i >= 0; i--) {
+ ContentProviderRecord r = mLaunchingProviders.get(i);
+ if (dumpPackage != null && !dumpPackage.equals(r.name.getPackageName())) {
+ continue;
+ }
+ if (!printed) {
+ if (needSep) pw.println();
+ needSep = true;
+ pw.println(" Launching content providers:");
+ printed = true;
+ printedAnything = true;
+ }
+ pw.print(" Launching #"); pw.print(i); pw.print(": ");
+ pw.println(r);
+ }
+ }
+
+ if (!printedAnything) {
+ pw.println(" (nothing)");
+ }
+ }
+
+ /**
+ * There are three ways to call this:
+ * - no provider specified: dump all the providers
+ * - a flattened component name that matched an existing provider was specified as the
+ * first arg: dump that one provider
+ * - the first arg isn't the flattened component name of an existing provider:
+ * dump all providers whose component contains the first arg as a substring
+ */
+ protected boolean dumpProvider(FileDescriptor fd, PrintWriter pw, String name, String[] args,
+ int opti, boolean dumpAll) {
+ return mProviderMap.dumpProvider(fd, pw, name, args, opti, dumpAll);
+ }
+
+ /**
+ * Similar to the dumpProvider, but only dumps the first matching provider.
+ * The provider is responsible for dumping as proto.
+ */
+ protected boolean dumpProviderProto(FileDescriptor fd, PrintWriter pw, String name,
+ String[] args) {
+ return mProviderMap.dumpProviderProto(fd, pw, name, args);
+ }
+}
diff --git a/services/core/java/com/android/server/am/CoreSettingsObserver.java b/services/core/java/com/android/server/am/CoreSettingsObserver.java
index ca61788d1918..00b33c4c3e68 100644
--- a/services/core/java/com/android/server/am/CoreSettingsObserver.java
+++ b/services/core/java/com/android/server/am/CoreSettingsObserver.java
@@ -105,9 +105,9 @@ final class CoreSettingsObserver extends ContentObserver {
sGlobalSettingToTypeMap.put(
Settings.Global.GAME_DRIVER_PRERELEASE_OPT_IN_APPS, String.class);
sGlobalSettingToTypeMap.put(Settings.Global.GAME_DRIVER_OPT_OUT_APPS, String.class);
- sGlobalSettingToTypeMap.put(Settings.Global.GAME_DRIVER_BLACKLIST, String.class);
- sGlobalSettingToTypeMap.put(Settings.Global.GAME_DRIVER_WHITELIST, String.class);
- sGlobalSettingToTypeMap.put(Settings.Global.GAME_DRIVER_BLACKLISTS, String.class);
+ sGlobalSettingToTypeMap.put(Settings.Global.GAME_DRIVER_DENYLIST, String.class);
+ sGlobalSettingToTypeMap.put(Settings.Global.GAME_DRIVER_ALLOWLIST, String.class);
+ sGlobalSettingToTypeMap.put(Settings.Global.GAME_DRIVER_DENYLISTS, String.class);
sGlobalSettingToTypeMap.put(Settings.Global.GAME_DRIVER_SPHAL_LIBRARIES, String.class);
// add other global settings here...
diff --git a/services/core/java/com/android/server/am/OWNERS b/services/core/java/com/android/server/am/OWNERS
index 1f826b5253bd..60530c4eb920 100644
--- a/services/core/java/com/android/server/am/OWNERS
+++ b/services/core/java/com/android/server/am/OWNERS
@@ -31,3 +31,5 @@ narayan@google.com
per-file SettingsToPropertiesMapper.java = omakoto@google.com, svetoslavganov@google.com, yamasani@google.com
per-file CarUserSwitchingDialog.java = keunyoung@google.com, felipeal@google.com, gurunagarajan@google.com
+
+per-file ContentProviderHelper.java = varunshah@google.com, omakoto@google.com, jsharkey@google.com, yamasani@google.com
diff --git a/services/core/java/com/android/server/am/PendingIntentRecord.java b/services/core/java/com/android/server/am/PendingIntentRecord.java
index 1997dbd6fc37..fbfed34d1bf0 100644
--- a/services/core/java/com/android/server/am/PendingIntentRecord.java
+++ b/services/core/java/com/android/server/am/PendingIntentRecord.java
@@ -437,15 +437,17 @@ public final class PendingIntentRecord extends IIntentSender.Stub {
break;
case ActivityManager.INTENT_SENDER_BROADCAST:
try {
+ final boolean allowedByToken =
+ mAllowBgActivityStartsForBroadcastSender.contains(whitelistToken);
+ final IBinder bgStartsToken = (allowedByToken) ? whitelistToken : null;
+
// If a completion callback has been requested, require
// that the broadcast be delivered synchronously
int sent = controller.mAmInternal.broadcastIntentInPackage(key.packageName,
key.featureId, uid, callingUid, callingPid, finalIntent,
resolvedType, finishedReceiver, code, null, null,
requiredPermission, options, (finishedReceiver != null), false,
- userId,
- mAllowBgActivityStartsForBroadcastSender.contains(whitelistToken)
- || allowTrampoline);
+ userId, allowedByToken || allowTrampoline, bgStartsToken);
if (sent == ActivityManager.BROADCAST_SUCCESS) {
sendFinish = false;
}
@@ -456,11 +458,14 @@ public final class PendingIntentRecord extends IIntentSender.Stub {
case ActivityManager.INTENT_SENDER_SERVICE:
case ActivityManager.INTENT_SENDER_FOREGROUND_SERVICE:
try {
+ final boolean allowedByToken =
+ mAllowBgActivityStartsForServiceSender.contains(whitelistToken);
+ final IBinder bgStartsToken = (allowedByToken) ? whitelistToken : null;
+
controller.mAmInternal.startServiceInPackage(uid, finalIntent, resolvedType,
key.type == ActivityManager.INTENT_SENDER_FOREGROUND_SERVICE,
key.packageName, key.featureId, userId,
- mAllowBgActivityStartsForServiceSender.contains(whitelistToken)
- || allowTrampoline);
+ allowedByToken || allowTrampoline, bgStartsToken);
} catch (RuntimeException e) {
Slog.w(TAG, "Unable to send startService intent", e);
} catch (TransactionTooLargeException e) {
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 1038069f5d11..5721fb7f5128 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -2951,25 +2951,26 @@ public final class ProcessList {
if ((expecting == null) || (old == expecting)) {
mProcessNames.remove(name, uid);
}
- if (old != null && old.uidRecord != null) {
- old.uidRecord.numProcs--;
- old.uidRecord.procRecords.remove(old);
- if (old.uidRecord.numProcs == 0) {
+ final ProcessRecord record = expecting != null ? expecting : old;
+ if (record != null && record.uidRecord != null) {
+ final UidRecord uidRecord = record.uidRecord;
+ uidRecord.numProcs--;
+ uidRecord.procRecords.remove(record);
+ if (uidRecord.numProcs == 0) {
// No more processes using this uid, tell clients it is gone.
if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS,
- "No more processes in " + old.uidRecord);
- mService.enqueueUidChangeLocked(old.uidRecord, -1, UidRecord.CHANGE_GONE);
+ "No more processes in " + uidRecord);
+ mService.enqueueUidChangeLocked(uidRecord, -1, UidRecord.CHANGE_GONE);
EventLogTags.writeAmUidStopped(uid);
mActiveUids.remove(uid);
mService.noteUidProcessState(uid, ActivityManager.PROCESS_STATE_NONEXISTENT,
ActivityManager.PROCESS_CAPABILITY_NONE);
}
- old.uidRecord = null;
+ record.uidRecord = null;
}
mIsolatedProcesses.remove(uid);
mGlobalIsolatedUids.freeIsolatedUidLocked(uid);
// Remove the (expected) ProcessRecord from the app zygote
- final ProcessRecord record = expecting != null ? expecting : old;
if (record != null && record.appZygote) {
removeProcessFromAppZygoteLocked(record);
}
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index 6e1bd8faeaf9..cd4302bb42fa 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -25,6 +25,7 @@ import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.am.ActivityManagerService.MY_PID;
+import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ApplicationErrorReport;
import android.app.ApplicationExitInfo;
@@ -274,9 +275,6 @@ class ProcessRecord implements WindowProcessListener {
final ArrayMap<String, ContentProviderRecord> pubProviders = new ArrayMap<>();
// All ContentProviderRecord process is using
final ArrayList<ContentProviderConnection> conProviders = new ArrayList<>();
- // A set of tokens that currently contribute to this process being temporarily allowed
- // to start activities even if it's not in the foreground
- final ArraySet<Binder> mAllowBackgroundActivityStartsTokens = new ArraySet<>();
// a set of UIDs of all bound clients
private ArraySet<Integer> mBoundClientUids = new ArraySet<>();
@@ -627,13 +625,6 @@ class ProcessRecord implements WindowProcessListener {
pw.print(prefix); pw.print(" - "); pw.println(receivers.valueAt(i));
}
}
- if (mAllowBackgroundActivityStartsTokens.size() > 0) {
- pw.print(prefix); pw.println("Background activity start tokens:");
- for (int i = 0; i < mAllowBackgroundActivityStartsTokens.size(); i++) {
- pw.print(prefix); pw.print(" - ");
- pw.println(mAllowBackgroundActivityStartsTokens.valueAt(i));
- }
- }
}
ProcessRecord(ActivityManagerService _service, ApplicationInfo _info, String _processName,
@@ -1331,17 +1322,23 @@ class ProcessRecord implements WindowProcessListener {
return mUsingWrapper;
}
- void addAllowBackgroundActivityStartsToken(Binder entity) {
+ /**
+ * Allows background activity starts using token {@param entity}. Optionally, you can provide
+ * {@param originatingToken} if you have one such originating token, this is useful for tracing
+ * back the grant in the case of the notification token.
+ */
+ void addAllowBackgroundActivityStartsToken(Binder entity, @Nullable IBinder originatingToken) {
if (entity == null) return;
- mAllowBackgroundActivityStartsTokens.add(entity);
- mWindowProcessController.setAllowBackgroundActivityStarts(true);
+ mWindowProcessController.addAllowBackgroundActivityStartsToken(entity, originatingToken);
}
void removeAllowBackgroundActivityStartsToken(Binder entity) {
if (entity == null) return;
- mAllowBackgroundActivityStartsTokens.remove(entity);
- mWindowProcessController.setAllowBackgroundActivityStarts(
- !mAllowBackgroundActivityStartsTokens.isEmpty());
+ mWindowProcessController.removeAllowBackgroundActivityStartsToken(entity);
+ }
+
+ boolean areBackgroundActivityStartsAllowedByToken() {
+ return mWindowProcessController.areBackgroundActivityStartsAllowedByToken();
}
void addBoundClientUid(int clientUid) {
diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java
index db05d65b92fe..022b04d89774 100644
--- a/services/core/java/com/android/server/am/ServiceRecord.java
+++ b/services/core/java/com/android/server/am/ServiceRecord.java
@@ -575,7 +575,7 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN
? _proc : null;
if (mIsAllowedBgActivityStartsByStart
|| mIsAllowedBgActivityStartsByBinding) {
- _proc.addAllowBackgroundActivityStartsToken(this);
+ _proc.addAllowBackgroundActivityStartsToken(this, null);
} else {
_proc.removeAllowBackgroundActivityStartsToken(this);
}
@@ -723,7 +723,9 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN
* {@code mIsAllowedBgActivityStartsByBinding}. If either is true, this ServiceRecord
* should be contributing as a token in parent ProcessRecord.
*
- * @see com.android.server.am.ProcessRecord#mAllowBackgroundActivityStartsTokens
+ * @see com.android.server.am.ProcessRecord#addAllowBackgroundActivityStartsToken(Binder,
+ * IBinder)
+ * @see com.android.server.am.ProcessRecord#removeAllowBackgroundActivityStartsToken(Binder)
*/
private void updateParentProcessBgActivityStartsToken() {
if (app == null) {
@@ -732,7 +734,7 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN
if (mIsAllowedBgActivityStartsByStart || mIsAllowedBgActivityStartsByBinding) {
// if the token is already there it's safe to "re-add it" - we're dealing with
// a set of Binder objects
- app.addAllowBackgroundActivityStartsToken(this);
+ app.addAllowBackgroundActivityStartsToken(this, null);
} else {
app.removeAllowBackgroundActivityStartsToken(this);
}
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index 9562158f9bb6..19b671e46b71 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -23,10 +23,11 @@ import static android.app.ActivityManager.USER_OP_ERROR_IS_SYSTEM;
import static android.app.ActivityManager.USER_OP_ERROR_RELATED_USERS_CANNOT_STOP;
import static android.app.ActivityManager.USER_OP_IS_CURRENT;
import static android.app.ActivityManager.USER_OP_SUCCESS;
-import static android.app.ActivityManagerInternal.ALLOW_ALL_PROFILE_PERMISSIONS_IN_PROFILE;
+import static android.app.ActivityManagerInternal.ALLOW_ACROSS_PROFILES_IN_PROFILE_OR_NON_FULL;
+import static android.app.ActivityManagerInternal.ALLOW_ACROSS_PROFILES_IN_PROFILE_OR_FULL;
import static android.app.ActivityManagerInternal.ALLOW_FULL_ONLY;
import static android.app.ActivityManagerInternal.ALLOW_NON_FULL;
-import static android.app.ActivityManagerInternal.ALLOW_NON_FULL_IN_PROFILE;
+import static android.app.ActivityManagerInternal.ALLOW_NON_FULL_IN_PROFILE_OR_FULL;
import static android.os.Process.SHELL_UID;
import static android.os.Process.SYSTEM_UID;
@@ -1891,8 +1892,7 @@ class UserController implements Handler.Callback {
if (callingUid != 0 && callingUid != SYSTEM_UID) {
final boolean allow;
final boolean isSameProfileGroup = isSameProfileGroup(callingUserId, targetUserId);
- if (mInjector.isCallerRecents(callingUid)
- && isSameProfileGroup(callingUserId, targetUserId)) {
+ if (mInjector.isCallerRecents(callingUid) && isSameProfileGroup) {
// If the caller is Recents and the caller has ownership of the profile group,
// we then allow it to access its profiles.
allow = true;
@@ -1910,11 +1910,12 @@ class UserController implements Handler.Callback {
callingUid, -1, true) != PackageManager.PERMISSION_GRANTED) {
// If the caller does not have either permission, they are always doomed.
allow = false;
- } else if (allowMode == ALLOW_NON_FULL) {
+ } else if (allowMode == ALLOW_NON_FULL
+ || allowMode == ALLOW_ACROSS_PROFILES_IN_PROFILE_OR_NON_FULL) {
// We are blanket allowing non-full access, you lucky caller!
allow = true;
- } else if (allowMode == ALLOW_NON_FULL_IN_PROFILE
- || allowMode == ALLOW_ALL_PROFILE_PERMISSIONS_IN_PROFILE) {
+ } else if (allowMode == ALLOW_NON_FULL_IN_PROFILE_OR_FULL
+ || allowMode == ALLOW_ACROSS_PROFILES_IN_PROFILE_OR_FULL) {
// We may or may not allow this depending on whether the two users are
// in the same profile.
allow = isSameProfileGroup;
@@ -1941,12 +1942,15 @@ class UserController implements Handler.Callback {
builder.append("; this requires ");
builder.append(INTERACT_ACROSS_USERS_FULL);
if (allowMode != ALLOW_FULL_ONLY) {
- if (allowMode == ALLOW_NON_FULL || isSameProfileGroup) {
+ if (allowMode == ALLOW_NON_FULL
+ || allowMode == ALLOW_ACROSS_PROFILES_IN_PROFILE_OR_NON_FULL
+ || isSameProfileGroup) {
builder.append(" or ");
builder.append(INTERACT_ACROSS_USERS);
}
if (isSameProfileGroup
- && allowMode == ALLOW_ALL_PROFILE_PERMISSIONS_IN_PROFILE) {
+ && (allowMode == ALLOW_ACROSS_PROFILES_IN_PROFILE_OR_FULL
+ || allowMode == ALLOW_ACROSS_PROFILES_IN_PROFILE_OR_NON_FULL)) {
builder.append(" or ");
builder.append(INTERACT_ACROSS_PROFILES);
}
@@ -1973,7 +1977,8 @@ class UserController implements Handler.Callback {
private boolean canInteractWithAcrossProfilesPermission(
int allowMode, boolean isSameProfileGroup, int callingPid, int callingUid,
String callingPackage) {
- if (allowMode != ALLOW_ALL_PROFILE_PERMISSIONS_IN_PROFILE) {
+ if (allowMode != ALLOW_ACROSS_PROFILES_IN_PROFILE_OR_FULL
+ && allowMode != ALLOW_ACROSS_PROFILES_IN_PROFILE_OR_NON_FULL) {
return false;
}
if (!isSameProfileGroup) {
@@ -2883,7 +2888,7 @@ class UserController implements Handler.Callback {
}
void installEncryptionUnawareProviders(@UserIdInt int userId) {
- mService.installEncryptionUnawareProviders(userId);
+ mService.mCpHelper.installEncryptionUnawareProviders(userId);
}
void showUserSwitchingDialog(UserInfo fromUser, UserInfo toUser,
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index e6480fc6cde8..74f3daf50079 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -19,6 +19,7 @@ package com.android.server.appop;
import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_CAMERA;
import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_LOCATION;
import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_MICROPHONE;
+import static android.app.ActivityManagerInternal.ALLOW_ACROSS_PROFILES_IN_PROFILE_OR_NON_FULL;
import static android.app.AppOpsManager.CALL_BACK_ON_SWITCHED_OP;
import static android.app.AppOpsManager.FILTER_BY_ATTRIBUTION_TAG;
import static android.app.AppOpsManager.FILTER_BY_OP_NAMES;
@@ -128,6 +129,7 @@ import android.provider.Settings;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.AtomicFile;
+import android.util.EventLog;
import android.util.KeyValueListParser;
import android.util.LongSparseArray;
import android.util.Pair;
@@ -161,6 +163,7 @@ import com.android.server.LocalServices;
import com.android.server.LockGuard;
import com.android.server.SystemServerInitThreadPool;
import com.android.server.SystemServiceManager;
+import com.android.server.am.ActivityManagerService;
import com.android.server.pm.PackageList;
import com.android.server.pm.parsing.pkg.AndroidPackage;
@@ -2197,8 +2200,11 @@ public class AppOpsService extends IAppOpsService.Stub {
+ " by uid " + Binder.getCallingUid());
}
+ int userId = UserHandle.getUserId(uid);
+
enforceManageAppOpsModes(Binder.getCallingPid(), Binder.getCallingUid(), uid);
verifyIncomingOp(code);
+ verifyIncomingUser(userId);
code = AppOpsManager.opToSwitch(code);
if (permissionPolicyCallback == null) {
@@ -2443,8 +2449,12 @@ public class AppOpsService extends IAppOpsService.Stub {
private void setMode(int code, int uid, @NonNull String packageName, int mode,
@Nullable IAppOpsCallback permissionPolicyCallback) {
enforceManageAppOpsModes(Binder.getCallingPid(), Binder.getCallingUid(), uid);
+
+ int userId = UserHandle.getUserId(uid);
+
verifyIncomingOp(code);
- verifyIncomingPackage(packageName, UserHandle.getUserId(uid));
+ verifyIncomingUser(userId);
+ verifyIncomingPackage(packageName, userId);
ArraySet<ModeCallback> repCbs = null;
code = AppOpsManager.opToSwitch(code);
@@ -2857,8 +2867,11 @@ public class AppOpsService extends IAppOpsService.Stub {
private int checkOperationImpl(int code, int uid, String packageName,
boolean raw) {
+ int userId = UserHandle.getUserId(uid);
+
verifyIncomingOp(code);
- verifyIncomingPackage(packageName, UserHandle.getUserId(uid));
+ verifyIncomingUser(userId);
+ verifyIncomingPackage(packageName, userId);
String resolvedPackageName = resolvePackageName(uid, packageName);
if (resolvedPackageName == null) {
@@ -2977,10 +2990,15 @@ public class AppOpsService extends IAppOpsService.Stub {
String proxiedAttributionTag, int proxyUid, String proxyPackageName,
String proxyAttributionTag, boolean shouldCollectAsyncNotedOp, String message,
boolean shouldCollectMessage) {
+ int proxiedUserId = UserHandle.getUserId(proxiedUid);
+ int proxyUserId = UserHandle.getUserId(proxyUid);
+
verifyIncomingUid(proxyUid);
verifyIncomingOp(code);
- verifyIncomingPackage(proxiedPackageName, UserHandle.getUserId(proxiedUid));
- verifyIncomingPackage(proxyPackageName, UserHandle.getUserId(proxyUid));
+ verifyIncomingUser(proxiedUserId);
+ verifyIncomingUser(proxyUserId);
+ verifyIncomingPackage(proxiedPackageName, proxiedUserId);
+ verifyIncomingPackage(proxyPackageName, proxyUserId);
String resolveProxyPackageName = resolvePackageName(proxyUid, proxyPackageName);
if (resolveProxyPackageName == null) {
@@ -3030,9 +3048,12 @@ public class AppOpsService extends IAppOpsService.Stub {
private int noteOperationImpl(int code, int uid, @Nullable String packageName,
@Nullable String attributionTag, boolean shouldCollectAsyncNotedOp,
@Nullable String message, boolean shouldCollectMessage) {
+ int userId = UserHandle.getUserId(uid);
+
verifyIncomingUid(uid);
verifyIncomingOp(code);
- verifyIncomingPackage(packageName, UserHandle.getUserId(uid));
+ verifyIncomingUser(userId);
+ verifyIncomingPackage(packageName, userId);
String resolvedPackageName = resolvePackageName(uid, packageName);
if (resolvedPackageName == null) {
@@ -3409,9 +3430,12 @@ public class AppOpsService extends IAppOpsService.Stub {
public int startOperation(IBinder clientId, int code, int uid, String packageName,
String attributionTag, boolean startIfModeDefault, boolean shouldCollectAsyncNotedOp,
String message, boolean shouldCollectMessage) {
+ int userId = UserHandle.getUserId(uid);
+
verifyIncomingUid(uid);
verifyIncomingOp(code);
- verifyIncomingPackage(packageName, UserHandle.getUserId(uid));
+ verifyIncomingUser(userId);
+ verifyIncomingPackage(packageName, userId);
String resolvedPackageName = resolvePackageName(uid, packageName);
if (resolvedPackageName == null) {
@@ -3491,9 +3515,12 @@ public class AppOpsService extends IAppOpsService.Stub {
@Override
public void finishOperation(IBinder clientId, int code, int uid, String packageName,
String attributionTag) {
+ int userId = UserHandle.getUserId(uid);
+
verifyIncomingUid(uid);
verifyIncomingOp(code);
- verifyIncomingPackage(packageName, UserHandle.getUserId(uid));
+ verifyIncomingUser(userId);
+ verifyIncomingPackage(packageName, userId);
String resolvedPackageName = resolvePackageName(uid, packageName);
if (resolvedPackageName == null) {
@@ -3722,6 +3749,33 @@ public class AppOpsService extends IAppOpsService.Stub {
}
}
+ private void verifyIncomingUser(@UserIdInt int userId) {
+ int callingUid = Binder.getCallingUid();
+ int callingUserId = UserHandle.getUserId(callingUid);
+ int callingPid = Binder.getCallingPid();
+
+ if (callingUserId != userId) {
+ // Prevent endless loop between when checking appops inside of handleIncomingUser
+ if (Binder.getCallingPid() == ActivityManagerService.MY_PID) {
+ return;
+ }
+ long token = Binder.clearCallingIdentity();
+ try {
+ try {
+ LocalServices.getService(ActivityManagerInternal.class).handleIncomingUser(
+ callingPid, callingUid, userId, /* allowAll */ false,
+ ALLOW_ACROSS_PROFILES_IN_PROFILE_OR_NON_FULL, "appop operation", null);
+ } catch (Exception e) {
+ EventLog.writeEvent(0x534e4554, "153996875", "appop", userId);
+
+ throw e;
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+ }
+
private @Nullable UidState getUidStateLocked(int uid, boolean edit) {
UidState uidState = mUidStates.get(uid);
if (uidState == null) {
@@ -5801,8 +5855,11 @@ public class AppOpsService extends IAppOpsService.Stub {
return false;
}
}
+ int userId = UserHandle.getUserId(uid);
+
verifyIncomingOp(code);
- verifyIncomingPackage(packageName, UserHandle.getUserId(uid));
+ verifyIncomingUser(userId);
+ verifyIncomingPackage(packageName, userId);
final String resolvedPackageName = resolvePackageName(uid, packageName);
if (resolvedPackageName == null) {
diff --git a/services/core/java/com/android/server/appop/TEST_MAPPING b/services/core/java/com/android/server/appop/TEST_MAPPING
index 84de25c06ebf..a3e1b7a7e5c5 100644
--- a/services/core/java/com/android/server/appop/TEST_MAPPING
+++ b/services/core/java/com/android/server/appop/TEST_MAPPING
@@ -7,6 +7,9 @@
"name": "CtsAppOps2TestCases"
},
{
+ "name": "CtsAppOpHostTestCases"
+ },
+ {
"name": "FrameworksServicesTests",
"options": [
{
diff --git a/services/core/java/com/android/server/attention/AttentionManagerService.java b/services/core/java/com/android/server/attention/AttentionManagerService.java
index 7051e4a294e2..e128d993ab63 100644
--- a/services/core/java/com/android/server/attention/AttentionManagerService.java
+++ b/services/core/java/com/android/server/attention/AttentionManagerService.java
@@ -108,7 +108,8 @@ public class AttentionManagerService extends SystemService {
private final PowerManager mPowerManager;
private final Object mLock;
@GuardedBy("mLock")
- private IAttentionService mService;
+ @VisibleForTesting
+ protected IAttentionService mService;
@GuardedBy("mLock")
private AttentionCheckCacheBuffer mAttentionCheckCacheBuffer;
@GuardedBy("mLock")
@@ -158,7 +159,8 @@ public class AttentionManagerService extends SystemService {
}
/** Resolves and sets up the attention service if it had not been done yet. */
- private boolean isServiceAvailable() {
+ @VisibleForTesting
+ protected boolean isServiceAvailable() {
if (mComponentName == null) {
mComponentName = resolveAttentionService(mContext);
}
@@ -168,12 +170,12 @@ public class AttentionManagerService extends SystemService {
/**
* Returns {@code true} if attention service is supported on this device.
*/
- private boolean isAttentionServiceSupported() {
+ @VisibleForTesting
+ protected boolean isAttentionServiceSupported() {
return isServiceEnabled() && isServiceConfigured(mContext);
}
- @VisibleForTesting
- protected boolean isServiceEnabled() {
+ private boolean isServiceEnabled() {
return DeviceConfig.getBoolean(NAMESPACE_ATTENTION_MANAGER_SERVICE, KEY_SERVICE_ENABLED,
DEFAULT_SERVICE_ENABLED);
}
diff --git a/services/core/java/com/android/server/connectivity/PermissionMonitor.java b/services/core/java/com/android/server/connectivity/PermissionMonitor.java
index a75a80a606eb..f8774b1b0054 100644
--- a/services/core/java/com/android/server/connectivity/PermissionMonitor.java
+++ b/services/core/java/com/android/server/connectivity/PermissionMonitor.java
@@ -21,14 +21,23 @@ import static android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS;
import static android.Manifest.permission.INTERNET;
import static android.Manifest.permission.NETWORK_STACK;
import static android.Manifest.permission.UPDATE_DEVICE_STATS;
-import static android.content.pm.PackageInfo.REQUESTED_PERMISSION_GRANTED;
import static android.content.pm.PackageManager.GET_PERMISSIONS;
import static android.content.pm.PackageManager.MATCH_ANY_USER;
+import static android.net.INetd.PERMISSION_INTERNET;
+import static android.net.INetd.PERMISSION_NETWORK;
+import static android.net.INetd.PERMISSION_NONE;
+import static android.net.INetd.PERMISSION_SYSTEM;
+import static android.net.INetd.PERMISSION_UNINSTALLED;
+import static android.net.INetd.PERMISSION_UPDATE_DEVICE_STATS;
import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK;
import static android.os.Process.INVALID_UID;
import static android.os.Process.SYSTEM_UID;
+import static com.android.internal.util.ArrayUtils.convertToIntArray;
+
import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.ActivityManager;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
@@ -51,7 +60,6 @@ import android.util.SparseIntArray;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.ArrayUtils;
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.LocalServices;
import com.android.server.SystemConfig;
@@ -65,7 +73,6 @@ import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
-
/**
* A utility class to inform Netd of UID permisisons.
* Does a mass update at boot and then monitors for app install/remove.
@@ -114,6 +121,13 @@ public class PermissionMonitor implements PackageManagerInternal.PackageListObse
public int getDeviceFirstSdkInt() {
return Build.VERSION.FIRST_SDK_INT;
}
+
+ /**
+ * Check whether given uid has specific permission.
+ */
+ public int uidPermission(@NonNull final String permission, final int uid) {
+ return ActivityManager.checkUidPermission(permission, uid);
+ }
}
public PermissionMonitor(@NonNull final Context context, @NonNull final INetd netd) {
@@ -156,8 +170,9 @@ public class PermissionMonitor implements PackageManagerInternal.PackageListObse
}
mAllApps.add(UserHandle.getAppId(uid));
- boolean isNetwork = hasNetworkPermission(app);
- boolean hasRestrictedPermission = hasRestrictedNetworkPermission(app);
+ final boolean isNetwork = hasPermission(CHANGE_NETWORK_STATE, uid);
+ final boolean hasRestrictedPermission =
+ hasRestrictedNetworkPermission(app.applicationInfo);
if (isNetwork || hasRestrictedPermission) {
Boolean permission = mApps.get(uid);
@@ -169,8 +184,7 @@ public class PermissionMonitor implements PackageManagerInternal.PackageListObse
}
//TODO: unify the management of the permissions into one codepath.
- int otherNetdPerms = getNetdPermissionMask(app.requestedPermissions,
- app.requestedPermissionsFlags);
+ final int otherNetdPerms = getNetdPermissionMask(uid);
netdPermsUids.put(uid, netdPermsUids.get(uid) | otherNetdPerms);
}
@@ -190,9 +204,8 @@ public class PermissionMonitor implements PackageManagerInternal.PackageListObse
// Get the uids of native services that have UPDATE_DEVICE_STATS or INTERNET permission.
if (perms != null) {
netdPermission |= perms.contains(UPDATE_DEVICE_STATS)
- ? INetd.PERMISSION_UPDATE_DEVICE_STATS : 0;
- netdPermission |= perms.contains(INTERNET)
- ? INetd.PERMISSION_INTERNET : 0;
+ ? PERMISSION_UPDATE_DEVICE_STATS : 0;
+ netdPermission |= perms.contains(INTERNET) ? PERMISSION_INTERNET : 0;
}
netdPermsUids.put(uid, netdPermsUids.get(uid) | netdPermission);
}
@@ -207,48 +220,33 @@ public class PermissionMonitor implements PackageManagerInternal.PackageListObse
}
@VisibleForTesting
- boolean hasPermission(@NonNull final PackageInfo app, @NonNull final String permission) {
- if (app.requestedPermissions == null || app.requestedPermissionsFlags == null) {
- return false;
- }
- final int index = ArrayUtils.indexOf(app.requestedPermissions, permission);
- if (index < 0 || index >= app.requestedPermissionsFlags.length) return false;
- return (app.requestedPermissionsFlags[index] & REQUESTED_PERMISSION_GRANTED) != 0;
+ boolean hasPermission(@NonNull final String permission, final int uid) {
+ return mDeps.uidPermission(permission, uid) == PackageManager.PERMISSION_GRANTED;
}
@VisibleForTesting
- boolean hasNetworkPermission(@NonNull final PackageInfo app) {
- return hasPermission(app, CHANGE_NETWORK_STATE);
- }
-
- @VisibleForTesting
- boolean hasRestrictedNetworkPermission(@NonNull final PackageInfo app) {
- // TODO : remove this check in the future(b/31479477). All apps should just
+ boolean hasRestrictedNetworkPermission(@Nullable final ApplicationInfo appInfo) {
+ if (appInfo == null) return false;
+ // TODO : remove this check in the future(b/162295056). All apps should just
// request the appropriate permission for their use case since android Q.
- if (app.applicationInfo != null) {
- // Backward compatibility for b/114245686, on devices that launched before Q daemons
- // and apps running as the system UID are exempted from this check.
- if (app.applicationInfo.uid == SYSTEM_UID && mDeps.getDeviceFirstSdkInt() < VERSION_Q) {
- return true;
- }
-
- if (app.applicationInfo.targetSdkVersion < VERSION_Q
- && isVendorApp(app.applicationInfo)) {
- return true;
- }
+ if ((appInfo.targetSdkVersion < VERSION_Q && isVendorApp(appInfo))
+ // Backward compatibility for b/114245686, on devices that launched before Q daemons
+ // and apps running as the system UID are exempted from this check.
+ || (appInfo.uid == SYSTEM_UID && mDeps.getDeviceFirstSdkInt() < VERSION_Q)) {
+ return true;
}
- return hasPermission(app, PERMISSION_MAINLINE_NETWORK_STACK)
- || hasPermission(app, NETWORK_STACK)
- || hasPermission(app, CONNECTIVITY_USE_RESTRICTED_NETWORKS);
+ return hasPermission(PERMISSION_MAINLINE_NETWORK_STACK, appInfo.uid)
+ || hasPermission(NETWORK_STACK, appInfo.uid)
+ || hasPermission(CONNECTIVITY_USE_RESTRICTED_NETWORKS, appInfo.uid);
}
/** Returns whether the given uid has using background network permission. */
public synchronized boolean hasUseBackgroundNetworksPermission(final int uid) {
// Apps with any of the CHANGE_NETWORK_STATE, NETWORK_STACK, CONNECTIVITY_INTERNAL or
// CONNECTIVITY_USE_RESTRICTED_NETWORKS permission has the permission to use background
- // networks. mApps contains the result of checks for both hasNetworkPermission and
- // hasRestrictedNetworkPermission. If uid is in the mApps list that means uid has one of
+ // networks. mApps contains the result of checks for both CHANGE_NETWORK_STATE permission
+ // and hasRestrictedNetworkPermission. If uid is in the mApps list that means uid has one of
// permissions at least.
return mApps.containsKey(uid);
}
@@ -273,11 +271,11 @@ public class PermissionMonitor implements PackageManagerInternal.PackageListObse
}
try {
if (add) {
- mNetd.networkSetPermissionForUser(INetd.PERMISSION_NETWORK, toIntArray(network));
- mNetd.networkSetPermissionForUser(INetd.PERMISSION_SYSTEM, toIntArray(system));
+ mNetd.networkSetPermissionForUser(PERMISSION_NETWORK, convertToIntArray(network));
+ mNetd.networkSetPermissionForUser(PERMISSION_SYSTEM, convertToIntArray(system));
} else {
- mNetd.networkClearPermissionForUser(toIntArray(network));
- mNetd.networkClearPermissionForUser(toIntArray(system));
+ mNetd.networkClearPermissionForUser(convertToIntArray(network));
+ mNetd.networkClearPermissionForUser(convertToIntArray(system));
}
} catch (RemoteException e) {
loge("Exception when updating permissions: " + e);
@@ -323,14 +321,15 @@ public class PermissionMonitor implements PackageManagerInternal.PackageListObse
}
@VisibleForTesting
- protected Boolean highestPermissionForUid(Boolean currentPermission, String name) {
+ protected Boolean highestPermissionForUid(Boolean currentPermission, String name, int uid) {
if (currentPermission == SYSTEM) {
return currentPermission;
}
try {
final PackageInfo app = mPackageManager.getPackageInfo(name, GET_PERMISSIONS);
- final boolean isNetwork = hasNetworkPermission(app);
- final boolean hasRestrictedPermission = hasRestrictedNetworkPermission(app);
+ final boolean isNetwork = hasPermission(CHANGE_NETWORK_STATE, uid);
+ final boolean hasRestrictedPermission =
+ hasRestrictedNetworkPermission(app.applicationInfo);
if (isNetwork || hasRestrictedPermission) {
currentPermission = hasRestrictedPermission;
}
@@ -342,23 +341,14 @@ public class PermissionMonitor implements PackageManagerInternal.PackageListObse
}
private int getPermissionForUid(final int uid) {
- int permission = INetd.PERMISSION_NONE;
// Check all the packages for this UID. The UID has the permission if any of the
// packages in it has the permission.
final String[] packages = mPackageManager.getPackagesForUid(uid);
- if (packages != null && packages.length > 0) {
- for (String name : packages) {
- final PackageInfo app = getPackageInfo(name);
- if (app != null && app.requestedPermissions != null) {
- permission |= getNetdPermissionMask(app.requestedPermissions,
- app.requestedPermissionsFlags);
- }
- }
- } else {
+ if (packages == null || packages.length <= 0) {
// The last package of this uid is removed from device. Clean the package up.
- permission = INetd.PERMISSION_UNINSTALLED;
+ return PERMISSION_UNINSTALLED;
}
- return permission;
+ return getNetdPermissionMask(uid);
}
/**
@@ -375,7 +365,7 @@ public class PermissionMonitor implements PackageManagerInternal.PackageListObse
// If multiple packages share a UID (cf: android:sharedUserId) and ask for different
// permissions, don't downgrade (i.e., if it's already SYSTEM, leave it as is).
- final Boolean permission = highestPermissionForUid(mApps.get(uid), packageName);
+ final Boolean permission = highestPermissionForUid(mApps.get(uid), packageName, uid);
if (permission != mApps.get(uid)) {
mApps.put(uid, permission);
@@ -431,7 +421,7 @@ public class PermissionMonitor implements PackageManagerInternal.PackageListObse
String[] packages = mPackageManager.getPackagesForUid(uid);
if (packages != null && packages.length > 0) {
for (String name : packages) {
- permission = highestPermissionForUid(permission, name);
+ permission = highestPermissionForUid(permission, name, uid);
if (permission == SYSTEM) {
// An app with this UID still has the SYSTEM permission.
// Therefore, this UID must already have the SYSTEM permission.
@@ -467,19 +457,13 @@ public class PermissionMonitor implements PackageManagerInternal.PackageListObse
sendPackagePermissionsForUid(uid, getPermissionForUid(uid));
}
- private static int getNetdPermissionMask(String[] requestedPermissions,
- int[] requestedPermissionsFlags) {
- int permissions = 0;
- if (requestedPermissions == null || requestedPermissionsFlags == null) return permissions;
- for (int i = 0; i < requestedPermissions.length; i++) {
- if (requestedPermissions[i].equals(INTERNET)
- && ((requestedPermissionsFlags[i] & REQUESTED_PERMISSION_GRANTED) != 0)) {
- permissions |= INetd.PERMISSION_INTERNET;
- }
- if (requestedPermissions[i].equals(UPDATE_DEVICE_STATS)
- && ((requestedPermissionsFlags[i] & REQUESTED_PERMISSION_GRANTED) != 0)) {
- permissions |= INetd.PERMISSION_UPDATE_DEVICE_STATS;
- }
+ private int getNetdPermissionMask(final int uid) {
+ int permissions = PERMISSION_NONE;
+ if (hasPermission(INTERNET, uid)) {
+ permissions |= PERMISSION_INTERNET;
+ }
+ if (hasPermission(UPDATE_DEVICE_STATS, uid)) {
+ permissions |= PERMISSION_UPDATE_DEVICE_STATS;
}
return permissions;
}
@@ -648,19 +632,19 @@ public class PermissionMonitor implements PackageManagerInternal.PackageListObse
for (int i = 0; i < netdPermissionsAppIds.size(); i++) {
int permissions = netdPermissionsAppIds.valueAt(i);
switch(permissions) {
- case (INetd.PERMISSION_INTERNET | INetd.PERMISSION_UPDATE_DEVICE_STATS):
+ case (PERMISSION_INTERNET | PERMISSION_UPDATE_DEVICE_STATS):
allPermissionAppIds.add(netdPermissionsAppIds.keyAt(i));
break;
- case INetd.PERMISSION_INTERNET:
+ case PERMISSION_INTERNET:
internetPermissionAppIds.add(netdPermissionsAppIds.keyAt(i));
break;
- case INetd.PERMISSION_UPDATE_DEVICE_STATS:
+ case PERMISSION_UPDATE_DEVICE_STATS:
updateStatsPermissionAppIds.add(netdPermissionsAppIds.keyAt(i));
break;
- case INetd.PERMISSION_NONE:
+ case PERMISSION_NONE:
noPermissionAppIds.add(netdPermissionsAppIds.keyAt(i));
break;
- case INetd.PERMISSION_UNINSTALLED:
+ case PERMISSION_UNINSTALLED:
uninstalledAppIds.add(netdPermissionsAppIds.keyAt(i));
default:
Log.e(TAG, "unknown permission type: " + permissions + "for uid: "
@@ -671,24 +655,24 @@ public class PermissionMonitor implements PackageManagerInternal.PackageListObse
// TODO: add a lock inside netd to protect IPC trafficSetNetPermForUids()
if (allPermissionAppIds.size() != 0) {
mNetd.trafficSetNetPermForUids(
- INetd.PERMISSION_INTERNET | INetd.PERMISSION_UPDATE_DEVICE_STATS,
- ArrayUtils.convertToIntArray(allPermissionAppIds));
+ PERMISSION_INTERNET | PERMISSION_UPDATE_DEVICE_STATS,
+ convertToIntArray(allPermissionAppIds));
}
if (internetPermissionAppIds.size() != 0) {
- mNetd.trafficSetNetPermForUids(INetd.PERMISSION_INTERNET,
- ArrayUtils.convertToIntArray(internetPermissionAppIds));
+ mNetd.trafficSetNetPermForUids(PERMISSION_INTERNET,
+ convertToIntArray(internetPermissionAppIds));
}
if (updateStatsPermissionAppIds.size() != 0) {
- mNetd.trafficSetNetPermForUids(INetd.PERMISSION_UPDATE_DEVICE_STATS,
- ArrayUtils.convertToIntArray(updateStatsPermissionAppIds));
+ mNetd.trafficSetNetPermForUids(PERMISSION_UPDATE_DEVICE_STATS,
+ convertToIntArray(updateStatsPermissionAppIds));
}
if (noPermissionAppIds.size() != 0) {
- mNetd.trafficSetNetPermForUids(INetd.PERMISSION_NONE,
- ArrayUtils.convertToIntArray(noPermissionAppIds));
+ mNetd.trafficSetNetPermForUids(PERMISSION_NONE,
+ convertToIntArray(noPermissionAppIds));
}
if (uninstalledAppIds.size() != 0) {
- mNetd.trafficSetNetPermForUids(INetd.PERMISSION_UNINSTALLED,
- ArrayUtils.convertToIntArray(uninstalledAppIds));
+ mNetd.trafficSetNetPermForUids(PERMISSION_UNINSTALLED,
+ convertToIntArray(uninstalledAppIds));
}
} catch (RemoteException e) {
Log.e(TAG, "Pass appId list of special permission failed." + e);
diff --git a/services/core/java/com/android/server/display/ColorFade.java b/services/core/java/com/android/server/display/ColorFade.java
index ec2b0c0a6830..ad3cd67ad65b 100644
--- a/services/core/java/com/android/server/display/ColorFade.java
+++ b/services/core/java/com/android/server/display/ColorFade.java
@@ -491,7 +491,14 @@ final class ColorFade {
mIsWideColor = SurfaceControl.getActiveColorMode(token)
== Display.COLOR_MODE_DISPLAY_P3;
- SurfaceControl.screenshot(token, s);
+ SurfaceControl.ScreenshotHardwareBuffer screenshotBuffer =
+ mDisplayManagerInternal.systemScreenshot(mDisplayId);
+ s.attachAndQueueBufferWithColorSpace(screenshotBuffer.getHardwareBuffer(),
+ screenshotBuffer.getColorSpace());
+
+ if (screenshotBuffer.containsSecureLayers()) {
+ mTransaction.setSecure(mSurfaceControl, true).apply();
+ }
st.updateTexImage();
st.getTransformMatrix(mTexMatrix);
} finally {
@@ -586,7 +593,6 @@ final class ColorFade {
}
if (mSurfaceControl == null) {
- Transaction t = new Transaction();
try {
final SurfaceControl.Builder builder = new SurfaceControl.Builder(mSurfaceSession)
.setName("ColorFade")
@@ -602,15 +608,16 @@ final class ColorFade {
return false;
}
- t.setLayerStack(mSurfaceControl, mDisplayLayerStack);
- t.setWindowCrop(mSurfaceControl, mDisplayWidth, mDisplayHeight);
+ mTransaction.setLayerStack(mSurfaceControl, mDisplayLayerStack);
+ mTransaction.setWindowCrop(mSurfaceControl, mDisplayWidth, mDisplayHeight);
+ mSurfaceLayout = new NaturalSurfaceLayout(mDisplayManagerInternal,
+ mDisplayId, mSurfaceControl);
+ mSurfaceLayout.onDisplayTransaction(mTransaction);
+ mTransaction.apply();
+
mSurface = new Surface();
mSurface.copyFrom(mSurfaceControl);
- mSurfaceLayout = new NaturalSurfaceLayout(mDisplayManagerInternal,
- mDisplayId, mSurfaceControl);
- mSurfaceLayout.onDisplayTransaction(t);
- t.apply();
}
return true;
}
@@ -652,7 +659,7 @@ final class ColorFade {
if (mSurfaceControl != null) {
mSurfaceLayout.dispose();
mSurfaceLayout = null;
- new Transaction().remove(mSurfaceControl).apply();
+ mTransaction.remove(mSurfaceControl).apply();
mSurface.release();
mSurfaceControl = null;
mSurfaceVisible = false;
diff --git a/services/core/java/com/android/server/display/color/ColorDisplayService.java b/services/core/java/com/android/server/display/color/ColorDisplayService.java
index 95a98f1e9494..fa4ba38e45c0 100644
--- a/services/core/java/com/android/server/display/color/ColorDisplayService.java
+++ b/services/core/java/com/android/server/display/color/ColorDisplayService.java
@@ -58,6 +58,7 @@ import android.os.Binder;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
+import android.os.ParcelFileDescriptor;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.provider.Settings.Secure;
@@ -819,7 +820,13 @@ public final class ColorDisplayService extends SystemService {
return LocalDateTime.MIN;
}
- private boolean setAppSaturationLevelInternal(String callingPackageName,
+ void setSaturationLevelInternal(int saturationLevel) {
+ final Message message = mHandler.obtainMessage(MSG_APPLY_GLOBAL_SATURATION);
+ message.arg1 = saturationLevel;
+ mHandler.sendMessage(message);
+ }
+
+ boolean setAppSaturationLevelInternal(String callingPackageName,
String affectedPackageName, int saturationLevel) {
return mAppSaturationController
.setSaturationLevel(callingPackageName, affectedPackageName, mCurrentUser,
@@ -1509,9 +1516,7 @@ public final class ColorDisplayService extends SystemService {
}
final long token = Binder.clearCallingIdentity();
try {
- final Message message = mHandler.obtainMessage(MSG_APPLY_GLOBAL_SATURATION);
- message.arg1 = level;
- mHandler.sendMessage(message);
+ setSaturationLevelInternal(level);
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -1724,5 +1729,22 @@ public final class ColorDisplayService extends SystemService {
Binder.restoreCallingIdentity(token);
}
}
+
+ @Override
+ public int handleShellCommand(ParcelFileDescriptor in,
+ ParcelFileDescriptor out, ParcelFileDescriptor err, String[] args) {
+ getContext().enforceCallingOrSelfPermission(
+ Manifest.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS,
+ "Permission required to use ADB color transform commands");
+ final long token = Binder.clearCallingIdentity();
+ try {
+ return new ColorDisplayShellCommand(ColorDisplayService.this)
+ .exec(this, in.getFileDescriptor(), out.getFileDescriptor(),
+ err.getFileDescriptor(),
+ args);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
}
}
diff --git a/services/core/java/com/android/server/display/color/ColorDisplayShellCommand.java b/services/core/java/com/android/server/display/color/ColorDisplayShellCommand.java
new file mode 100644
index 000000000000..b4555f851d4d
--- /dev/null
+++ b/services/core/java/com/android/server/display/color/ColorDisplayShellCommand.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.display.color;
+
+import android.content.pm.PackageManagerInternal;
+import android.os.ShellCommand;
+
+import com.android.server.LocalServices;
+
+class ColorDisplayShellCommand extends ShellCommand {
+
+ private static final String USAGE = "usage: cmd color_display SUBCOMMAND [ARGS]\n"
+ + " help\n"
+ + " Shows this message.\n"
+ + " set-saturation LEVEL\n"
+ + " Sets the device saturation to the given LEVEL, 0-100 inclusive.\n"
+ + " set-layer-saturation CALLER_PACKAGE TARGET_PACKAGE LEVEL\n"
+ + " Sets the saturation LEVEL for all layers of the TARGET_PACKAGE, attributed\n"
+ + " to the CALLER_PACKAGE. The lowest LEVEL from any CALLER_PACKAGE is applied.\n";
+
+ private static final int ERROR = -1;
+ private static final int SUCCESS = 0;
+
+ private final ColorDisplayService mService;
+
+ ColorDisplayShellCommand(ColorDisplayService service) {
+ mService = service;
+ }
+
+ @Override
+ public int onCommand(String cmd) {
+ if (cmd == null) {
+ return handleDefaultCommands(cmd);
+ }
+ switch (cmd) {
+ case "set-saturation":
+ return setSaturation();
+ case "set-layer-saturation":
+ return setLayerSaturation();
+ default:
+ return handleDefaultCommands(cmd);
+ }
+ }
+
+ private int setSaturation() {
+ final int level = getLevel();
+ if (level == ERROR) {
+ return ERROR;
+ }
+ mService.setSaturationLevelInternal(level);
+ return SUCCESS;
+ }
+
+ private int setLayerSaturation() {
+ final int level = getLevel();
+ if (level == ERROR) {
+ return ERROR;
+ }
+ final String callerPackageName = getPackageName();
+ if (callerPackageName == null) {
+ getErrPrintWriter().println("Error: CALLER_PACKAGE must be an installed package name");
+ return ERROR;
+ }
+ final String targetPackageName = getPackageName();
+ if (targetPackageName == null) {
+ getErrPrintWriter().println("Error: TARGET_PACKAGE must be an installed package name");
+ return ERROR;
+ }
+ mService.setAppSaturationLevelInternal(callerPackageName, targetPackageName, level);
+ return SUCCESS;
+ }
+
+ private String getPackageName() {
+ final String packageNameArg = getNextArg();
+ return LocalServices.getService(PackageManagerInternal.class).getPackage(packageNameArg)
+ == null
+ ? null : packageNameArg;
+ }
+
+ private int getLevel() {
+ final String levelArg = getNextArg();
+ if (levelArg == null) {
+ getErrPrintWriter().println("Error: Required argument LEVEL is unspecified");
+ return ERROR;
+ }
+ final int level;
+ try {
+ level = Integer.parseInt(levelArg);
+ } catch (NumberFormatException e) {
+ getErrPrintWriter().println("Error: LEVEL argument is not an integer");
+ return ERROR;
+ }
+ if (level < 0 || level > 100) {
+ getErrPrintWriter()
+ .println("Error: LEVEL argument must be an integer between 0 and 100");
+ return ERROR;
+ }
+ return level;
+ }
+
+ @Override
+ public void onHelp() {
+ getOutPrintWriter().print(USAGE);
+ }
+}
diff --git a/services/core/java/com/android/server/gpu/GpuService.java b/services/core/java/com/android/server/gpu/GpuService.java
index 8a3c963f4805..c0617ca95f9f 100644
--- a/services/core/java/com/android/server/gpu/GpuService.java
+++ b/services/core/java/com/android/server/gpu/GpuService.java
@@ -29,8 +29,6 @@ import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.database.ContentObserver;
-import android.gamedriver.GameDriverProto.Blacklist;
-import android.gamedriver.GameDriverProto.Blacklists;
import android.net.Uri;
import android.os.Build;
import android.os.Handler;
@@ -40,6 +38,8 @@ import android.provider.DeviceConfig;
import android.provider.DeviceConfig.Properties;
import android.provider.Settings;
import android.text.TextUtils;
+import android.updatabledriver.UpdatableDriverProto.Denylist;
+import android.updatabledriver.UpdatableDriverProto.Denylists;
import android.util.Base64;
import android.util.Slog;
@@ -65,7 +65,7 @@ public class GpuService extends SystemService {
private static final String PROD_DRIVER_PROPERTY = "ro.gfx.driver.0";
private static final String DEV_DRIVER_PROPERTY = "ro.gfx.driver.1";
- private static final String GAME_DRIVER_WHITELIST_FILENAME = "whitelist.txt";
+ private static final String GAME_DRIVER_ALLOWLIST_FILENAME = "allowlist.txt";
private static final int BASE64_FLAGS = Base64.NO_PADDING | Base64.NO_WRAP;
private final Context mContext;
@@ -81,7 +81,7 @@ public class GpuService extends SystemService {
private SettingsObserver mSettingsObserver;
private DeviceConfigListener mDeviceConfigListener;
@GuardedBy("mLock")
- private Blacklists mBlacklists;
+ private Denylists mDenylists;
public GpuService(Context context) {
super(context);
@@ -118,19 +118,19 @@ public class GpuService extends SystemService {
mSettingsObserver = new SettingsObserver();
mDeviceConfigListener = new DeviceConfigListener();
fetchGameDriverPackageProperties();
- processBlacklists();
- setBlacklist();
+ processDenylists();
+ setDenylist();
fetchDeveloperDriverPackageProperties();
}
}
private final class SettingsObserver extends ContentObserver {
- private final Uri mGameDriverBlackUri =
- Settings.Global.getUriFor(Settings.Global.GAME_DRIVER_BLACKLISTS);
+ private final Uri mGameDriverDenylistsUri =
+ Settings.Global.getUriFor(Settings.Global.GAME_DRIVER_DENYLISTS);
SettingsObserver() {
super(new Handler());
- mContentResolver.registerContentObserver(mGameDriverBlackUri, false, this,
+ mContentResolver.registerContentObserver(mGameDriverDenylistsUri, false, this,
UserHandle.USER_ALL);
}
@@ -140,9 +140,9 @@ public class GpuService extends SystemService {
return;
}
- if (mGameDriverBlackUri.equals(uri)) {
- processBlacklists();
- setBlacklist();
+ if (mGameDriverDenylistsUri.equals(uri)) {
+ processDenylists();
+ setDenylist();
}
}
}
@@ -157,10 +157,10 @@ public class GpuService extends SystemService {
@Override
public void onPropertiesChanged(Properties properties) {
synchronized (mDeviceConfigLock) {
- if (properties.getKeyset().contains(Settings.Global.GAME_DRIVER_BLACKLISTS)) {
- parseBlacklists(
- properties.getString(Settings.Global.GAME_DRIVER_BLACKLISTS, ""));
- setBlacklist();
+ if (properties.getKeyset().contains(Settings.Global.GAME_DRIVER_DENYLISTS)) {
+ parseDenylists(
+ properties.getString(Settings.Global.GAME_DRIVER_DENYLISTS, ""));
+ setDenylist();
}
}
}
@@ -187,7 +187,7 @@ public class GpuService extends SystemService {
case ACTION_PACKAGE_REMOVED:
if (isProdDriver) {
fetchGameDriverPackageProperties();
- setBlacklist();
+ setDenylist();
} else if (isDevDriver) {
fetchDeveloperDriverPackageProperties();
}
@@ -239,17 +239,17 @@ public class GpuService extends SystemService {
return;
}
- // Reset the whitelist.
+ // Reset the allowlist.
Settings.Global.putString(mContentResolver,
- Settings.Global.GAME_DRIVER_WHITELIST, "");
+ Settings.Global.GAME_DRIVER_ALLOWLIST, "");
mGameDriverVersionCode = driverInfo.longVersionCode;
try {
final Context driverContext = mContext.createPackageContext(mProdDriverPackageName,
Context.CONTEXT_RESTRICTED);
- assetToSettingsGlobal(mContext, driverContext, GAME_DRIVER_WHITELIST_FILENAME,
- Settings.Global.GAME_DRIVER_WHITELIST, ",");
+ assetToSettingsGlobal(mContext, driverContext, GAME_DRIVER_ALLOWLIST_FILENAME,
+ Settings.Global.GAME_DRIVER_ALLOWLIST, ",");
} catch (PackageManager.NameNotFoundException e) {
if (DEBUG) {
Slog.w(TAG, "driver package '" + mProdDriverPackageName + "' not installed");
@@ -257,48 +257,48 @@ public class GpuService extends SystemService {
}
}
- private void processBlacklists() {
+ private void processDenylists() {
String base64String = DeviceConfig.getProperty(DeviceConfig.NAMESPACE_GAME_DRIVER,
- Settings.Global.GAME_DRIVER_BLACKLISTS);
+ Settings.Global.GAME_DRIVER_DENYLISTS);
if (base64String == null) {
base64String =
Settings.Global.getString(mContentResolver,
- Settings.Global.GAME_DRIVER_BLACKLISTS);
+ Settings.Global.GAME_DRIVER_DENYLISTS);
}
- parseBlacklists(base64String != null ? base64String : "");
+ parseDenylists(base64String != null ? base64String : "");
}
- private void parseBlacklists(String base64String) {
+ private void parseDenylists(String base64String) {
synchronized (mLock) {
- // Reset all blacklists
- mBlacklists = null;
+ // Reset all denylists
+ mDenylists = null;
try {
- mBlacklists = Blacklists.parseFrom(Base64.decode(base64String, BASE64_FLAGS));
+ mDenylists = Denylists.parseFrom(Base64.decode(base64String, BASE64_FLAGS));
} catch (IllegalArgumentException e) {
if (DEBUG) {
- Slog.w(TAG, "Can't parse blacklist, skip and continue...");
+ Slog.w(TAG, "Can't parse denylist, skip and continue...");
}
} catch (InvalidProtocolBufferException e) {
if (DEBUG) {
- Slog.w(TAG, "Can't parse blacklist, skip and continue...");
+ Slog.w(TAG, "Can't parse denylist, skip and continue...");
}
}
}
}
- private void setBlacklist() {
+ private void setDenylist() {
Settings.Global.putString(mContentResolver,
- Settings.Global.GAME_DRIVER_BLACKLIST, "");
+ Settings.Global.GAME_DRIVER_DENYLIST, "");
synchronized (mLock) {
- if (mBlacklists == null) {
+ if (mDenylists == null) {
return;
}
- List<Blacklist> blacklists = mBlacklists.getBlacklistsList();
- for (Blacklist blacklist : blacklists) {
- if (blacklist.getVersionCode() == mGameDriverVersionCode) {
+ List<Denylist> denylists = mDenylists.getDenylistsList();
+ for (Denylist denylist : denylists) {
+ if (denylist.getVersionCode() == mGameDriverVersionCode) {
Settings.Global.putString(mContentResolver,
- Settings.Global.GAME_DRIVER_BLACKLIST,
- String.join(",", blacklist.getPackageNamesList()));
+ Settings.Global.GAME_DRIVER_DENYLIST,
+ String.join(",", denylist.getPackageNamesList()));
return;
}
}
diff --git a/services/core/java/com/android/server/hdmi/ActiveSourceAction.java b/services/core/java/com/android/server/hdmi/ActiveSourceAction.java
index 3c4dae0f6467..c90f297e1485 100644
--- a/services/core/java/com/android/server/hdmi/ActiveSourceAction.java
+++ b/services/core/java/com/android/server/hdmi/ActiveSourceAction.java
@@ -39,15 +39,19 @@ public class ActiveSourceAction extends HdmiCecFeatureAction {
@Override
boolean start() {
mState = STATE_STARTED;
- sendCommand(HdmiCecMessageBuilder.buildActiveSource(getSourceAddress(),
- source().mService.getPhysicalAddress()));
+ int logicalAddress = getSourceAddress();
+ int physicalAddress = getSourcePath();
+
+ sendCommand(HdmiCecMessageBuilder.buildActiveSource(logicalAddress, physicalAddress));
if (source().getType() == HdmiDeviceInfo.DEVICE_PLAYBACK) {
// Reports menu-status active to receive <User Control Pressed>.
sendCommand(
- HdmiCecMessageBuilder.buildReportMenuStatus(getSourceAddress(), mDestination,
+ HdmiCecMessageBuilder.buildReportMenuStatus(logicalAddress, mDestination,
Constants.MENU_STATE_ACTIVATED));
}
+
+ source().setActiveSource(logicalAddress, physicalAddress);
mState = STATE_FINISHED;
finish();
return true;
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
index 64d70d6601f6..596c1eccfabe 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
@@ -85,6 +85,14 @@ public class HdmiCecLocalDevicePlayback extends HdmiCecLocalDeviceSource {
// The option is false by default. Update settings db as well to have the right
// initial setting on UI.
mService.writeBooleanSetting(Global.HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED, mAutoTvOff);
+
+ // Initialize settings database with System Property value. This will be the initial
+ // setting on the UI. If no System Property is set, the option is set to to_tv by default.
+ mService.writeStringSetting(Global.HDMI_CONTROL_SEND_STANDBY_ON_SLEEP,
+ mService.readStringSetting(Global.HDMI_CONTROL_SEND_STANDBY_ON_SLEEP,
+ HdmiProperties.send_standby_on_sleep().orElse(
+ HdmiProperties.send_standby_on_sleep_values.TO_TV).name()
+ .toLowerCase()));
}
@Override
@@ -188,8 +196,26 @@ public class HdmiCecLocalDevicePlayback extends HdmiCecLocalDeviceSource {
}
switch (standbyAction) {
case HdmiControlService.STANDBY_SCREEN_OFF:
- mService.sendCecCommand(
- HdmiCecMessageBuilder.buildStandby(mAddress, Constants.ADDR_TV));
+ // Get latest setting value
+ @HdmiControlManager.StandbyBehavior
+ String sendStandbyOnSleep = mService.readStringSetting(
+ Global.HDMI_CONTROL_SEND_STANDBY_ON_SLEEP,
+ HdmiProperties.send_standby_on_sleep().orElse(
+ HdmiProperties.send_standby_on_sleep_values.TO_TV).name()
+ .toLowerCase());
+ switch (sendStandbyOnSleep) {
+ case HdmiControlManager.SEND_STANDBY_ON_SLEEP_TO_TV:
+ mService.sendCecCommand(
+ HdmiCecMessageBuilder.buildStandby(mAddress, Constants.ADDR_TV));
+ break;
+ case HdmiControlManager.SEND_STANDBY_ON_SLEEP_BROADCAST:
+ mService.sendCecCommand(
+ HdmiCecMessageBuilder.buildStandby(mAddress,
+ Constants.ADDR_BROADCAST));
+ break;
+ case HdmiControlManager.SEND_STANDBY_ON_SLEEP_NONE:
+ break;
+ }
break;
case HdmiControlService.STANDBY_SHUTDOWN:
// ACTION_SHUTDOWN is taken as a signal to power off all the devices.
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index 30d7d5494a7e..0576e91b79eb 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -772,6 +772,11 @@ public class HdmiControlService extends SystemService {
return content;
}
+ void writeStringSetting(String key, String value) {
+ ContentResolver cr = getContext().getContentResolver();
+ Global.putString(cr, key, value);
+ }
+
private void initializeCec(int initiatedBy) {
mAddressAllocated = false;
mCecController.setOption(OptionKey.SYSTEM_CEC_CONTROL, true);
@@ -2290,7 +2295,7 @@ public class HdmiControlService extends SystemService {
pw.println("mHdmiControlEnabled: " + mHdmiControlEnabled);
pw.println("mMhlInputChangeEnabled: " + mMhlInputChangeEnabled);
pw.println("mSystemAudioActivated: " + isSystemAudioActivated());
- pw.println("mHdmiCecVolumeControlEnabled " + mHdmiCecVolumeControlEnabled);
+ pw.println("mHdmiCecVolumeControlEnabled: " + mHdmiCecVolumeControlEnabled);
pw.decreaseIndent();
pw.println("mMhlController: ");
@@ -3244,7 +3249,6 @@ public class HdmiControlService extends SystemService {
playback.setIsActiveSource(true);
playback.wakeUpIfActiveSource();
playback.maySendActiveSource(source);
- setActiveSource(playback.mAddress, physicalAddress);
}
if (deviceType == HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM) {
@@ -3255,7 +3259,6 @@ public class HdmiControlService extends SystemService {
audioSystem.setIsActiveSource(true);
audioSystem.wakeUpIfActiveSource();
audioSystem.maySendActiveSource(source);
- setActiveSource(audioSystem.mAddress, physicalAddress);
}
}
}
@@ -3278,13 +3281,11 @@ public class HdmiControlService extends SystemService {
if (audioSystem != null) {
audioSystem.setIsActiveSource(false);
}
- setActiveSource(playback.mAddress, physicalAddress);
} else {
if (audioSystem != null) {
audioSystem.setIsActiveSource(true);
audioSystem.wakeUpIfActiveSource();
audioSystem.maySendActiveSource(sourceAddress);
- setActiveSource(audioSystem.mAddress, physicalAddress);
}
}
}
diff --git a/services/core/java/com/android/server/location/HardwareActivityRecognitionProxy.java b/services/core/java/com/android/server/location/HardwareActivityRecognitionProxy.java
index e29471bdfd6b..eed1aac79166 100644
--- a/services/core/java/com/android/server/location/HardwareActivityRecognitionProxy.java
+++ b/services/core/java/com/android/server/location/HardwareActivityRecognitionProxy.java
@@ -17,6 +17,7 @@
package com.android.server.location;
import android.annotation.Nullable;
+import android.content.ComponentName;
import android.content.Context;
import android.hardware.location.ActivityRecognitionHardware;
import android.hardware.location.IActivityRecognitionHardwareClient;
@@ -77,7 +78,7 @@ public class HardwareActivityRecognitionProxy {
return mServiceWatcher.register();
}
- private void onBind(IBinder binder) throws RemoteException {
+ private void onBind(IBinder binder, ComponentName service) throws RemoteException {
String descriptor = binder.getInterfaceDescriptor();
if (IActivityRecognitionHardwareWatcher.class.getCanonicalName().equals(descriptor)) {
diff --git a/services/core/java/com/android/server/location/LocationManagerService.java b/services/core/java/com/android/server/location/LocationManagerService.java
index d933c109b27d..d3558f1458b8 100644
--- a/services/core/java/com/android/server/location/LocationManagerService.java
+++ b/services/core/java/com/android/server/location/LocationManagerService.java
@@ -39,6 +39,7 @@ import static android.os.PowerManager.locationPowerSaveModeToString;
import static com.android.server.location.LocationPermissions.PERMISSION_COARSE;
import static com.android.server.location.LocationPermissions.PERMISSION_FINE;
+import static com.android.server.location.LocationPermissions.PERMISSION_NONE;
import static java.util.concurrent.TimeUnit.NANOSECONDS;
@@ -1248,9 +1249,11 @@ public class LocationManagerService extends ILocationManager.Stub {
}
}
} else {
- if (!allowMonitoring || !mAppOpsHelper.checkOpNoThrow(LocationPermissions.asAppOp(
- LocationPermissions.getPermissionLevel(mContext, mCallerIdentity.getUid(),
- mCallerIdentity.getPid())), mCallerIdentity)) {
+ int permissionLevel = LocationPermissions.getPermissionLevel(mContext,
+ mCallerIdentity.getUid(), mCallerIdentity.getPid());
+ if (!allowMonitoring || permissionLevel == PERMISSION_NONE
+ || !mAppOpsHelper.checkOpNoThrow(
+ LocationPermissions.asAppOp(permissionLevel), mCallerIdentity)) {
if (!highPower) {
mAppOpsHelper.finishOp(OP_MONITOR_LOCATION, mCallerIdentity);
} else {
diff --git a/services/core/java/com/android/server/location/LocationProviderProxy.java b/services/core/java/com/android/server/location/LocationProviderProxy.java
index 2bcee2faa813..d778d242f571 100644
--- a/services/core/java/com/android/server/location/LocationProviderProxy.java
+++ b/services/core/java/com/android/server/location/LocationProviderProxy.java
@@ -19,6 +19,7 @@ package com.android.server.location;
import static com.android.internal.util.ConcurrentUtils.DIRECT_EXECUTOR;
import android.annotation.Nullable;
+import android.content.ComponentName;
import android.content.Context;
import android.location.Location;
import android.location.util.identity.CallerIdentity;
@@ -32,10 +33,12 @@ import com.android.internal.location.ILocationProvider;
import com.android.internal.location.ILocationProviderManager;
import com.android.internal.location.ProviderProperties;
import com.android.internal.location.ProviderRequest;
+import com.android.internal.util.ArrayUtils;
import com.android.server.ServiceWatcher;
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.util.Objects;
/**
* Proxy for ILocationProvider implementations.
@@ -65,6 +68,8 @@ public class LocationProviderProxy extends AbstractLocationProvider {
@GuardedBy("mLock")
Proxy mProxy;
+ @GuardedBy("mLock")
+ @Nullable ComponentName mService;
private volatile ProviderRequest mRequest;
@@ -86,11 +91,12 @@ public class LocationProviderProxy extends AbstractLocationProvider {
return mServiceWatcher.register();
}
- private void onBind(IBinder binder) throws RemoteException {
+ private void onBind(IBinder binder, ComponentName service) throws RemoteException {
ILocationProvider provider = ILocationProvider.Stub.asInterface(binder);
synchronized (mLock) {
mProxy = new Proxy();
+ mService = service;
provider.setLocationProviderManager(mProxy);
ProviderRequest request = mRequest;
@@ -103,6 +109,7 @@ public class LocationProviderProxy extends AbstractLocationProvider {
private void onUnbind() {
synchronized (mLock) {
mProxy = null;
+ mService = null;
setState(State.EMPTY_STATE);
}
}
@@ -111,16 +118,16 @@ public class LocationProviderProxy extends AbstractLocationProvider {
public void onSetRequest(ProviderRequest request) {
mRequest = request;
mServiceWatcher.runOnBinder(binder -> {
- ILocationProvider service = ILocationProvider.Stub.asInterface(binder);
- service.setRequest(request, request.workSource);
+ ILocationProvider provider = ILocationProvider.Stub.asInterface(binder);
+ provider.setRequest(request, request.workSource);
});
}
@Override
public void onExtraCommand(int uid, int pid, String command, Bundle extras) {
mServiceWatcher.runOnBinder(binder -> {
- ILocationProvider service = ILocationProvider.Stub.asInterface(binder);
- service.sendExtraCommand(command, extras);
+ ILocationProvider provider = ILocationProvider.Stub.asInterface(binder);
+ provider.sendExtraCommand(command, extras);
});
}
@@ -129,12 +136,14 @@ public class LocationProviderProxy extends AbstractLocationProvider {
mServiceWatcher.dump(fd, pw, args);
}
- private static String guessPackageName(Context context, int uid) {
+ private static String guessPackageName(Context context, int uid, String packageName) {
String[] packageNames = context.getPackageManager().getPackagesForUid(uid);
if (packageNames == null || packageNames.length == 0) {
// illegal state exception will propagate back through binders
throw new IllegalStateException(
"location provider from uid " + uid + " has no package information");
+ } else if (ArrayUtils.contains(packageNames, packageName)) {
+ return packageName;
} else {
return packageNames[0];
}
@@ -154,7 +163,8 @@ public class LocationProviderProxy extends AbstractLocationProvider {
CallerIdentity identity;
if (packageName == null) {
- packageName = guessPackageName(mContext, Binder.getCallingUid());
+ packageName = guessPackageName(mContext, Binder.getCallingUid(),
+ Objects.requireNonNull(mService).getPackageName());
// unsafe is ok since the package is coming direct from the package manager here
identity = CallerIdentity.fromBinderUnsafe(packageName, attributionTag);
} else {
@@ -175,7 +185,8 @@ public class LocationProviderProxy extends AbstractLocationProvider {
// if no identity is set yet, set it now
if (getIdentity() == null) {
- String packageName = guessPackageName(mContext, Binder.getCallingUid());
+ String packageName = guessPackageName(mContext, Binder.getCallingUid(),
+ Objects.requireNonNull(mService).getPackageName());
// unsafe is ok since the package is coming direct from the package manager here
setIdentity(CallerIdentity.fromBinderUnsafe(packageName, null));
}
diff --git a/services/core/java/com/android/server/location/geofence/GeofenceProxy.java b/services/core/java/com/android/server/location/geofence/GeofenceProxy.java
index 2218079c7889..686a66bb4d97 100644
--- a/services/core/java/com/android/server/location/geofence/GeofenceProxy.java
+++ b/services/core/java/com/android/server/location/geofence/GeofenceProxy.java
@@ -63,7 +63,7 @@ public final class GeofenceProxy {
private GeofenceProxy(Context context, IGpsGeofenceHardware gpsGeofence) {
mGpsGeofenceHardware = Objects.requireNonNull(gpsGeofence);
mServiceWatcher = new ServiceWatcher(context, SERVICE_ACTION,
- this::updateGeofenceHardware, null,
+ (binder, service) -> updateGeofenceHardware(binder), null,
com.android.internal.R.bool.config_enableGeofenceOverlay,
com.android.internal.R.string.config_geofenceProviderPackageName);
diff --git a/services/core/java/com/android/server/media/MediaButtonReceiverHolder.java b/services/core/java/com/android/server/media/MediaButtonReceiverHolder.java
index 9dae1b44117b..b9997e0c2ec8 100644
--- a/services/core/java/com/android/server/media/MediaButtonReceiverHolder.java
+++ b/services/core/java/com/android/server/media/MediaButtonReceiverHolder.java
@@ -221,8 +221,8 @@ final class MediaButtonReceiverHolder {
context.startActivityAsUser(mediaButtonIntent, userHandle);
break;
case COMPONENT_TYPE_SERVICE:
- context.startForegroundServiceAsUser(mediaButtonIntent,
- userHandle);
+ context.createContextAsUser(userHandle, 0).startForegroundService(
+ mediaButtonIntent);
break;
default:
// Legacy behavior for other cases.
diff --git a/services/core/java/com/android/server/media/MediaResourceMonitorService.java b/services/core/java/com/android/server/media/MediaResourceMonitorService.java
index 6669b8cec143..e5da9b1c178c 100644
--- a/services/core/java/com/android/server/media/MediaResourceMonitorService.java
+++ b/services/core/java/com/android/server/media/MediaResourceMonitorService.java
@@ -25,7 +25,6 @@ import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
import android.util.Log;
-import android.util.Slog;
import com.android.server.SystemService;
@@ -53,7 +52,7 @@ public class MediaResourceMonitorService extends SystemService {
public void notifyResourceGranted(int pid, int type)
throws RemoteException {
if (DEBUG) {
- Slog.d(TAG, "notifyResourceGranted(pid=" + pid + ", type=" + type + ")");
+ Log.d(TAG, "notifyResourceGranted(pid=" + pid + ", type=" + type + ")");
}
final long identity = Binder.clearCallingIdentity();
try {
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index 0eba69ef6348..9f6c18d5ec72 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -26,8 +26,8 @@ import static com.android.server.media.MediaKeyDispatcher.isSingleTapOverridden;
import static com.android.server.media.MediaKeyDispatcher.isTripleTapOverridden;
import android.app.ActivityManager;
-import android.app.INotificationManager;
import android.app.KeyguardManager;
+import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.ActivityNotFoundException;
import android.content.ComponentName;
@@ -68,7 +68,6 @@ import android.os.Process;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.ResultReceiver;
-import android.os.ServiceManager;
import android.os.ShellCallback;
import android.os.UserHandle;
import android.os.UserManager;
@@ -118,7 +117,7 @@ public class MediaSessionService extends SystemService implements Monitor {
private final SessionManagerImpl mSessionManagerImpl;
private final MessageHandler mHandler = new MessageHandler();
private final PowerManager.WakeLock mMediaEventWakeLock;
- private final INotificationManager mNotificationManager;
+ private final NotificationManager mNotificationManager;
private final Object mLock = new Object();
private final HandlerThread mRecordThread = new HandlerThread("SessionRecordThread");
// Keeps the full user id for each user.
@@ -158,10 +157,9 @@ public class MediaSessionService extends SystemService implements Monitor {
super(context);
mContext = context;
mSessionManagerImpl = new SessionManagerImpl();
- PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
+ PowerManager pm = mContext.getSystemService(PowerManager.class);
mMediaEventWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "handleMediaEvent");
- mNotificationManager = INotificationManager.Stub.asInterface(
- ServiceManager.getService(Context.NOTIFICATION_SERVICE));
+ mNotificationManager = mContext.getSystemService(NotificationManager.class);
}
@Override
@@ -507,11 +505,12 @@ public class MediaSessionService extends SystemService implements Monitor {
private void enforceMediaPermissions(ComponentName compName, int pid, int uid,
int resolvedUserId) {
if (hasStatusBarServicePermission(pid, uid)) return;
+ // TODO: Refactor to use hasMediaControlPermission and hasEnabledNotificationListener
if (mContext
.checkPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL, pid, uid)
!= PackageManager.PERMISSION_GRANTED
&& !isEnabledNotificationListener(compName,
- UserHandle.getUserHandleForUid(uid).getIdentifier(), resolvedUserId)) {
+ UserHandle.getUserHandleForUid(uid), resolvedUserId)) {
throw new SecurityException("Missing permission to control media.");
}
}
@@ -547,13 +546,13 @@ public class MediaSessionService extends SystemService implements Monitor {
* they're running as.
*
* @param compName The component that is enabled.
- * @param userId The user id of the caller.
+ * @param userHandle The user handle of the caller.
* @param forUserId The user id they're making the request on behalf of.
* @return True if the component is enabled, false otherwise
*/
- private boolean isEnabledNotificationListener(ComponentName compName, int userId,
+ private boolean isEnabledNotificationListener(ComponentName compName, UserHandle userHandle,
int forUserId) {
- if (userId != forUserId) {
+ if (userHandle.getIdentifier() != forUserId) {
// You may not access another user's content as an enabled listener.
return false;
}
@@ -561,12 +560,8 @@ public class MediaSessionService extends SystemService implements Monitor {
Log.d(TAG, "Checking if enabled notification listener " + compName);
}
if (compName != null) {
- try {
- return mNotificationManager.isNotificationListenerAccessGrantedForUser(
- compName, userId);
- } catch (RemoteException e) {
- Log.w(TAG, "Dead NotificationManager in isEnabledNotificationListener", e);
- }
+ return mNotificationManager.hasEnabledNotificationListener(compName.getPackageName(),
+ userHandle);
}
return false;
}
@@ -1922,8 +1917,8 @@ public class MediaSessionService extends SystemService implements Monitor {
* @param controllerUid uid of the controller app
*/
@Override
- public boolean isTrusted(String controllerPackageName, int controllerPid, int controllerUid)
- throws RemoteException {
+ public boolean isTrusted(String controllerPackageName, int controllerPid,
+ int controllerUid) {
final int uid = Binder.getCallingUid();
final int userId = UserHandle.getUserHandleForUid(uid).getIdentifier();
final long token = Binder.clearCallingIdentity();
@@ -1937,7 +1932,7 @@ public class MediaSessionService extends SystemService implements Monitor {
// Context#getPackageName() for getting package name that matches with the PID/UID,
// but it doesn't tell which package has created the MediaController, so useless.
return hasMediaControlPermission(controllerPid, controllerUid)
- || hasEnabledNotificationListener(userId, controllerPackageName);
+ || hasEnabledNotificationListener(userId, controllerPackageName, uid);
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -2001,28 +1996,20 @@ public class MediaSessionService extends SystemService implements Monitor {
return resolvedUserId;
}
- private boolean hasEnabledNotificationListener(int resolvedUserId, String packageName)
- throws RemoteException {
+ private boolean hasEnabledNotificationListener(int resolvedUserId, String packageName,
+ int uid) {
+ // TODO: revisit this checking code
// You may not access another user's content as an enabled listener.
final int userId = UserHandle.getUserHandleForUid(resolvedUserId).getIdentifier();
if (resolvedUserId != userId) {
return false;
}
-
- // TODO(jaewan): (Post-P) Propose NotificationManager#hasEnabledNotificationListener(
- // String pkgName) to notification team for optimization
- final List<ComponentName> enabledNotificationListeners =
- mNotificationManager.getEnabledNotificationListeners(userId);
- if (enabledNotificationListeners != null) {
- for (int i = 0; i < enabledNotificationListeners.size(); i++) {
- if (TextUtils.equals(packageName,
- enabledNotificationListeners.get(i).getPackageName())) {
- return true;
- }
- }
+ if (mNotificationManager.hasEnabledNotificationListener(packageName,
+ UserHandle.getUserHandleForUid(uid))) {
+ return true;
}
if (DEBUG) {
- Log.d(TAG, packageName + " (uid=" + resolvedUserId + ") doesn't have an enabled "
+ Log.d(TAG, packageName + " (uid=" + uid + ") doesn't have an enabled "
+ "notification listener");
}
return false;
diff --git a/services/core/java/com/android/server/net/NetworkStatsCollection.java b/services/core/java/com/android/server/net/NetworkStatsCollection.java
index 05ab2ae87aa5..342a11b87aa5 100644
--- a/services/core/java/com/android/server/net/NetworkStatsCollection.java
+++ b/services/core/java/com/android/server/net/NetworkStatsCollection.java
@@ -28,6 +28,7 @@ import static android.net.NetworkStats.SET_DEFAULT;
import static android.net.NetworkStats.TAG_NONE;
import static android.net.NetworkStats.UID_ALL;
import static android.net.TrafficStats.UID_REMOVED;
+import static android.net.NetworkUtils.multiplySafeByRational;
import static android.text.format.DateUtils.WEEK_IN_MILLIS;
import static com.android.server.net.NetworkStatsService.TAG;
@@ -185,35 +186,6 @@ public class NetworkStatsCollection implements FileRotator.Reader {
}
}
- /**
- * Safely multiple a value by a rational.
- * <p>
- * Internally it uses integer-based math whenever possible, but switches
- * over to double-based math if values would overflow.
- */
- @VisibleForTesting
- public static long multiplySafe(long value, long num, long den) {
- if (den == 0) den = 1;
- long x = value;
- long y = num;
-
- // Logic shamelessly borrowed from Math.multiplyExact()
- long r = x * y;
- long ax = Math.abs(x);
- long ay = Math.abs(y);
- if (((ax | ay) >>> 31 != 0)) {
- // Some bits greater than 2^31 that might cause overflow
- // Check the result using the divide operator
- // and check for the special case of Long.MIN_VALUE * -1
- if (((y != 0) && (r / y != x)) ||
- (x == Long.MIN_VALUE && y == -1)) {
- // Use double math to avoid overflowing
- return (long) (((double) num / den) * value);
- }
- }
- return r / den;
- }
-
public int[] getRelevantUids(@NetworkStatsAccess.Level int accessLevel) {
return getRelevantUids(accessLevel, Binder.getCallingUid());
}
@@ -311,11 +283,13 @@ public class NetworkStatsCollection implements FileRotator.Reader {
}
final long rawBytes = entry.rxBytes + entry.txBytes;
- final long rawRxBytes = entry.rxBytes;
- final long rawTxBytes = entry.txBytes;
+ final long rawRxBytes = entry.rxBytes == 0 ? 1 : entry.rxBytes;
+ final long rawTxBytes = entry.txBytes == 0 ? 1 : entry.txBytes;
final long targetBytes = augmentPlan.getDataUsageBytes();
- final long targetRxBytes = multiplySafe(targetBytes, rawRxBytes, rawBytes);
- final long targetTxBytes = multiplySafe(targetBytes, rawTxBytes, rawBytes);
+
+ final long targetRxBytes = multiplySafeByRational(targetBytes, rawRxBytes, rawBytes);
+ final long targetTxBytes = multiplySafeByRational(targetBytes, rawTxBytes, rawBytes);
+
// Scale all matching buckets to reach anchor target
final long beforeTotal = combined.getTotalBytes();
@@ -323,8 +297,10 @@ public class NetworkStatsCollection implements FileRotator.Reader {
combined.getValues(i, entry);
if (entry.bucketStart >= augmentStart
&& entry.bucketStart + entry.bucketDuration <= augmentEnd) {
- entry.rxBytes = multiplySafe(targetRxBytes, entry.rxBytes, rawRxBytes);
- entry.txBytes = multiplySafe(targetTxBytes, entry.txBytes, rawTxBytes);
+ entry.rxBytes = multiplySafeByRational(
+ targetRxBytes, entry.rxBytes, rawRxBytes);
+ entry.txBytes = multiplySafeByRational(
+ targetTxBytes, entry.txBytes, rawTxBytes);
// We purposefully clear out packet counters to indicate
// that this data has been augmented.
entry.rxPackets = 0;
diff --git a/services/core/java/com/android/server/net/NetworkStatsFactory.java b/services/core/java/com/android/server/net/NetworkStatsFactory.java
index 86ad0b308676..e9868fde3059 100644
--- a/services/core/java/com/android/server/net/NetworkStatsFactory.java
+++ b/services/core/java/com/android/server/net/NetworkStatsFactory.java
@@ -59,7 +59,7 @@ public class NetworkStatsFactory {
private static final String TAG = "NetworkStatsFactory";
private static final boolean USE_NATIVE_PARSING = true;
- private static final boolean SANITY_CHECK_NATIVE = false;
+ private static final boolean VALIDATE_NATIVE_STATS = false;
/** Path to {@code /proc/net/xt_qtaguid/iface_stat_all}. */
private final File mStatsXtIfaceAll;
@@ -347,7 +347,7 @@ public class NetworkStatsFactory {
INTERFACES_ALL, TAG_ALL, mUseBpfStats) != 0) {
throw new IOException("Failed to parse network stats");
}
- if (SANITY_CHECK_NATIVE) {
+ if (VALIDATE_NATIVE_STATS) {
final NetworkStats javaStats = javaReadNetworkStatsDetail(mStatsXtUid,
UID_ALL, INTERFACES_ALL, TAG_ALL);
assertEquals(javaStats, stats);
diff --git a/services/core/java/com/android/server/net/NetworkStatsRecorder.java b/services/core/java/com/android/server/net/NetworkStatsRecorder.java
index 9eff5d1648bd..ce741693cb4b 100644
--- a/services/core/java/com/android/server/net/NetworkStatsRecorder.java
+++ b/services/core/java/com/android/server/net/NetworkStatsRecorder.java
@@ -227,7 +227,7 @@ public class NetworkStatsRecorder {
for (int i = 0; i < delta.size(); i++) {
entry = delta.getValues(i, entry);
- // As a last-ditch sanity check, report any negative values and
+ // As a last-ditch check, report any negative values and
// clamp them so recording below doesn't croak.
if (entry.isNegative()) {
if (mObserver != null) {
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 88964e055a18..eefff2fb76f7 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -274,6 +274,7 @@ import com.android.server.policy.PhoneWindowManager;
import com.android.server.statusbar.StatusBarManagerInternal;
import com.android.server.uri.UriGrantsManagerInternal;
import com.android.server.wm.ActivityTaskManagerInternal;
+import com.android.server.wm.BackgroundActivityStartCallback;
import com.android.server.wm.WindowManagerInternal;
import libcore.io.IoUtils;
@@ -515,7 +516,7 @@ public class NotificationManagerService extends SystemService {
private static final int MY_UID = Process.myUid();
private static final int MY_PID = Process.myPid();
- private static final IBinder WHITELIST_TOKEN = new Binder();
+ private static final IBinder ALLOWLIST_TOKEN = new Binder();
protected RankingHandler mRankingHandler;
private long mLastOverRateLogTime;
private float mMaxPackageEnqueueRate = DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE;
@@ -1722,7 +1723,7 @@ public class NotificationManagerService extends SystemService {
super(context);
mNotificationRecordLogger = notificationRecordLogger;
mNotificationInstanceIdSequence = notificationInstanceIdSequence;
- Notification.processWhitelistToken = WHITELIST_TOKEN;
+ Notification.processAllowlistToken = ALLOWLIST_TOKEN;
}
// TODO - replace these methods with new fields in the VisibleForTesting constructor
@@ -1894,6 +1895,7 @@ public class NotificationManagerService extends SystemService {
(AccessibilityManager) getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
mAm = am;
mAtm = atm;
+ mAtm.setBackgroundActivityStartCallback(new NotificationTrampolineCallback());
mUgm = ugm;
mUgmInternal = ugmInternal;
mPackageManager = packageManager;
@@ -4752,6 +4754,12 @@ public class NotificationManagerService extends SystemService {
}
@Override
+ public boolean hasEnabledNotificationListener(String packageName, int userId) {
+ checkCallerIsSystem();
+ return mListeners.isPackageAllowed(packageName, userId);
+ }
+
+ @Override
public boolean isNotificationListenerAccessGranted(ComponentName listener) {
Objects.requireNonNull(listener);
checkCallerIsSystemOrSameApp(listener.getPackageName());
@@ -4853,7 +4861,6 @@ public class NotificationManagerService extends SystemService {
// calculate the final importance here
r.calculateImportance();
foundEnqueued = true;
- break;
}
}
if (!foundEnqueued) {
@@ -5775,21 +5782,21 @@ public class NotificationManagerService extends SystemService {
mShortcutHelper.cacheShortcut(info, user);
}
- // Whitelist pending intents.
+ // temporarily allow apps to perform extra work when their pending intents are launched
if (notification.allPendingIntents != null) {
final int intentCount = notification.allPendingIntents.size();
if (intentCount > 0) {
final ActivityManagerInternal am = LocalServices
.getService(ActivityManagerInternal.class);
final long duration = LocalServices.getService(
- DeviceIdleInternal.class).getNotificationWhitelistDuration();
+ DeviceIdleInternal.class).getNotificationAllowlistDuration();
for (int i = 0; i < intentCount; i++) {
PendingIntent pendingIntent = notification.allPendingIntents.valueAt(i);
if (pendingIntent != null) {
am.setPendingIntentWhitelistDuration(pendingIntent.getTarget(),
- WHITELIST_TOKEN, duration);
+ ALLOWLIST_TOKEN, duration);
am.setPendingIntentAllowBgActivityStarts(pendingIntent.getTarget(),
- WHITELIST_TOKEN, (FLAG_ACTIVITY_SENDER | FLAG_BROADCAST_SENDER
+ ALLOWLIST_TOKEN, (FLAG_ACTIVITY_SENDER | FLAG_BROADCAST_SENDER
| FLAG_SERVICE_SENDER));
}
}
@@ -7642,7 +7649,7 @@ public class NotificationManagerService extends SystemService {
// make sure deleteIntent cannot be used to start activities from background
LocalServices.getService(ActivityManagerInternal.class)
.clearPendingIntentAllowBgActivityStarts(deleteIntent.getTarget(),
- WHITELIST_TOKEN);
+ ALLOWLIST_TOKEN);
deleteIntent.send();
} catch (PendingIntent.CanceledException ex) {
// do nothing - there's no relevant way to recover, and
@@ -9918,4 +9925,36 @@ public class NotificationManagerService extends SystemService {
if (TextUtils.isEmpty(val)) return defValue;
return Boolean.parseBoolean(val);
}
+
+ /**
+ * Shows a warning on logcat. Shows the toast only once per package. This is to avoid being too
+ * aggressive and annoying the user.
+ *
+ * TODO(b/161957908): Remove dogfooder toast.
+ */
+ private class NotificationTrampolineCallback implements BackgroundActivityStartCallback {
+ private Set<String> mPackagesShown = new ArraySet<>();
+
+ @Override
+ public IBinder getToken() {
+ return ALLOWLIST_TOKEN;
+ }
+
+ @Override
+ public void onExclusiveTokenActivityStart(String packageName) {
+ Slog.w(TAG, "Indirect notification activity start from " + packageName);
+ boolean isFirstOccurrence = mPackagesShown.add(packageName);
+ if (!isFirstOccurrence) {
+ return;
+ }
+
+ mUiHandler.post(() ->
+ Toast.makeText(getUiContext(),
+ "Indirect activity start from "
+ + packageName + ". "
+ + "This will be blocked in S.\n"
+ + "See go/s-trampolines.",
+ Toast.LENGTH_LONG).show());
+ }
+ }
}
diff --git a/services/core/java/com/android/server/notification/RankingReconsideration.java b/services/core/java/com/android/server/notification/RankingReconsideration.java
index 057f0f111e5d..9b046b118aab 100644
--- a/services/core/java/com/android/server/notification/RankingReconsideration.java
+++ b/services/core/java/com/android/server/notification/RankingReconsideration.java
@@ -90,7 +90,7 @@ public abstract class RankingReconsideration implements Runnable {
/**
* Apply any computed changes to the notification record. This method will be
- * called on the main service thread, synchronized on he mNotificationList.
+ * called on the main service thread, synchronized on the mNotificationList.
* @param record The locked record to be updated.
*/
public abstract void applyChangesLocked(NotificationRecord record);
diff --git a/services/core/java/com/android/server/om/OverlayReferenceMapper.java b/services/core/java/com/android/server/om/OverlayReferenceMapper.java
index cadb8e4746f3..a9dbb2f29535 100644
--- a/services/core/java/com/android/server/om/OverlayReferenceMapper.java
+++ b/services/core/java/com/android/server/om/OverlayReferenceMapper.java
@@ -18,14 +18,15 @@ package com.android.server.om;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import com.android.server.pm.parsing.pkg.AndroidPackage;
import android.text.TextUtils;
import android.util.Pair;
+import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.CollectionUtils;
import com.android.server.SystemConfig;
+import com.android.server.pm.parsing.pkg.AndroidPackage;
import java.util.Collections;
import java.util.HashMap;
@@ -72,6 +73,8 @@ import java.util.Set;
*/
public class OverlayReferenceMapper {
+ private static final String TAG = "OverlayReferenceMapper";
+
private final Object mLock = new Object();
/**
@@ -144,7 +147,7 @@ public class OverlayReferenceMapper {
public boolean isValidActor(@NonNull String targetName, @NonNull String actorPackageName) {
synchronized (mLock) {
- assertMapBuilt();
+ ensureMapBuilt();
Set<String> validSet = mActorPkgToPkgs.get(actorPackageName);
return validSet != null && validSet.contains(targetName);
}
@@ -292,10 +295,11 @@ public class OverlayReferenceMapper {
}
}
- private void assertMapBuilt() {
+ private void ensureMapBuilt() {
if (mDeferRebuild) {
- throw new IllegalStateException("The actor map must be built by calling "
- + "rebuildIfDeferred before it is queried");
+ rebuildIfDeferred();
+ Slog.w(TAG, "The actor map was queried before the system was ready, which may"
+ + "result in decreased performance.");
}
}
@@ -360,7 +364,7 @@ public class OverlayReferenceMapper {
* Given the actor string from an overlayable definition, return the actor's package name.
*/
@Nullable
- String getActorPkg(String actor);
+ String getActorPkg(@NonNull String actor);
/**
* Mock response of multiple overlay tags.
diff --git a/services/core/java/com/android/server/os/TEST_MAPPING b/services/core/java/com/android/server/os/TEST_MAPPING
index a837fb4184ba..d937af1e3fdb 100644
--- a/services/core/java/com/android/server/os/TEST_MAPPING
+++ b/services/core/java/com/android/server/os/TEST_MAPPING
@@ -1,6 +1,14 @@
{
"presubmit": [
- // TODO(159590499) add BugreportManagerTestCases
+ {
+ "file_patterns": ["Bugreport[^/]*\\.java"],
+ "name": "BugreportManagerTestCases",
+ "options": [
+ {
+ "exclude-annotation": "androidx.test.filters.LargeTest"
+ }
+ ]
+ },
{
"file_patterns": ["Bugreport[^/]*\\.java"],
"name": "CtsBugreportTestCases",
diff --git a/services/core/java/com/android/server/pm/BackgroundDexOptService.java b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
index 5415967c3bdc..d48570fa3b0f 100644
--- a/services/core/java/com/android/server/pm/BackgroundDexOptService.java
+++ b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
@@ -337,6 +337,7 @@ public class BackgroundDexOptService extends JobService {
private int idleOptimizePackages(PackageManagerService pm, ArraySet<String> pkgs,
long lowStorageThreshold) {
ArraySet<String> updatedPackages = new ArraySet<>();
+ ArraySet<String> updatedPackagesDueToSecondaryDex = new ArraySet<>();
try {
final boolean supportSecondaryDex = supportSecondaryDex();
@@ -391,11 +392,14 @@ public class BackgroundDexOptService extends JobService {
}
int secondaryResult = optimizePackages(pm, pkgs, lowStorageThreshold,
- /*isForPrimaryDex*/ false, updatedPackages);
+ /*isForPrimaryDex*/ false, updatedPackagesDueToSecondaryDex);
return secondaryResult;
} finally {
// Always let the pinner service know about changes.
notifyPinService(updatedPackages);
+ // Only notify IORap the primary dex opt, because we don't want to
+ // invalidate traces unnecessary due to b/161633001 and that it's
+ // better to have a trace than no trace at all.
notifyPackagesUpdated(updatedPackages);
}
}
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 391a08db6716..1dabfdb67a2c 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -157,6 +157,7 @@ import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.Set;
+import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
public class PackageInstallerSession extends IPackageInstallerSession.Stub {
@@ -164,10 +165,11 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
private static final boolean LOGD = true;
private static final String REMOVE_MARKER_EXTENSION = ".removed";
- private static final int MSG_STREAM_VALIDATE_AND_COMMIT = 1;
- private static final int MSG_INSTALL = 2;
- private static final int MSG_ON_PACKAGE_INSTALLED = 3;
- private static final int MSG_SESSION_VERIFICATION_FAILURE = 4;
+ private static final int MSG_ON_SESSION_SEALED = 1;
+ private static final int MSG_STREAM_VALIDATE_AND_COMMIT = 2;
+ private static final int MSG_INSTALL = 3;
+ private static final int MSG_ON_PACKAGE_INSTALLED = 4;
+ private static final int MSG_SESSION_VERIFICATION_FAILURE = 5;
/** XML constants used for persisting a session */
static final String TAG_SESSION = "session";
@@ -261,6 +263,12 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
private final Object mLock = new Object();
+ /**
+ * Used to detect and reject concurrent access to this session object to ensure mutation
+ * to multiple objects like {@link #addChildSessionId} are done atomically.
+ */
+ private final AtomicBoolean mTransactionLock = new AtomicBoolean(false);
+
/** Timestamp of the last time this session changed state */
@GuardedBy("mLock")
private long updatedMillis;
@@ -444,6 +452,9 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
@Override
public boolean handleMessage(Message msg) {
switch (msg.what) {
+ case MSG_ON_SESSION_SEALED:
+ handleSessionSealed();
+ break;
case MSG_STREAM_VALIDATE_AND_COMMIT:
handleStreamValidateAndCommit();
break;
@@ -1172,6 +1183,22 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
}
}
+ dispatchSessionSealed();
+ }
+
+ /**
+ * Kicks off the install flow. The first step is to persist 'sealed' flags
+ * to prevent mutations of hard links created later.
+ */
+ private void dispatchSessionSealed() {
+ mHandler.obtainMessage(MSG_ON_SESSION_SEALED).sendToTarget();
+ }
+
+ private void handleSessionSealed() {
+ assertSealed("dispatchSessionSealed");
+ // Persist the fact that we've sealed ourselves to prevent
+ // mutations of any hard links we create.
+ mCallback.onSessionSealedBlocking(this);
dispatchStreamValidateAndCommit();
}
@@ -1425,11 +1452,6 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
}
}
- // Persist the fact that we've sealed ourselves to prevent
- // mutations of any hard links we create. We do this without holding
- // the session lock, since otherwise it's a lock inversion.
- mCallback.onSessionSealedBlocking(this);
-
return true;
}
@@ -1701,11 +1723,6 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
mInstallerUid = newOwnerAppInfo.uid;
mInstallSource = InstallSource.create(packageName, null, packageName, null);
}
-
- // Persist the fact that we've sealed ourselves to prevent
- // mutations of any hard links we create. We do this without holding
- // the session lock, since otherwise it's a lock inversion.
- mCallback.onSessionSealedBlocking(this);
}
private void handleInstall() {
@@ -1736,7 +1753,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
List<PackageInstallerSession> childSessions = getChildSessionsNotLocked();
try {
- installNonStaged(childSessions);
+ verifyNonStaged(childSessions);
} catch (PackageManagerException e) {
final String completeMsg = ExceptionUtils.getCompleteMessage(e);
Slog.e(TAG, "Commit of session " + sessionId + " failed: " + completeMsg);
@@ -1745,23 +1762,64 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
}
}
+ private void verifyNonStaged(List<PackageInstallerSession> childSessions)
+ throws PackageManagerException {
+ final PackageManagerService.VerificationParams verifyingSession =
+ makeVerificationParams();
+ if (verifyingSession == null) {
+ return;
+ }
+ if (isMultiPackage()) {
+ List<PackageManagerService.VerificationParams> verifyingChildSessions =
+ new ArrayList<>(childSessions.size());
+ boolean success = true;
+ PackageManagerException failure = null;
+ for (int i = 0; i < childSessions.size(); ++i) {
+ final PackageInstallerSession session = childSessions.get(i);
+ try {
+ final PackageManagerService.VerificationParams verifyingChildSession =
+ session.makeVerificationParams();
+ if (verifyingChildSession != null) {
+ verifyingChildSessions.add(verifyingChildSession);
+ }
+ } catch (PackageManagerException e) {
+ failure = e;
+ success = false;
+ }
+ }
+ if (!success) {
+ final IntentSender statusReceiver;
+ synchronized (mLock) {
+ statusReceiver = mRemoteStatusReceiver;
+ }
+ sendOnPackageInstalled(mContext, statusReceiver, sessionId,
+ isInstallerDeviceOwnerOrAffiliatedProfileOwner(), userId, null,
+ failure.error, failure.getLocalizedMessage(), null);
+ return;
+ }
+ mPm.verifyStage(verifyingSession, verifyingChildSessions);
+ } else {
+ mPm.verifyStage(verifyingSession);
+ }
+ }
+
private void installNonStaged(List<PackageInstallerSession> childSessions)
throws PackageManagerException {
- final PackageManagerService.ActiveInstallSession installingSession =
- makeSessionActive();
+ final PackageManagerService.InstallParams installingSession =
+ makeInstallParams();
if (installingSession == null) {
return;
}
if (isMultiPackage()) {
- List<PackageManagerService.ActiveInstallSession> installingChildSessions =
+ List<PackageManagerService.InstallParams> installingChildSessions =
new ArrayList<>(childSessions.size());
boolean success = true;
PackageManagerException failure = null;
for (int i = 0; i < childSessions.size(); ++i) {
final PackageInstallerSession session = childSessions.get(i);
try {
- final PackageManagerService.ActiveInstallSession installingChildSession =
- session.makeSessionActive();
+ final PackageManagerService.InstallParams installingChildSession =
+ session.makeInstallParams();
if (installingChildSession != null) {
installingChildSessions.add(installingChildSession);
}
@@ -1787,11 +1845,12 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
}
/**
- * Stages this session for install and returns a
- * {@link PackageManagerService.ActiveInstallSession} representing this new staged state or null
- * in case permissions need to be requested before install can proceed.
+ * Stages this session for verification and returns a
+ * {@link PackageManagerService.VerificationParams} representing this new staged state or null
+ * in case permissions need to be requested before verification can proceed.
*/
- private PackageManagerService.ActiveInstallSession makeSessionActive()
+ @Nullable
+ private PackageManagerService.VerificationParams makeVerificationParams()
throws PackageManagerException {
assertNotLocked("makeSessionActive");
@@ -1810,6 +1869,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
}
}
+ // TODO(b/159331446): Move this to makeSessionActiveForInstall and update javadoc
if (!params.isMultiPackage && needToAskForPermissions()) {
// User needs to confirm installation;
// give installer an intent they can use to involve
@@ -1831,12 +1891,12 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
}
synchronized (mLock) {
- return makeSessionActiveLocked();
+ return makeVerificationParamsLocked();
}
}
@GuardedBy("mLock")
- private PackageManagerService.ActiveInstallSession makeSessionActiveLocked()
+ private PackageManagerService.VerificationParams makeVerificationParamsLocked()
throws PackageManagerException {
if (!params.isMultiPackage) {
Objects.requireNonNull(mPackageName);
@@ -1900,29 +1960,10 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
extractNativeLibraries(stageDir, params.abiOverride, mayInheritNativeLibs());
}
- // We've reached point of no return; call into PMS to install the stage.
- // Regardless of success or failure we always destroy session.
- final IPackageInstallObserver2 localObserver = new IPackageInstallObserver2.Stub() {
- @Override
- public void onUserActionRequired(Intent intent) {
- throw new IllegalStateException();
- }
-
- @Override
- public void onPackageInstalled(String basePackageName, int returnCode, String msg,
- Bundle extras) {
- destroyInternal();
- dispatchSessionFinished(returnCode, msg, extras);
- }
- };
-
- // An observer through which PMS returns the result of verification
- // TODO(samiul): We are temporarily assigning two observer to ActiveInstallSession. One for
- // installation and one for verification. This will be fixed within next few CLs.
- final IPackageInstallObserver2 sessionVerificationObserver;
+ final IPackageInstallObserver2 localObserver;
if (!hasParentSessionId()) {
// Avoid attaching this observer to child session since they won't use it.
- sessionVerificationObserver = new IPackageInstallObserver2.Stub() {
+ localObserver = new IPackageInstallObserver2.Stub() {
@Override
public void onUserActionRequired(Intent intent) {
throw new IllegalStateException();
@@ -1932,16 +1973,15 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
public void onPackageInstalled(String basePackageName, int returnCode, String msg,
Bundle extras) {
if (returnCode == PackageManager.INSTALL_SUCCEEDED) {
- // TODO(samiul): In future, packages will not be installed immediately after
- // verification. Package verification will return control back to here,
- // and we will have call into PMS again to install package.
- //
- // For now, this is a no op.
+ onVerificationComplete();
+ } else {
+ destroyInternal();
+ dispatchSessionFinished(returnCode, msg, extras);
}
}
};
} else {
- sessionVerificationObserver = null;
+ localObserver = null;
}
final UserHandle user;
@@ -1952,9 +1992,73 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
}
mRelinquished = true;
- return new PackageManagerService.ActiveInstallSession(mPackageName, stageDir, localObserver,
- sessionVerificationObserver, sessionId, params, mInstallerUid, mInstallSource, user,
- mSigningDetails);
+
+ return mPm.new VerificationParams(user, stageDir, localObserver, params,
+ mInstallSource, mInstallerUid, mSigningDetails, sessionId);
+ }
+
+ private void onVerificationComplete() {
+ if ((params.installFlags & PackageManager.INSTALL_DRY_RUN) != 0) {
+ destroyInternal();
+ dispatchSessionFinished(PackageManager.INSTALL_SUCCEEDED, "Dry run", new Bundle());
+ return;
+ }
+
+ List<PackageInstallerSession> childSessions = getChildSessionsNotLocked();
+ try {
+ installNonStaged(childSessions);
+ } catch (PackageManagerException e) {
+ final String completeMsg = ExceptionUtils.getCompleteMessage(e);
+ Slog.e(TAG, "Commit of session " + sessionId + " failed: " + completeMsg);
+ destroyInternal();
+ dispatchSessionFinished(e.error, completeMsg, null);
+ }
+ }
+
+ /**
+ * Stages this session for install and returns a
+ * {@link PackageManagerService.InstallParams} representing this new staged state.
+ */
+ private PackageManagerService.InstallParams makeInstallParams()
+ throws PackageManagerException {
+ synchronized (mLock) {
+ if (mDestroyed) {
+ throw new PackageManagerException(
+ INSTALL_FAILED_INTERNAL_ERROR, "Session destroyed");
+ }
+ if (!mSealed) {
+ throw new PackageManagerException(
+ INSTALL_FAILED_INTERNAL_ERROR, "Session not sealed");
+ }
+ }
+
+ // We've reached point of no return; call into PMS to install the stage.
+ // Regardless of success or failure we always destroy session.
+ final IPackageInstallObserver2 localObserver = new IPackageInstallObserver2.Stub() {
+ @Override
+ public void onUserActionRequired(Intent intent) {
+ throw new IllegalStateException();
+ }
+
+ @Override
+ public void onPackageInstalled(String basePackageName, int returnCode, String msg,
+ Bundle extras) {
+ destroyInternal();
+ dispatchSessionFinished(returnCode, msg, extras);
+ }
+ };
+
+ final UserHandle user;
+ if ((params.installFlags & PackageManager.INSTALL_ALL_USERS) != 0) {
+ user = UserHandle.ALL;
+ } else {
+ user = new UserHandle(userId);
+ }
+
+ synchronized (mLock) {
+ return mPm.new InstallParams(stageDir, localObserver, params, mInstallSource, user,
+ mSigningDetails, mInstallerUid);
+ }
}
private static void maybeRenameFile(File from, File to) throws PackageManagerException {
@@ -2923,9 +3027,9 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
}
if (hasParentSessionId()) {
mSessionProvider.getSession(
- getParentSessionId()).dispatchStreamValidateAndCommit();
+ getParentSessionId()).dispatchSessionSealed();
} else {
- dispatchStreamValidateAndCommit();
+ dispatchSessionSealed();
}
if (manualStartAndDestroy) {
dataLoader.destroy(dataLoaderId);
@@ -3063,39 +3167,85 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
}
}
+ private void acquireTransactionLock() {
+ if (!mTransactionLock.compareAndSet(false, true)) {
+ throw new UnsupportedOperationException("Concurrent access not supported");
+ }
+ }
+
+ private void releaseTransactionLock() {
+ mTransactionLock.compareAndSet(true, false);
+ }
+
@Override
public void addChildSessionId(int childSessionId) {
+ if (!params.isMultiPackage) {
+ throw new IllegalStateException("Single-session " + sessionId + " can't have child.");
+ }
+
final PackageInstallerSession childSession = mSessionProvider.getSession(childSessionId);
- if (childSession == null || !childSession.canBeAddedAsChild(sessionId)) {
+ if (childSession == null) {
throw new IllegalStateException("Unable to add child session " + childSessionId
- + " as it does not exist or is in an invalid state.");
+ + " as it does not exist.");
+ }
+ if (childSession.params.isMultiPackage) {
+ throw new IllegalStateException("Multi-session " + childSessionId
+ + " can't be a child.");
}
- synchronized (mLock) {
- assertCallerIsOwnerOrRootLocked();
- assertPreparedAndNotSealedLocked("addChildSessionId");
- final int indexOfSession = mChildSessionIds.indexOfKey(childSessionId);
- if (indexOfSession >= 0) {
- return;
+ try {
+ acquireTransactionLock();
+ childSession.acquireTransactionLock();
+
+ if (!childSession.canBeAddedAsChild(sessionId)) {
+ throw new IllegalStateException("Unable to add child session " + childSessionId
+ + " as it is in an invalid state.");
+ }
+ synchronized (mLock) {
+ assertCallerIsOwnerOrRootLocked();
+ assertPreparedAndNotSealedLocked("addChildSessionId");
+
+ final int indexOfSession = mChildSessionIds.indexOfKey(childSessionId);
+ if (indexOfSession >= 0) {
+ return;
+ }
+ childSession.setParentSessionId(this.sessionId);
+ addChildSessionIdLocked(childSessionId);
}
- childSession.setParentSessionId(this.sessionId);
- addChildSessionIdLocked(childSessionId);
+ } finally {
+ releaseTransactionLock();
+ childSession.releaseTransactionLock();
}
}
@Override
public void removeChildSessionId(int sessionId) {
final PackageInstallerSession session = mSessionProvider.getSession(sessionId);
- synchronized (mLock) {
- final int indexOfSession = mChildSessionIds.indexOfKey(sessionId);
+ try {
+ acquireTransactionLock();
if (session != null) {
- session.setParentSessionId(SessionInfo.INVALID_ID);
+ session.acquireTransactionLock();
}
- if (indexOfSession < 0) {
- // not added in the first place; no-op
- return;
+
+ synchronized (mLock) {
+ assertCallerIsOwnerOrRootLocked();
+ assertPreparedAndNotSealedLocked("removeChildSessionId");
+
+ final int indexOfSession = mChildSessionIds.indexOfKey(sessionId);
+ if (indexOfSession < 0) {
+ // not added in the first place; no-op
+ return;
+ }
+ if (session != null) {
+ session.setParentSessionId(SessionInfo.INVALID_ID);
+ }
+ mChildSessionIds.removeAt(indexOfSession);
+ }
+ } finally {
+ releaseTransactionLock();
+ if (session != null) {
+ session.releaseTransactionLock();
}
- mChildSessionIds.removeAt(indexOfSession);
}
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 2854b337fd29..b39efbc08265 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -331,6 +331,7 @@ import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.Preconditions;
+import com.android.permission.persistence.RuntimePermissionsPersistence;
import com.android.server.AttributeCache;
import com.android.server.DeviceIdleInternal;
import com.android.server.EventLogTags;
@@ -1159,7 +1160,7 @@ public class PackageManagerService extends IPackageManager.Stub
final SparseArray<PackageVerificationState> mPendingVerification = new SparseArray<>();
/** List of packages waiting for rollback to be enabled. */
- final SparseArray<InstallParams> mPendingEnableRollback = new SparseArray<>();
+ final SparseArray<VerificationParams> mPendingEnableRollback = new SparseArray<>();
final PackageInstallerService mInstallerService;
@@ -1833,7 +1834,7 @@ public class PackageManagerService extends IPackageManager.Stub
if ((state != null) && !state.isVerificationComplete()
&& !state.timeoutExtended()) {
- final InstallParams params = state.getInstallParams();
+ final VerificationParams params = state.getVerificationParams();
final Uri originUri = Uri.fromFile(params.origin.resolvedFile);
Slog.i(TAG, "Verification timed out for " + originUri);
@@ -1874,7 +1875,7 @@ public class PackageManagerService extends IPackageManager.Stub
final PackageVerificationState state = mPendingVerification.get(verificationId);
if (state != null && !state.isIntegrityVerificationComplete()) {
- final InstallParams params = state.getInstallParams();
+ final VerificationParams params = state.getVerificationParams();
final Uri originUri = Uri.fromFile(params.origin.resolvedFile);
Slog.i(TAG, "Integrity verification timed out for " + originUri);
@@ -1919,7 +1920,7 @@ public class PackageManagerService extends IPackageManager.Stub
state.setVerifierResponse(response.callerUid, response.code);
if (state.isVerificationComplete()) {
- final InstallParams params = state.getInstallParams();
+ final VerificationParams params = state.getVerificationParams();
final Uri originUri = Uri.fromFile(params.origin.resolvedFile);
if (state.isInstallAllowed()) {
@@ -1953,7 +1954,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
final int response = (Integer) msg.obj;
- final InstallParams params = state.getInstallParams();
+ final VerificationParams params = state.getVerificationParams();
final Uri originUri = Uri.fromFile(params.origin.resolvedFile);
state.setIntegrityVerificationResult(response);
@@ -2037,7 +2038,8 @@ public class PackageManagerService extends IPackageManager.Stub
case ENABLE_ROLLBACK_STATUS: {
final int enableRollbackToken = msg.arg1;
final int enableRollbackCode = msg.arg2;
- InstallParams params = mPendingEnableRollback.get(enableRollbackToken);
+ final VerificationParams params =
+ mPendingEnableRollback.get(enableRollbackToken);
if (params == null) {
Slog.w(TAG, "Invalid rollback enabled token "
+ enableRollbackToken + " received");
@@ -2061,7 +2063,8 @@ public class PackageManagerService extends IPackageManager.Stub
case ENABLE_ROLLBACK_TIMEOUT: {
final int enableRollbackToken = msg.arg1;
final int sessionId = msg.arg2;
- final InstallParams params = mPendingEnableRollback.get(enableRollbackToken);
+ final VerificationParams params =
+ mPendingEnableRollback.get(enableRollbackToken);
if (params != null) {
final Uri originUri = Uri.fromFile(params.origin.resolvedFile);
@@ -2588,7 +2591,7 @@ public class PackageManagerService extends IPackageManager.Stub
(i, pm) ->
new Settings(Environment.getDataDirectory(),
i.getPermissionManagerServiceInternal().getPermissionSettings(),
- lock),
+ RuntimePermissionsPersistence.createInstance(), lock),
new Injector.LocalServicesProducer<>(ActivityTaskManagerInternal.class),
new Injector.LocalServicesProducer<>(ActivityManagerInternal.class),
new Injector.LocalServicesProducer<>(DeviceIdleInternal.class),
@@ -2969,7 +2972,6 @@ public class PackageManagerService extends IPackageManager.Stub
= systemConfig.getSharedLibraries();
final int builtInLibCount = libConfig.size();
for (int i = 0; i < builtInLibCount; i++) {
- SystemConfig.SharedLibraryEntry entry = libConfig.valueAt(i);
addBuiltInSharedLibraryLocked(libConfig.valueAt(i));
}
@@ -6445,9 +6447,14 @@ public class PackageManagerService extends IPackageManager.Stub
true /*allowDynamicSplits*/);
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+ final boolean queryMayBeFiltered =
+ UserHandle.getAppId(filterCallingUid) >= Process.FIRST_APPLICATION_UID
+ && !resolveForStart;
+
final ResolveInfo bestChoice =
chooseBestActivity(
- intent, resolvedType, flags, privateResolveFlags, query, userId);
+ intent, resolvedType, flags, privateResolveFlags, query, userId,
+ queryMayBeFiltered);
final boolean nonBrowserOnly =
(privateResolveFlags & PackageManagerInternal.RESOLVE_NON_BROWSER_ONLY) != 0;
if (nonBrowserOnly && bestChoice != null && bestChoice.handleAllWebDataURI) {
@@ -6611,7 +6618,8 @@ public class PackageManagerService extends IPackageManager.Stub
}
private ResolveInfo chooseBestActivity(Intent intent, String resolvedType,
- int flags, int privateResolveFlags, List<ResolveInfo> query, int userId) {
+ int flags, int privateResolveFlags, List<ResolveInfo> query, int userId,
+ boolean queryMayBeFiltered) {
if (query != null) {
final int N = query.size();
if (N == 1) {
@@ -6636,7 +6644,7 @@ public class PackageManagerService extends IPackageManager.Stub
// If we have saved a preference for a preferred activity for
// this Intent, use that.
ResolveInfo ri = findPreferredActivityNotLocked(intent, resolvedType,
- flags, query, r0.priority, true, false, debug, userId);
+ flags, query, r0.priority, true, false, debug, userId, queryMayBeFiltered);
if (ri != null) {
return ri;
}
@@ -6818,11 +6826,19 @@ public class PackageManagerService extends IPackageManager.Stub
&& intent.hasCategory(CATEGORY_DEFAULT);
}
+ ResolveInfo findPreferredActivityNotLocked(Intent intent, String resolvedType, int flags,
+ List<ResolveInfo> query, int priority, boolean always,
+ boolean removeMatches, boolean debug, int userId) {
+ return findPreferredActivityNotLocked(
+ intent, resolvedType, flags, query, priority, always, removeMatches, debug, userId,
+ UserHandle.getAppId(Binder.getCallingUid()) >= Process.FIRST_APPLICATION_UID);
+ }
+
// TODO: handle preferred activities missing while user has amnesia
/** <b>must not hold {@link #mLock}</b> */
ResolveInfo findPreferredActivityNotLocked(Intent intent, String resolvedType, int flags,
List<ResolveInfo> query, int priority, boolean always,
- boolean removeMatches, boolean debug, int userId) {
+ boolean removeMatches, boolean debug, int userId, boolean queryMayBeFiltered) {
if (Thread.holdsLock(mLock)) {
Slog.wtf(TAG, "Calling thread " + Thread.currentThread().getName()
+ " is holding mLock", new Throwable());
@@ -6916,10 +6932,12 @@ public class PackageManagerService extends IPackageManager.Stub
}
final boolean excludeSetupWizardHomeActivity = isHomeIntent(intent)
&& !isDeviceProvisioned;
+ final boolean allowSetMutation = !excludeSetupWizardHomeActivity
+ && !queryMayBeFiltered;
if (ai == null) {
// Do not remove launcher's preferred activity during SetupWizard
// due to it may not install yet
- if (excludeSetupWizardHomeActivity) {
+ if (!allowSetMutation) {
continue;
}
@@ -6944,7 +6962,7 @@ public class PackageManagerService extends IPackageManager.Stub
continue;
}
- if (removeMatches) {
+ if (removeMatches && allowSetMutation) {
pir.removeFilter(pa);
changed = true;
if (DEBUG_PREFERRED) {
@@ -6961,7 +6979,7 @@ public class PackageManagerService extends IPackageManager.Stub
if (always && !pa.mPref.sameSet(query, excludeSetupWizardHomeActivity)) {
if (pa.mPref.isSuperset(query, excludeSetupWizardHomeActivity)) {
- if (!excludeSetupWizardHomeActivity) {
+ if (allowSetMutation) {
// some components of the set are no longer present in
// the query, but the preferred activity can still be reused
if (DEBUG_PREFERRED) {
@@ -6982,24 +7000,28 @@ public class PackageManagerService extends IPackageManager.Stub
changed = true;
} else {
if (DEBUG_PREFERRED) {
- Slog.i(TAG, "Do not remove preferred activity for launcher"
- + " during SetupWizard");
+ Slog.i(TAG, "Do not remove preferred activity");
}
}
} else {
- Slog.i(TAG,
- "Result set changed, dropping preferred activity for "
- + intent + " type " + resolvedType);
- if (DEBUG_PREFERRED) {
- Slog.v(TAG, "Removing preferred activity since set changed "
- + pa.mPref.mComponent);
+ if (allowSetMutation) {
+ Slog.i(TAG,
+ "Result set changed, dropping preferred activity "
+ + "for " + intent + " type "
+ + resolvedType);
+ if (DEBUG_PREFERRED) {
+ Slog.v(TAG,
+ "Removing preferred activity since set changed "
+ + pa.mPref.mComponent);
+ }
+ pir.removeFilter(pa);
+ // Re-add the filter as a "last chosen" entry (!always)
+ PreferredActivity lastChosen = new PreferredActivity(
+ pa, pa.mPref.mMatch, null, pa.mPref.mComponent,
+ false);
+ pir.addFilter(lastChosen);
+ changed = true;
}
- pir.removeFilter(pa);
- // Re-add the filter as a "last chosen" entry (!always)
- PreferredActivity lastChosen = new PreferredActivity(
- pa, pa.mPref.mMatch, null, pa.mPref.mComponent, false);
- pir.addFilter(lastChosen);
- changed = true;
return null;
}
}
@@ -12831,15 +12853,8 @@ public class PackageManagerService extends IPackageManager.Stub
return installReason;
}
- void installStage(ActiveInstallSession activeInstallSession) {
- if (DEBUG_INSTANT) {
- if ((activeInstallSession.getSessionParams().installFlags
- & PackageManager.INSTALL_INSTANT_APP) != 0) {
- Slog.d(TAG, "Ephemeral install of " + activeInstallSession.getPackageName());
- }
- }
+ void installStage(InstallParams params) {
final Message msg = mHandler.obtainMessage(INIT_COPY);
- final InstallParams params = new InstallParams(activeInstallSession);
params.setTraceMethod("installStage").setTraceCookie(System.identityHashCode(params));
msg.obj = params;
@@ -12851,11 +12866,11 @@ public class PackageManagerService extends IPackageManager.Stub
mHandler.sendMessage(msg);
}
- void installStage(ActiveInstallSession parent, List<ActiveInstallSession> children)
+ void installStage(InstallParams parent, List<InstallParams> children)
throws PackageManagerException {
final Message msg = mHandler.obtainMessage(INIT_COPY);
final MultiPackageInstallParams params =
- new MultiPackageInstallParams(UserHandle.ALL, parent, children);
+ new MultiPackageInstallParams(parent, children);
params.setTraceMethod("installStageMultiPackage")
.setTraceCookie(System.identityHashCode(params));
msg.obj = params;
@@ -12867,6 +12882,21 @@ public class PackageManagerService extends IPackageManager.Stub
mHandler.sendMessage(msg);
}
+ void verifyStage(VerificationParams params) {
+ mHandler.post(()-> {
+ params.startCopy();
+ });
+ }
+
+ void verifyStage(VerificationParams parent, List<VerificationParams> children)
+ throws PackageManagerException {
+ final MultiPackageVerificationParams params =
+ new MultiPackageVerificationParams(parent, children);
+ mHandler.post(()-> {
+ params.startCopy();
+ });
+ }
+
private void sendPackageAddedForUser(String packageName, PackageSetting pkgSetting,
int userId, int dataLoaderType) {
final boolean isSystem = isSystemApp(pkgSetting) || isUpdatedSystemApp(pkgSetting);
@@ -14727,32 +14757,21 @@ public class PackageManagerService extends IPackageManager.Stub
* committed together.
*/
class MultiPackageInstallParams extends HandlerParams {
- private final IPackageInstallObserver2 mVerificationObserver;
- @NonNull
- private final ArrayList<InstallParams> mChildParams;
- // TODO(samiul): mCurrentState will relocated to a install-specific class in future
- @NonNull
+ private final List<InstallParams> mChildParams;
private final Map<InstallArgs, Integer> mCurrentState;
- private final Map<InstallParams, Integer> mVerificationState;
- MultiPackageInstallParams(
- @NonNull UserHandle user,
- @NonNull ActiveInstallSession parent,
- @NonNull List<ActiveInstallSession> activeInstallSessions)
+ MultiPackageInstallParams(InstallParams parent, List<InstallParams> childParams)
throws PackageManagerException {
- super(user);
- if (activeInstallSessions.size() == 0) {
+ super(parent.getUser());
+ if (childParams.size() == 0) {
throw new PackageManagerException("No child sessions found!");
}
- mChildParams = new ArrayList<>(activeInstallSessions.size());
- for (int i = 0; i < activeInstallSessions.size(); i++) {
- final InstallParams childParams = new InstallParams(activeInstallSessions.get(i));
- childParams.mParentInstallParams = this;
- this.mChildParams.add(childParams);
+ mChildParams = childParams;
+ for (int i = 0; i < childParams.size(); i++) {
+ final InstallParams childParam = childParams.get(i);
+ childParam.mParentInstallParams = this;
}
this.mCurrentState = new ArrayMap<>(mChildParams.size());
- this.mVerificationState = new ArrayMap<>(mChildParams.size());
- mVerificationObserver = parent.getVerificationObserver();
}
@Override
@@ -14769,7 +14788,6 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
- // TODO(samiul): this method will relocated to a install-specific class in future
void tryProcessInstallRequest(InstallArgs args, int currentStatus) {
mCurrentState.put(args, currentStatus);
if (mCurrentState.size() != mChildParams.size()) {
@@ -14793,122 +14811,67 @@ public class PackageManagerService extends IPackageManager.Stub
completeStatus == PackageManager.INSTALL_SUCCEEDED,
installRequests);
}
-
- void trySendVerificationCompleteNotification(InstallParams child, int currentStatus) {
- mVerificationState.put(child, currentStatus);
- if (mVerificationState.size() != mChildParams.size()) {
- return;
- }
- int completeStatus = PackageManager.INSTALL_SUCCEEDED;
- for (Integer status : mVerificationState.values()) {
- if (status == PackageManager.INSTALL_UNKNOWN) {
- return;
- } else if (status != PackageManager.INSTALL_SUCCEEDED) {
- completeStatus = status;
- break;
- }
- }
- try {
- mVerificationObserver.onPackageInstalled(null, completeStatus,
- "Package Verification Result", new Bundle());
- } catch (RemoteException e) {
- Slog.i(TAG, "Observer no longer exists.");
- }
- }
}
class InstallParams extends HandlerParams {
- // TODO: see if we can collapse this into ActiveInstallSession
-
final OriginInfo origin;
final MoveInfo move;
- final IPackageInstallObserver2 mInstallObserver;
- private final IPackageInstallObserver2 mVerificationObserver;
+ final IPackageInstallObserver2 observer;
int installFlags;
@NonNull final InstallSource installSource;
final String volumeUuid;
- private boolean mWaitForVerificationToComplete;
- private boolean mWaitForIntegrityVerificationToComplete;
- private boolean mWaitForEnableRollbackToComplete;
int mRet;
final String packageAbiOverride;
final String[] grantedRuntimePermissions;
final List<String> whitelistedRestrictedPermissions;
final int autoRevokePermissionsMode;
- final VerificationInfo verificationInfo;
final PackageParser.SigningDetails signingDetails;
final int installReason;
- @Nullable
- MultiPackageInstallParams mParentInstallParams;
- final long requiredInstalledVersionCode;
+ @Nullable MultiPackageInstallParams mParentInstallParams;
final boolean forceQueryableOverride;
final int mDataLoaderType;
- final int mSessionId;
- InstallParams(OriginInfo origin, MoveInfo move, IPackageInstallObserver2 installObserver,
+ InstallParams(OriginInfo origin, MoveInfo move, IPackageInstallObserver2 observer,
int installFlags, InstallSource installSource, String volumeUuid,
- VerificationInfo verificationInfo, UserHandle user, String packageAbiOverride,
- String[] grantedPermissions, List<String> whitelistedRestrictedPermissions,
- int autoRevokePermissionsMode,
- SigningDetails signingDetails, int installReason,
- long requiredInstalledVersionCode, int dataLoaderType) {
+ UserHandle user, String packageAbiOverride) {
super(user);
this.origin = origin;
this.move = move;
- this.mInstallObserver = installObserver;
- this.mVerificationObserver = null;
+ this.observer = observer;
this.installFlags = installFlags;
this.installSource = Preconditions.checkNotNull(installSource);
this.volumeUuid = volumeUuid;
- this.verificationInfo = verificationInfo;
this.packageAbiOverride = packageAbiOverride;
- this.grantedRuntimePermissions = grantedPermissions;
- this.whitelistedRestrictedPermissions = whitelistedRestrictedPermissions;
- this.autoRevokePermissionsMode = autoRevokePermissionsMode;
- this.signingDetails = signingDetails;
- this.installReason = installReason;
- this.requiredInstalledVersionCode = requiredInstalledVersionCode;
+
+ this.grantedRuntimePermissions = null;
+ this.whitelistedRestrictedPermissions = null;
+ this.autoRevokePermissionsMode = MODE_DEFAULT;
+ this.signingDetails = PackageParser.SigningDetails.UNKNOWN;
+ this.installReason = PackageManager.INSTALL_REASON_UNKNOWN;
this.forceQueryableOverride = false;
- this.mDataLoaderType = dataLoaderType;
- this.mSessionId = -1;
+ this.mDataLoaderType = DataLoaderType.NONE;
}
- InstallParams(ActiveInstallSession activeInstallSession) {
- super(activeInstallSession.getUser());
- final PackageInstaller.SessionParams sessionParams =
- activeInstallSession.getSessionParams();
- if (DEBUG_INSTANT) {
- if ((sessionParams.installFlags
- & PackageManager.INSTALL_INSTANT_APP) != 0) {
- Slog.d(TAG, "Ephemeral install of " + activeInstallSession.getPackageName());
- }
- }
- verificationInfo = new VerificationInfo(
- sessionParams.originatingUri,
- sessionParams.referrerUri,
- sessionParams.originatingUid,
- activeInstallSession.getInstallerUid());
- origin = OriginInfo.fromStagedFile(activeInstallSession.getStagedDir());
+ InstallParams(File stagedDir, IPackageInstallObserver2 observer,
+ PackageInstaller.SessionParams sessionParams, InstallSource installSource,
+ UserHandle user, SigningDetails signingDetails, int installerUid) {
+ super(user);
+ origin = OriginInfo.fromStagedFile(stagedDir);
move = null;
installReason = fixUpInstallReason(
- activeInstallSession.getInstallSource().installerPackageName,
- activeInstallSession.getInstallerUid(),
- sessionParams.installReason);
- mInstallObserver = activeInstallSession.getInstallObserver();
- mVerificationObserver = activeInstallSession.getVerificationObserver();
+ installSource.installerPackageName, installerUid, sessionParams.installReason);
+ this.observer = observer;
installFlags = sessionParams.installFlags;
- installSource = activeInstallSession.getInstallSource();
+ this.installSource = installSource;
volumeUuid = sessionParams.volumeUuid;
packageAbiOverride = sessionParams.abiOverride;
grantedRuntimePermissions = sessionParams.grantedRuntimePermissions;
whitelistedRestrictedPermissions = sessionParams.whitelistedRestrictedPermissions;
autoRevokePermissionsMode = sessionParams.autoRevokePermissionsMode;
- signingDetails = activeInstallSession.getSigningDetails();
- requiredInstalledVersionCode = sessionParams.requiredInstalledVersionCode;
+ this.signingDetails = signingDetails;
forceQueryableOverride = sessionParams.forceQueryableOverride;
mDataLoaderType = (sessionParams.dataLoaderParams != null)
? sessionParams.dataLoaderParams.getType() : DataLoaderType.NONE;
- mSessionId = activeInstallSession.getSessionId();
}
@Override
@@ -15055,12 +15018,146 @@ public class PackageManagerService extends IPackageManager.Stub
public void handleStartCopy() {
PackageInfoLite pkgLite = PackageManagerServiceUtils.getMinimalPackageInfo(mContext,
origin.resolvedPath, installFlags, packageAbiOverride);
+ mRet = overrideInstallLocation(pkgLite);
+ }
- mRet = verifyReplacingVersionCode(pkgLite);
+ @Override
+ void handleReturnCode() {
+ processPendingInstall();
+ }
+
+ private void processPendingInstall() {
+ InstallArgs args = createInstallArgs(this);
+ if (mRet == PackageManager.INSTALL_SUCCEEDED) {
+ mRet = args.copyApk();
+ }
+ if (mParentInstallParams != null) {
+ mParentInstallParams.tryProcessInstallRequest(args, mRet);
+ } else {
+ PackageInstalledInfo res = createPackageInstalledInfo(mRet);
+ processInstallRequestsAsync(
+ res.returnCode == PackageManager.INSTALL_SUCCEEDED,
+ Collections.singletonList(new InstallRequest(args, res)));
+
+ }
+ }
+ }
+
+ /**
+ * Container for a multi-package install which refers to all install sessions and args being
+ * committed together.
+ */
+ class MultiPackageVerificationParams extends HandlerParams {
+ private final IPackageInstallObserver2 mObserver;
+ private final List<VerificationParams> mChildParams;
+ private final Map<VerificationParams, Integer> mVerificationState;
+
+ MultiPackageVerificationParams(
+ VerificationParams parent,
+ List<VerificationParams> children)
+ throws PackageManagerException {
+ super(parent.getUser());
+ if (children.size() == 0) {
+ throw new PackageManagerException("No child sessions found!");
+ }
+ mChildParams = children;
+ // Provide every child with reference to this object as parent
+ for (int i = 0; i < children.size(); i++) {
+ final VerificationParams childParams = children.get(i);
+ childParams.mParentVerificationParams = this;
+ }
+ this.mVerificationState = new ArrayMap<>(mChildParams.size());
+ mObserver = parent.observer;
+ }
- if (mRet == INSTALL_SUCCEEDED) {
- mRet = overrideInstallLocation(pkgLite);
+ @Override
+ void handleStartCopy() {
+ for (VerificationParams params : mChildParams) {
+ params.handleStartCopy();
}
+ }
+
+ @Override
+ void handleReturnCode() {
+ for (VerificationParams params : mChildParams) {
+ params.handleReturnCode();
+ }
+ }
+
+ void trySendVerificationCompleteNotification(VerificationParams child, int currentStatus) {
+ mVerificationState.put(child, currentStatus);
+ if (mVerificationState.size() != mChildParams.size()) {
+ return;
+ }
+ int completeStatus = PackageManager.INSTALL_SUCCEEDED;
+ for (Integer status : mVerificationState.values()) {
+ if (status == PackageManager.INSTALL_UNKNOWN) {
+ return;
+ } else if (status != PackageManager.INSTALL_SUCCEEDED) {
+ completeStatus = status;
+ break;
+ }
+ }
+ try {
+ mObserver.onPackageInstalled(null, completeStatus,
+ "Package Verification Result", new Bundle());
+ } catch (RemoteException e) {
+ Slog.i(TAG, "Observer no longer exists.");
+ }
+ }
+ }
+
+ class VerificationParams extends HandlerParams {
+ final OriginInfo origin;
+ final IPackageInstallObserver2 observer;
+ final int installFlags;
+ @NonNull final InstallSource installSource;
+ final String packageAbiOverride;
+ final VerificationInfo verificationInfo;
+ final PackageParser.SigningDetails signingDetails;
+ @Nullable MultiPackageVerificationParams mParentVerificationParams;
+ final long requiredInstalledVersionCode;
+ final int mDataLoaderType;
+ final int mSessionId;
+
+ private boolean mWaitForVerificationToComplete;
+ private boolean mWaitForIntegrityVerificationToComplete;
+ private boolean mWaitForEnableRollbackToComplete;
+ private int mRet;
+
+ VerificationParams(UserHandle user, File stagedDir, IPackageInstallObserver2 observer,
+ PackageInstaller.SessionParams sessionParams, InstallSource installSource,
+ int installerUid, SigningDetails signingDetails, int sessionId) {
+ super(user);
+ origin = OriginInfo.fromStagedFile(stagedDir);
+ this.observer = observer;
+ installFlags = sessionParams.installFlags;
+ this.installSource = installSource;
+ packageAbiOverride = sessionParams.abiOverride;
+ verificationInfo = new VerificationInfo(
+ sessionParams.originatingUri,
+ sessionParams.referrerUri,
+ sessionParams.originatingUid,
+ installerUid
+ );
+ this.signingDetails = signingDetails;
+ requiredInstalledVersionCode = sessionParams.requiredInstalledVersionCode;
+ mDataLoaderType = (sessionParams.dataLoaderParams != null)
+ ? sessionParams.dataLoaderParams.getType() : DataLoaderType.NONE;
+ mSessionId = sessionId;
+ }
+
+ @Override
+ public String toString() {
+ return "InstallParams{" + Integer.toHexString(System.identityHashCode(this))
+ + " file=" + origin.file + "}";
+ }
+
+ public void handleStartCopy() {
+ PackageInfoLite pkgLite = PackageManagerServiceUtils.getMinimalPackageInfo(mContext,
+ origin.resolvedPath, installFlags, packageAbiOverride);
+
+ mRet = verifyReplacingVersionCode(pkgLite);
// Perform package verification and enable rollback (unless we are simply moving the
// package).
@@ -15223,7 +15320,7 @@ public class PackageManagerService extends IPackageManager.Stub
final long idleDuration = getVerificationTimeout();
idleController.addPowerSaveTempWhitelistAppDirect(Process.myUid(),
- idleDuration,
+ idleDuration,
false, "integrity component");
final BroadcastOptions options = BroadcastOptions.makeBasic();
options.setTemporaryAppWhitelistDuration(idleDuration);
@@ -15457,44 +15554,16 @@ public class PackageManagerService extends IPackageManager.Stub
|| mWaitForEnableRollbackToComplete) {
return;
}
-
- if ((installFlags & PackageManager.INSTALL_DRY_RUN) != 0) {
- try {
- mInstallObserver.onPackageInstalled(null, mRet, "Dry run", new Bundle());
- } catch (RemoteException e) {
- Slog.i(TAG, "Observer no longer exists.");
- }
- return;
- }
sendVerificationCompleteNotification();
-
- // TODO(samiul): In future return once verification is complete
- processPendingInstall();
- }
-
- private void processPendingInstall() {
- InstallArgs args = createInstallArgs(this);
- if (mRet == PackageManager.INSTALL_SUCCEEDED) {
- mRet = args.copyApk();
- }
- if (mParentInstallParams != null) {
- mParentInstallParams.tryProcessInstallRequest(args, mRet);
- } else {
- PackageInstalledInfo res = createPackageInstalledInfo(mRet);
- processInstallRequestsAsync(
- res.returnCode == PackageManager.INSTALL_SUCCEEDED,
- Collections.singletonList(new InstallRequest(args, res)));
-
- }
}
private void sendVerificationCompleteNotification() {
- if (mParentInstallParams != null) {
- mParentInstallParams.trySendVerificationCompleteNotification(this, mRet);
+ if (mParentVerificationParams != null) {
+ mParentVerificationParams.trySendVerificationCompleteNotification(this, mRet);
} else {
try {
- mVerificationObserver.onPackageInstalled(null, mRet,
- "Package Verification Result", new Bundle());
+ observer.onPackageInstalled(null, mRet, "Package Verification Result",
+ new Bundle());
} catch (RemoteException e) {
Slog.i(TAG, "Observer no longer exists.");
}
@@ -15578,7 +15647,7 @@ public class PackageManagerService extends IPackageManager.Stub
/** New install */
InstallArgs(InstallParams params) {
- this(params.origin, params.move, params.mInstallObserver, params.installFlags,
+ this(params.origin, params.move, params.observer, params.installFlags,
params.installSource, params.volumeUuid,
params.getUser(), null /*instructionSets*/, params.packageAbiOverride,
params.grantedRuntimePermissions, params.whitelistedRestrictedPermissions,
@@ -23358,12 +23427,7 @@ public class PackageManagerService extends IPackageManager.Stub
final Message msg = mHandler.obtainMessage(INIT_COPY);
final OriginInfo origin = OriginInfo.fromExistingFile(codeFile);
final InstallParams params = new InstallParams(origin, move, installObserver, installFlags,
- installSource, volumeUuid, null /*verificationInfo*/, user,
- packageAbiOverride, null /*grantedPermissions*/,
- null /*whitelistedRestrictedPermissions*/, MODE_DEFAULT /* autoRevokePermissions */,
- PackageParser.SigningDetails.UNKNOWN,
- PackageManager.INSTALL_REASON_UNKNOWN, PackageManager.VERSION_CODE_HIGHEST,
- DataLoaderType.NONE);
+ installSource, volumeUuid, user, packageAbiOverride);
params.setTraceMethod("movePackage").setTraceCookie(System.identityHashCode(params));
msg.obj = params;
@@ -25609,79 +25673,6 @@ public class PackageManagerService extends IPackageManager.Stub
public List<String> getMimeGroup(String packageName, String mimeGroup) {
return mSettings.mPackages.get(packageName).getMimeGroup(mimeGroup);
}
-
- static class ActiveInstallSession {
- private final String mPackageName;
- private final File mStagedDir;
- private final IPackageInstallObserver2 mInstallObserver;
- // TODO(samiul): We are temporarily assigning two observer to ActiveInstallSession. One for
- // installation and one for verification. This will be fixed within next few CLs.
- private final IPackageInstallObserver2 mVerificationObserver;
- private final int mSessionId;
- private final PackageInstaller.SessionParams mSessionParams;
- private final int mInstallerUid;
- @NonNull private final InstallSource mInstallSource;
- private final UserHandle mUser;
- private final SigningDetails mSigningDetails;
-
- ActiveInstallSession(String packageName, File stagedDir,
- IPackageInstallObserver2 installObserver,
- IPackageInstallObserver2 verificationObserver,
- int sessionId, PackageInstaller.SessionParams sessionParams, int installerUid,
- InstallSource installSource, UserHandle user, SigningDetails signingDetails) {
- mPackageName = packageName;
- mStagedDir = stagedDir;
- mInstallObserver = installObserver;
- mVerificationObserver = verificationObserver;
- mSessionId = sessionId;
- mSessionParams = sessionParams;
- mInstallerUid = installerUid;
- mInstallSource = Preconditions.checkNotNull(installSource);
- mUser = user;
- mSigningDetails = signingDetails;
- }
-
- public String getPackageName() {
- return mPackageName;
- }
-
- public File getStagedDir() {
- return mStagedDir;
- }
-
- public IPackageInstallObserver2 getInstallObserver() {
- return mInstallObserver;
- }
-
- public IPackageInstallObserver2 getVerificationObserver() {
- return mVerificationObserver;
- }
-
- public int getSessionId() {
- return mSessionId;
- }
-
- public PackageInstaller.SessionParams getSessionParams() {
- return mSessionParams;
- }
-
- public int getInstallerUid() {
- return mInstallerUid;
- }
-
- @NonNull
- public InstallSource getInstallSource() {
- return mInstallSource;
- }
-
- public UserHandle getUser() {
- return mUser;
- }
-
- public SigningDetails getSigningDetails() {
- return mSigningDetails;
- }
- }
}
interface PackageSender {
diff --git a/services/core/java/com/android/server/pm/PackageVerificationState.java b/services/core/java/com/android/server/pm/PackageVerificationState.java
index ea7af9031bd0..cb9c2e997e22 100644
--- a/services/core/java/com/android/server/pm/PackageVerificationState.java
+++ b/services/core/java/com/android/server/pm/PackageVerificationState.java
@@ -19,7 +19,7 @@ package com.android.server.pm;
import android.content.pm.PackageManager;
import android.util.SparseBooleanArray;
-import com.android.server.pm.PackageManagerService.InstallParams;
+import com.android.server.pm.PackageManagerService.VerificationParams;
/**
* Tracks the package verification state for a particular package. Each package verification has a
@@ -28,7 +28,7 @@ import com.android.server.pm.PackageManagerService.InstallParams;
* sufficient verifiers, then package verification is considered complete.
*/
class PackageVerificationState {
- private final InstallParams mParams;
+ private final VerificationParams mParams;
private final SparseBooleanArray mSufficientVerifierUids;
@@ -50,13 +50,13 @@ class PackageVerificationState {
* Create a new package verification state where {@code requiredVerifierUid} is the user ID for
* the package that must reply affirmative before things can continue.
*/
- PackageVerificationState(InstallParams params) {
+ PackageVerificationState(VerificationParams params) {
mParams = params;
mSufficientVerifierUids = new SparseBooleanArray();
mExtendedTimeout = false;
}
- InstallParams getInstallParams() {
+ VerificationParams getVerificationParams() {
return mParams;
}
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 7106499f9b56..1805713387ae 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -435,10 +435,11 @@ public final class Settings {
}
Settings(File dataDir, PermissionSettings permission,
- Object lock) {
+ RuntimePermissionsPersistence runtimePermissionsPersistence, Object lock) {
mLock = lock;
mPermissions = permission;
- mRuntimePermissionsPersistence = new RuntimePermissionPersistence(mLock);
+ mRuntimePermissionsPersistence = new RuntimePermissionPersistence(
+ runtimePermissionsPersistence, mLock);
mSystemDir = new File(dataDir, "system");
mSystemDir.mkdirs();
@@ -5381,8 +5382,7 @@ public final class Settings {
private String mExtendedFingerprint;
- private final RuntimePermissionsPersistence mPersistence =
- RuntimePermissionsPersistence.createInstance();
+ private final RuntimePermissionsPersistence mPersistence;
private final Handler mHandler = new MyHandler();
@@ -5407,7 +5407,9 @@ public final class Settings {
// The mapping keys are user ids.
private final SparseBooleanArray mPermissionUpgradeNeeded = new SparseBooleanArray();
- public RuntimePermissionPersistence(Object persistenceLock) {
+ public RuntimePermissionPersistence(RuntimePermissionsPersistence persistence,
+ Object persistenceLock) {
+ mPersistence = persistence;
mPersistenceLock = persistenceLock;
}
diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java
index 616e5d13f990..89bdb3ecbff9 100644
--- a/services/core/java/com/android/server/pm/StagingManager.java
+++ b/services/core/java/com/android/server/pm/StagingManager.java
@@ -804,6 +804,7 @@ public class StagingManager {
params.isStaged = false;
if (preReboot) {
params.installFlags &= ~PackageManager.INSTALL_ENABLE_ROLLBACK;
+ params.installFlags |= PackageManager.INSTALL_DRY_RUN;
}
final int apkParentSessionId = mPi.createSession(
params, session.getInstallerPackageName(), session.getInstallerAttributionTag(),
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index a44d1797b82b..b0d3d53d58b2 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -4699,6 +4699,7 @@ public class UserManagerService extends IUserManager.Stub {
pw.println("N/A");
}
+ pw.println();
StringBuilder sb = new StringBuilder();
synchronized (mPackagesLock) {
synchronized (mUsersLock) {
@@ -4786,6 +4787,7 @@ public class UserManagerService extends IUserManager.Stub {
}
}
pw.println();
+ pw.println("Device properties:");
pw.println(" Device owner id:" + mDeviceOwnerUserId);
pw.println();
pw.println(" Guest restrictions:");
@@ -4819,10 +4821,10 @@ public class UserManagerService extends IUserManager.Stub {
// Dump UserTypes
pw.println();
- pw.println(" User types (" + mUserTypes.size() + " types):");
+ pw.println("User types (" + mUserTypes.size() + " types):");
for (int i = 0; i < mUserTypes.size(); i++) {
pw.println(" " + mUserTypes.keyAt(i) + ": ");
- mUserTypes.valueAt(i).dump(pw);
+ mUserTypes.valueAt(i).dump(pw, " ");
}
// Dump package whitelist
diff --git a/services/core/java/com/android/server/pm/UserTypeDetails.java b/services/core/java/com/android/server/pm/UserTypeDetails.java
index be6880e76904..d840e5d8b882 100644
--- a/services/core/java/com/android/server/pm/UserTypeDetails.java
+++ b/services/core/java/com/android/server/pm/UserTypeDetails.java
@@ -271,8 +271,7 @@ public final class UserTypeDetails {
}
/** Dumps details of the UserTypeDetails. Do not parse this. */
- public void dump(PrintWriter pw) {
- final String prefix = " ";
+ public void dump(PrintWriter pw, String prefix) {
pw.print(prefix); pw.print("mName: "); pw.println(mName);
pw.print(prefix); pw.print("mBaseType: "); pw.println(UserInfo.flagsToString(mBaseType));
pw.print(prefix); pw.print("mEnabled: "); pw.println(mEnabled);
@@ -282,6 +281,7 @@ public final class UserTypeDetails {
pw.println(UserInfo.flagsToString(mDefaultUserInfoPropertyFlags));
pw.print(prefix); pw.print("mLabel: "); pw.println(mLabel);
+ final String restrictionsPrefix = prefix + " ";
if (isSystem()) {
pw.print(prefix); pw.println("config_defaultFirstUserRestrictions: ");
try {
@@ -293,13 +293,13 @@ public final class UserTypeDetails {
restrictions.putBoolean(userRestriction, true);
}
}
- UserRestrictionsUtils.dumpRestrictions(pw, prefix + " ", restrictions);
+ UserRestrictionsUtils.dumpRestrictions(pw, restrictionsPrefix, restrictions);
} catch (Resources.NotFoundException e) {
- pw.print(prefix); pw.println(" none - resource not found");
+ pw.print(restrictionsPrefix); pw.println("none - resource not found");
}
} else {
pw.print(prefix); pw.println("mDefaultRestrictions: ");
- UserRestrictionsUtils.dumpRestrictions(pw, prefix + " ", mDefaultRestrictions);
+ UserRestrictionsUtils.dumpRestrictions(pw, restrictionsPrefix, mDefaultRestrictions);
}
pw.print(prefix); pw.print("mIconBadge: "); pw.println(mIconBadge);
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 bc7554c54eb0..6e0efb09aff3 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -137,6 +137,7 @@ import com.android.server.LocalServices;
import com.android.server.ServiceThread;
import com.android.server.SystemConfig;
import com.android.server.Watchdog;
+import com.android.server.am.ActivityManagerService;
import com.android.server.pm.ApexManager;
import com.android.server.pm.PackageManagerServiceUtils;
import com.android.server.pm.PackageSetting;
@@ -554,13 +555,14 @@ public class PermissionManagerService extends IPermissionManager.Stub {
if (mPackageManagerInt.getInstantAppPackageName(callingUid) != null) {
return null;
}
+ final AndroidPackage pkg = mPackageManagerInt.getPackage(packageName);
synchronized (mLock) {
final BasePermission bp = mSettings.getPermissionLocked(permName);
if (bp == null) {
return null;
}
final int adjustedProtectionLevel = adjustPermissionProtectionFlagsLocked(
- bp.getProtectionLevel(), packageName, callingUid);
+ bp.getProtectionLevel(), pkg, callingUid);
return bp.generatePermissionInfo(adjustedProtectionLevel, flags);
}
}
@@ -920,6 +922,16 @@ public class PermissionManagerService extends IPermissionManager.Stub {
}
final int uid = UserHandle.getUid(userId, pkg.getUid());
+
+ try {
+ enforceCrossUserOrProfilePermission(Binder.getCallingUid(), UserHandle.getUserId(uid),
+ false, false, "checkPermissionInternal");
+ } catch (Exception e) {
+ EventLog.writeEvent(0x534e4554, "153996875", "checkPermission", uid);
+
+ throw e;
+ }
+
final PackageSetting ps = (PackageSetting) mPackageManagerInt.getPackageSetting(
pkg.getPackageName());
if (ps == null) {
@@ -1927,10 +1939,8 @@ public class PermissionManagerService extends IPermissionManager.Stub {
}
}
if (doGrant && packageName != null) {
- synchronized (mLock) {
- mDefaultPermissionGrantPolicy.grantDefaultPermissionsToDefaultBrowser(packageName,
- userId);
- }
+ mDefaultPermissionGrantPolicy.grantDefaultPermissionsToDefaultBrowser(packageName,
+ userId);
}
return true;
}
@@ -1940,10 +1950,8 @@ public class PermissionManagerService extends IPermissionManager.Stub {
final int callingUid = Binder.getCallingUid();
PackageManagerServiceUtils
.enforceSystemOrPhoneCaller("grantPermissionsToEnabledCarrierApps", callingUid);
- synchronized (mLock) {
- Binder.withCleanCallingIdentity(() -> mDefaultPermissionGrantPolicy
- .grantDefaultPermissionsToEnabledCarrierApps(packageNames, userId));
- }
+ Binder.withCleanCallingIdentity(() -> mDefaultPermissionGrantPolicy
+ .grantDefaultPermissionsToEnabledCarrierApps(packageNames, userId));
}
@Override
@@ -1951,10 +1959,8 @@ public class PermissionManagerService extends IPermissionManager.Stub {
final int callingUid = Binder.getCallingUid();
PackageManagerServiceUtils.enforceSystemOrPhoneCaller(
"grantDefaultPermissionsToEnabledImsServices", callingUid);
- synchronized (mLock) {
- Binder.withCleanCallingIdentity(() -> mDefaultPermissionGrantPolicy
- .grantDefaultPermissionsToEnabledImsServices(packageNames, userId));
- }
+ Binder.withCleanCallingIdentity(() -> mDefaultPermissionGrantPolicy
+ .grantDefaultPermissionsToEnabledImsServices(packageNames, userId));
}
@Override
@@ -1963,11 +1969,8 @@ public class PermissionManagerService extends IPermissionManager.Stub {
final int callingUid = Binder.getCallingUid();
PackageManagerServiceUtils.enforceSystemOrPhoneCaller(
"grantDefaultPermissionsToEnabledTelephonyDataServices", callingUid);
- synchronized (mLock) {
- Binder.withCleanCallingIdentity(() -> mDefaultPermissionGrantPolicy
- .grantDefaultPermissionsToEnabledTelephonyDataServices(
- packageNames, userId));
- }
+ Binder.withCleanCallingIdentity(() -> mDefaultPermissionGrantPolicy
+ .grantDefaultPermissionsToEnabledTelephonyDataServices(packageNames, userId));
}
@Override
@@ -1976,11 +1979,8 @@ public class PermissionManagerService extends IPermissionManager.Stub {
final int callingUid = Binder.getCallingUid();
PackageManagerServiceUtils.enforceSystemOrPhoneCaller(
"revokeDefaultPermissionsFromDisabledTelephonyDataServices", callingUid);
- synchronized (mLock) {
- Binder.withCleanCallingIdentity(() -> mDefaultPermissionGrantPolicy
- .revokeDefaultPermissionsFromDisabledTelephonyDataServices(
- packageNames, userId));
- }
+ Binder.withCleanCallingIdentity(() -> mDefaultPermissionGrantPolicy
+ .revokeDefaultPermissionsFromDisabledTelephonyDataServices(packageNames, userId));
}
@Override
@@ -1988,10 +1988,8 @@ public class PermissionManagerService extends IPermissionManager.Stub {
final int callingUid = Binder.getCallingUid();
PackageManagerServiceUtils
.enforceSystemOrPhoneCaller("grantDefaultPermissionsToActiveLuiApp", callingUid);
- synchronized (mLock) {
- Binder.withCleanCallingIdentity(() -> mDefaultPermissionGrantPolicy
- .grantDefaultPermissionsToActiveLuiApp(packageName, userId));
- }
+ Binder.withCleanCallingIdentity(() -> mDefaultPermissionGrantPolicy
+ .grantDefaultPermissionsToActiveLuiApp(packageName, userId));
}
@Override
@@ -1999,10 +1997,8 @@ public class PermissionManagerService extends IPermissionManager.Stub {
final int callingUid = Binder.getCallingUid();
PackageManagerServiceUtils
.enforceSystemOrPhoneCaller("revokeDefaultPermissionsFromLuiApps", callingUid);
- synchronized (mLock) {
- Binder.withCleanCallingIdentity(() -> mDefaultPermissionGrantPolicy
- .revokeDefaultPermissionsFromLuiApps(packageNames, userId));
- }
+ Binder.withCleanCallingIdentity(() -> mDefaultPermissionGrantPolicy
+ .revokeDefaultPermissionsFromLuiApps(packageNames, userId));
}
@Override
@@ -2229,8 +2225,8 @@ public class PermissionManagerService extends IPermissionManager.Stub {
}
}
- private int adjustPermissionProtectionFlagsLocked(
- int protectionLevel, String packageName, int uid) {
+ private int adjustPermissionProtectionFlagsLocked(int protectionLevel,
+ @Nullable AndroidPackage pkg, int uid) {
// Signature permission flags area always reported
final int protectionLevelMasked = protectionLevel
& (PermissionInfo.PROTECTION_NORMAL
@@ -2245,8 +2241,6 @@ public class PermissionManagerService extends IPermissionManager.Stub {
|| appId == Process.SHELL_UID) {
return protectionLevel;
}
- // Normalize package name to handle renamed packages and static libs
- final AndroidPackage pkg = mPackageManagerInt.getPackage(packageName);
if (pkg == null) {
return protectionLevel;
}
@@ -2254,14 +2248,6 @@ public class PermissionManagerService extends IPermissionManager.Stub {
return protectionLevelMasked;
}
// Apps that target O see flags for all protection levels.
- final PackageSetting ps = (PackageSetting) mPackageManagerInt.getPackageSetting(
- pkg.getPackageName());
- if (ps == null) {
- return protectionLevel;
- }
- if (ps.getAppId() != appId) {
- return protectionLevel;
- }
return protectionLevel;
}
@@ -2586,8 +2572,8 @@ public class PermissionManagerService extends IPermissionManager.Stub {
// changed runtime permissions here are promotion of an install to
// runtime and revocation of a runtime from a shared user.
synchronized (mLock) {
- updatedUserIds = revokeUnusedSharedUserPermissionsLocked(
- ps.getSharedUser(), UserManagerService.getInstance().getUserIds());
+ updatedUserIds = revokeUnusedSharedUserPermissionsLocked(ps.getSharedUser(),
+ currentUserIds);
if (!ArrayUtils.isEmpty(updatedUserIds)) {
runtimePermissionsRevoked = true;
}
@@ -2597,150 +2583,152 @@ public class PermissionManagerService extends IPermissionManager.Stub {
permissionsState.setGlobalGids(mGlobalGids);
- synchronized (mLock) {
- ArraySet<String> newImplicitPermissions = new ArraySet<>();
-
- final int N = pkg.getRequestedPermissions().size();
- for (int i = 0; i < N; i++) {
- final String permName = pkg.getRequestedPermissions().get(i);
- final BasePermission bp = mSettings.getPermissionLocked(permName);
- final boolean appSupportsRuntimePermissions =
- pkg.getTargetSdkVersion() >= Build.VERSION_CODES.M;
- String upgradedActivityRecognitionPermission = null;
-
- if (DEBUG_INSTALL && bp != null) {
- Log.i(TAG, "Package " + pkg.getPackageName()
- + " checking " + permName + ": " + bp);
- }
+ ArraySet<String> newImplicitPermissions = new ArraySet<>();
- if (bp == null || getSourcePackageSetting(bp) == null) {
- if (packageOfInterest == null || packageOfInterest.equals(
- pkg.getPackageName())) {
- if (DEBUG_PERMISSIONS) {
- Slog.i(TAG, "Unknown permission " + permName
- + " in package " + pkg.getPackageName());
- }
+ final int N = pkg.getRequestedPermissions().size();
+ for (int i = 0; i < N; i++) {
+ final String permName = pkg.getRequestedPermissions().get(i);
+ final BasePermission bp = mSettings.getPermission(permName);
+ final boolean appSupportsRuntimePermissions =
+ pkg.getTargetSdkVersion() >= Build.VERSION_CODES.M;
+ String upgradedActivityRecognitionPermission = null;
+
+ if (DEBUG_INSTALL && bp != null) {
+ Log.i(TAG, "Package " + pkg.getPackageName()
+ + " checking " + permName + ": " + bp);
+ }
+
+ if (bp == null || getSourcePackageSetting(bp) == null) {
+ if (packageOfInterest == null || packageOfInterest.equals(
+ pkg.getPackageName())) {
+ if (DEBUG_PERMISSIONS) {
+ Slog.i(TAG, "Unknown permission " + permName
+ + " in package " + pkg.getPackageName());
}
- continue;
}
+ continue;
+ }
- // Cache newImplicitPermissions before modifing permissionsState as for the shared
- // uids the original and new state are the same object
- if (!origPermissions.hasRequestedPermission(permName)
- && (pkg.getImplicitPermissions().contains(permName)
- || (permName.equals(Manifest.permission.ACTIVITY_RECOGNITION)))) {
- if (pkg.getImplicitPermissions().contains(permName)) {
- // If permName is an implicit permission, try to auto-grant
- newImplicitPermissions.add(permName);
+ // Cache newImplicitPermissions before modifing permissionsState as for the shared
+ // uids the original and new state are the same object
+ if (!origPermissions.hasRequestedPermission(permName)
+ && (pkg.getImplicitPermissions().contains(permName)
+ || (permName.equals(Manifest.permission.ACTIVITY_RECOGNITION)))) {
+ if (pkg.getImplicitPermissions().contains(permName)) {
+ // If permName is an implicit permission, try to auto-grant
+ newImplicitPermissions.add(permName);
- if (DEBUG_PERMISSIONS) {
- Slog.i(TAG, permName + " is newly added for " + pkg.getPackageName());
- }
- } else {
- // Special case for Activity Recognition permission. Even if AR permission
- // is not an implicit permission we want to add it to the list (try to
- // auto-grant it) if the app was installed on a device before AR permission
- // was split, regardless of if the app now requests the new AR permission
- // or has updated its target SDK and AR is no longer implicit to it.
- // This is a compatibility workaround for apps when AR permission was
- // split in Q.
- final List<SplitPermissionInfoParcelable> permissionList =
- getSplitPermissions();
- int numSplitPerms = permissionList.size();
- for (int splitPermNum = 0; splitPermNum < numSplitPerms; splitPermNum++) {
- SplitPermissionInfoParcelable sp = permissionList.get(splitPermNum);
- String splitPermName = sp.getSplitPermission();
- if (sp.getNewPermissions().contains(permName)
- && origPermissions.hasInstallPermission(splitPermName)) {
- upgradedActivityRecognitionPermission = splitPermName;
- newImplicitPermissions.add(permName);
+ if (DEBUG_PERMISSIONS) {
+ Slog.i(TAG, permName + " is newly added for " + pkg.getPackageName());
+ }
+ } else {
+ // Special case for Activity Recognition permission. Even if AR permission
+ // is not an implicit permission we want to add it to the list (try to
+ // auto-grant it) if the app was installed on a device before AR permission
+ // was split, regardless of if the app now requests the new AR permission
+ // or has updated its target SDK and AR is no longer implicit to it.
+ // This is a compatibility workaround for apps when AR permission was
+ // split in Q.
+ final List<SplitPermissionInfoParcelable> permissionList =
+ getSplitPermissions();
+ int numSplitPerms = permissionList.size();
+ for (int splitPermNum = 0; splitPermNum < numSplitPerms; splitPermNum++) {
+ SplitPermissionInfoParcelable sp = permissionList.get(splitPermNum);
+ String splitPermName = sp.getSplitPermission();
+ if (sp.getNewPermissions().contains(permName)
+ && origPermissions.hasInstallPermission(splitPermName)) {
+ upgradedActivityRecognitionPermission = splitPermName;
+ newImplicitPermissions.add(permName);
- if (DEBUG_PERMISSIONS) {
- Slog.i(TAG, permName + " is newly added for "
- + pkg.getPackageName());
- }
- break;
+ if (DEBUG_PERMISSIONS) {
+ Slog.i(TAG, permName + " is newly added for "
+ + pkg.getPackageName());
}
+ break;
}
}
}
+ }
- // TODO(b/140256621): The package instant app method has been removed
- // as part of work in b/135203078, so this has been commented out in the meantime
- // Limit ephemeral apps to ephemeral allowed permissions.
-// if (/*pkg.isInstantApp()*/ false && !bp.isInstant()) {
-// if (DEBUG_PERMISSIONS) {
-// Log.i(TAG, "Denying non-ephemeral permission " + bp.getName()
-// + " for package " + pkg.getPackageName());
-// }
-// continue;
+ // TODO(b/140256621): The package instant app method has been removed
+ // as part of work in b/135203078, so this has been commented out in the meantime
+ // Limit ephemeral apps to ephemeral allowed permissions.
+// if (/*pkg.isInstantApp()*/ false && !bp.isInstant()) {
+// if (DEBUG_PERMISSIONS) {
+// Log.i(TAG, "Denying non-ephemeral permission " + bp.getName()
+// + " for package " + pkg.getPackageName());
// }
+// continue;
+// }
- if (bp.isRuntimeOnly() && !appSupportsRuntimePermissions) {
- if (DEBUG_PERMISSIONS) {
- Log.i(TAG, "Denying runtime-only permission " + bp.getName()
- + " for package " + pkg.getPackageName());
- }
- continue;
+ if (bp.isRuntimeOnly() && !appSupportsRuntimePermissions) {
+ if (DEBUG_PERMISSIONS) {
+ Log.i(TAG, "Denying runtime-only permission " + bp.getName()
+ + " for package " + pkg.getPackageName());
}
+ continue;
+ }
- final String perm = bp.getName();
- boolean allowedSig = false;
- int grant = GRANT_DENIED;
+ final String perm = bp.getName();
+ boolean allowedSig = false;
+ int grant = GRANT_DENIED;
- // Keep track of app op permissions.
- if (bp.isAppOp()) {
- mSettings.addAppOpPackage(perm, pkg.getPackageName());
- }
+ // Keep track of app op permissions.
+ if (bp.isAppOp()) {
+ mSettings.addAppOpPackage(perm, pkg.getPackageName());
+ }
- if (bp.isNormal()) {
- // For all apps normal permissions are install time ones.
- grant = GRANT_INSTALL;
- } else if (bp.isRuntime()) {
- if (origPermissions.hasInstallPermission(bp.getName())
- || upgradedActivityRecognitionPermission != null) {
- // Before Q we represented some runtime permissions as install permissions,
- // in Q we cannot do this anymore. Hence upgrade them all.
- grant = GRANT_UPGRADE;
- } else {
- // For modern apps keep runtime permissions unchanged.
- grant = GRANT_RUNTIME;
- }
- } else if (bp.isSignature()) {
- // For all apps signature permissions are install time ones.
- allowedSig = grantSignaturePermission(perm, pkg, ps, bp, origPermissions);
- if (allowedSig) {
- grant = GRANT_INSTALL;
- }
+ if (bp.isNormal()) {
+ // For all apps normal permissions are install time ones.
+ grant = GRANT_INSTALL;
+ } else if (bp.isRuntime()) {
+ if (origPermissions.hasInstallPermission(bp.getName())
+ || upgradedActivityRecognitionPermission != null) {
+ // Before Q we represented some runtime permissions as install permissions,
+ // in Q we cannot do this anymore. Hence upgrade them all.
+ grant = GRANT_UPGRADE;
+ } else {
+ // For modern apps keep runtime permissions unchanged.
+ grant = GRANT_RUNTIME;
}
-
- if (DEBUG_PERMISSIONS) {
- Slog.i(TAG, "Considering granting permission " + perm + " to package "
- + pkg.getPackageName());
+ } else if (bp.isSignature()) {
+ // For all apps signature permissions are install time ones.
+ allowedSig = shouldGrantSignaturePermission(perm, pkg, ps, bp, origPermissions);
+ if (allowedSig) {
+ grant = GRANT_INSTALL;
}
+ }
- if (grant != GRANT_DENIED) {
- if (!ps.isSystem() && ps.areInstallPermissionsFixed() && !bp.isRuntime()) {
- // If this is an existing, non-system package, then
- // we can't add any new permissions to it. Runtime
- // permissions can be added any time - they ad dynamic.
- if (!allowedSig && !origPermissions.hasInstallPermission(perm)) {
- // Except... if this is a permission that was added
- // to the platform (note: need to only do this when
- // updating the platform).
- if (!isNewPlatformPermissionForPackage(perm, pkg)) {
- grant = GRANT_DENIED;
- }
+ if (grant != GRANT_DENIED) {
+ if (!ps.isSystem() && ps.areInstallPermissionsFixed() && !bp.isRuntime()) {
+ // If this is an existing, non-system package, then
+ // we can't add any new permissions to it. Runtime
+ // permissions can be added any time - they ad dynamic.
+ if (!allowedSig && !origPermissions.hasInstallPermission(perm)) {
+ // Except... if this is a permission that was added
+ // to the platform (note: need to only do this when
+ // updating the platform).
+ if (!isNewPlatformPermissionForPackage(perm, pkg)) {
+ grant = GRANT_DENIED;
}
}
+ }
+ }
+
+ if (DEBUG_PERMISSIONS) {
+ Slog.i(TAG, "Considering granting permission " + perm + " to package "
+ + pkg.getPackageName());
+ }
+ synchronized (mLock) {
+ if (grant != GRANT_DENIED) {
switch (grant) {
case GRANT_INSTALL: {
// Revoke this as runtime permission to handle the case of
// a runtime permission being downgraded to an install one.
// Also in permission review mode we keep dangerous permissions
// for legacy apps
- for (int userId : UserManagerService.getInstance().getUserIds()) {
+ for (int userId : currentUserIds) {
if (origPermissions.getRuntimePermissionState(
perm, userId) != null) {
// Revoke the runtime permission and clear the flags.
@@ -3042,20 +3030,23 @@ public class PermissionManagerService extends IPermissionManager.Stub {
}
}
}
+ }
- if ((changedInstallPermission || replace) && !ps.areInstallPermissionsFixed() &&
- !ps.isSystem() || ps.getPkgState().isUpdatedSystemApp()) {
- // This is the first that we have heard about this package, so the
- // permissions we have now selected are fixed until explicitly
- // changed.
- ps.setInstallPermissionsFixed(true);
- }
+ if ((changedInstallPermission || replace) && !ps.areInstallPermissionsFixed() &&
+ !ps.isSystem() || ps.getPkgState().isUpdatedSystemApp()) {
+ // This is the first that we have heard about this package, so the
+ // permissions we have now selected are fixed until explicitly
+ // changed.
+ ps.setInstallPermissionsFixed(true);
+ }
+ synchronized (mLock) {
updatedUserIds = revokePermissionsNoLongerImplicitLocked(permissionsState, pkg,
- updatedUserIds);
+ currentUserIds, updatedUserIds);
updatedUserIds = setInitialGrantForNewImplicitPermissionsLocked(origPermissions,
- permissionsState, pkg, newImplicitPermissions, updatedUserIds);
- updatedUserIds = checkIfLegacyStorageOpsNeedToBeUpdated(pkg, replace, updatedUserIds);
+ permissionsState, pkg, newImplicitPermissions, currentUserIds, updatedUserIds);
+ updatedUserIds = checkIfLegacyStorageOpsNeedToBeUpdated(pkg, replace, currentUserIds,
+ updatedUserIds);
}
// Persist the runtime permissions state for users with changes. If permissions
@@ -3076,23 +3067,19 @@ public class PermissionManagerService extends IPermissionManager.Stub {
*
* @param ps The state of the permissions of the package
* @param pkg The package that is currently looked at
+ * @param userIds All user IDs in the system, must be passed in because this method is locked
* @param updatedUserIds a list of user ids that needs to be amended if the permission state
* for a user is changed.
*
* @return The updated value of the {@code updatedUserIds} parameter
*/
- private @NonNull int[] revokePermissionsNoLongerImplicitLocked(
- @NonNull PermissionsState ps, @NonNull AndroidPackage pkg,
- @NonNull int[] updatedUserIds) {
+ private @NonNull int[] revokePermissionsNoLongerImplicitLocked(@NonNull PermissionsState ps,
+ @NonNull AndroidPackage pkg, @NonNull int[] userIds, @NonNull int[] updatedUserIds) {
String pkgName = pkg.getPackageName();
boolean supportsRuntimePermissions = pkg.getTargetSdkVersion()
>= Build.VERSION_CODES.M;
- int[] users = UserManagerService.getInstance().getUserIds();
- int numUsers = users.length;
- for (int i = 0; i < numUsers; i++) {
- int userId = users[i];
-
+ for (int userId : userIds) {
for (String permission : ps.getPermissions(userId)) {
if (!pkg.getImplicitPermissions().contains(permission)) {
if (!ps.hasInstallPermission(permission)) {
@@ -3188,16 +3175,17 @@ public class PermissionManagerService extends IPermissionManager.Stub {
*
* @param pkg The package for which the permissions are updated
* @param replace If the app is being replaced
+ * @param userIds All user IDs in the system, must be passed in because this method is locked
* @param updatedUserIds The ids of the users that already changed.
*
* @return The ids of the users that are changed
*/
- private @NonNull int[] checkIfLegacyStorageOpsNeedToBeUpdated(
- @NonNull AndroidPackage pkg, boolean replace, @NonNull int[] updatedUserIds) {
+ private @NonNull int[] checkIfLegacyStorageOpsNeedToBeUpdated(@NonNull AndroidPackage pkg,
+ boolean replace, @NonNull int[] userIds, @NonNull int[] updatedUserIds) {
if (replace && pkg.isRequestLegacyExternalStorage() && (
pkg.getRequestedPermissions().contains(READ_EXTERNAL_STORAGE)
|| pkg.getRequestedPermissions().contains(WRITE_EXTERNAL_STORAGE))) {
- return UserManagerService.getInstance().getUserIds();
+ return userIds.clone();
}
return updatedUserIds;
@@ -3209,15 +3197,15 @@ public class PermissionManagerService extends IPermissionManager.Stub {
* @param origPs The permission state of the package before the split
* @param ps The new permission state
* @param pkg The package the permission belongs to
+ * @param userIds All user IDs in the system, must be passed in because this method is locked
* @param updatedUserIds List of users for which the permission state has already been changed
*
* @return List of users for which the permission state has been changed
*/
private @NonNull int[] setInitialGrantForNewImplicitPermissionsLocked(
- @NonNull PermissionsState origPs,
- @NonNull PermissionsState ps, @NonNull AndroidPackage pkg,
- @NonNull ArraySet<String> newImplicitPermissions,
- @NonNull int[] updatedUserIds) {
+ @NonNull PermissionsState origPs, @NonNull PermissionsState ps,
+ @NonNull AndroidPackage pkg, @NonNull ArraySet<String> newImplicitPermissions,
+ @NonNull int[] userIds, @NonNull int[] updatedUserIds) {
String pkgName = pkg.getPackageName();
ArrayMap<String, ArraySet<String>> newToSplitPerms = new ArrayMap<>();
@@ -3251,11 +3239,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
if (!ps.hasInstallPermission(newPerm)) {
BasePermission bp = mSettings.getPermissionLocked(newPerm);
- int[] users = UserManagerService.getInstance().getUserIds();
- int numUsers = users.length;
- for (int userNum = 0; userNum < numUsers; userNum++) {
- int userId = users[userNum];
-
+ for (int userId : userIds) {
if (!newPerm.equals(Manifest.permission.ACTIVITY_RECOGNITION)) {
ps.updatePermissionFlags(bp, userId,
FLAG_PERMISSION_REVOKE_WHEN_REQUESTED,
@@ -3413,7 +3397,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
return wlPermissions != null && wlPermissions.contains(perm);
}
- private boolean grantSignaturePermission(String perm, AndroidPackage pkg,
+ private boolean shouldGrantSignaturePermission(String perm, AndroidPackage pkg,
PackageSetting pkgSetting, BasePermission bp, PermissionsState origPermissions) {
boolean oemPermission = bp.isOEM();
boolean vendorPrivilegedPermission = bp.isVendorPrivileged();
@@ -4210,6 +4194,14 @@ public class PermissionManagerService extends IPermissionManager.Stub {
// The target package is the source of the current permission
// Set to changed for either install or uninstall
changed = true;
+ if (needsUpdate == null) {
+ needsUpdate = new ArraySet<>(mSettings.mPermissions.size());
+ }
+ needsUpdate.add(bp);
+ }
+ }
+ if (needsUpdate != null) {
+ for (final BasePermission bp : needsUpdate) {
// If the target package is being uninstalled, we need to revoke this permission
// From all other packages
if (pkg == null || !hasPermission(pkg, bp.getName())) {
@@ -4239,16 +4231,9 @@ public class PermissionManagerService extends IPermissionManager.Stub {
}
});
}
- it.remove();
- }
- if (needsUpdate == null) {
- needsUpdate = new ArraySet<>(mSettings.mPermissions.size());
+ mSettings.removePermissionLocked(bp.getName());
+ continue;
}
- needsUpdate.add(bp);
- }
- }
- if (needsUpdate != null) {
- for (final BasePermission bp : needsUpdate) {
final AndroidPackage sourcePkg =
mPackageManagerInt.getPackage(bp.getSourcePackageName());
final PackageSetting sourcePs =
@@ -4414,7 +4399,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
}
final int callingUserId = UserHandle.getUserId(callingUid);
if (hasCrossUserPermission(
- callingUid, callingUserId, userId, requireFullPermission,
+ Binder.getCallingPid(), callingUid, callingUserId, userId, requireFullPermission,
requirePermissionWhenSameUser)) {
return;
}
@@ -4441,37 +4426,54 @@ public class PermissionManagerService extends IPermissionManager.Stub {
private void enforceCrossUserOrProfilePermission(int callingUid, int userId,
boolean requireFullPermission, boolean checkShell,
String message) {
+ int callingPid = Binder.getCallingPid();
+ final int callingUserId = UserHandle.getUserId(callingUid);
+
if (userId < 0) {
throw new IllegalArgumentException("Invalid userId " + userId);
}
- if (checkShell) {
- PackageManagerServiceUtils.enforceShellRestriction(mUserManagerInt,
- UserManager.DISALLOW_DEBUGGING_FEATURES, callingUid, userId);
- }
- final int callingUserId = UserHandle.getUserId(callingUid);
- if (hasCrossUserPermission(callingUid, callingUserId, userId, requireFullPermission,
- /*requirePermissionWhenSameUser= */ false)) {
+
+ if (callingUserId == userId) {
return;
}
- final boolean isSameProfileGroup = isSameProfileGroup(callingUserId, userId);
- if (isSameProfileGroup && PermissionChecker.checkPermissionForPreflight(
- mContext,
- android.Manifest.permission.INTERACT_ACROSS_PROFILES,
- PermissionChecker.PID_UNKNOWN,
- callingUid,
- mPackageManagerInt.getPackage(callingUid).getPackageName())
- == PermissionChecker.PERMISSION_GRANTED) {
+
+ // Prevent endless loop between when checking permission while checking a permission
+ if (callingPid == ActivityManagerService.MY_PID) {
return;
}
- String errorMessage = buildInvalidCrossUserOrProfilePermissionMessage(
- message, requireFullPermission, isSameProfileGroup);
- Slog.w(TAG, errorMessage);
- throw new SecurityException(errorMessage);
+
+ long token = Binder.clearCallingIdentity();
+ try {
+ if (checkShell) {
+ PackageManagerServiceUtils.enforceShellRestriction(mUserManagerInt,
+ UserManager.DISALLOW_DEBUGGING_FEATURES, callingUid, userId);
+ }
+ if (hasCrossUserPermission(callingPid, callingUid, callingUserId, userId,
+ requireFullPermission, /*requirePermissionWhenSameUser= */ false)) {
+ return;
+ }
+ final boolean isSameProfileGroup = isSameProfileGroup(callingUserId, userId);
+ if (isSameProfileGroup && PermissionChecker.checkPermissionForPreflight(
+ mContext,
+ android.Manifest.permission.INTERACT_ACROSS_PROFILES,
+ PermissionChecker.PID_UNKNOWN,
+ callingUid,
+ mPackageManagerInt.getPackage(callingUid).getPackageName())
+ == PermissionChecker.PERMISSION_GRANTED) {
+ return;
+ }
+
+ String errorMessage = buildInvalidCrossUserOrProfilePermissionMessage(
+ message, requireFullPermission, isSameProfileGroup);
+ Slog.w(TAG, errorMessage);
+ throw new SecurityException(errorMessage);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
}
- private boolean hasCrossUserPermission(
- int callingUid, int callingUserId, int userId, boolean requireFullPermission,
- boolean requirePermissionWhenSameUser) {
+ private boolean hasCrossUserPermission(int callingPid, int callingUid, int callingUserId,
+ int userId, boolean requireFullPermission, boolean requirePermissionWhenSameUser) {
if (!requirePermissionWhenSameUser && userId == callingUserId) {
return true;
}
@@ -4479,15 +4481,11 @@ public class PermissionManagerService extends IPermissionManager.Stub {
return true;
}
if (requireFullPermission) {
- return hasPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL);
+ return mContext.checkPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL,
+ callingPid, callingUid) == PackageManager.PERMISSION_GRANTED;
}
- return hasPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
- || hasPermission(Manifest.permission.INTERACT_ACROSS_USERS);
- }
-
- private boolean hasPermission(String permission) {
- return mContext.checkCallingOrSelfPermission(permission)
- == PackageManager.PERMISSION_GRANTED;
+ return mContext.checkPermission(android.Manifest.permission.INTERACT_ACROSS_USERS,
+ callingPid, callingUid) == PackageManager.PERMISSION_GRANTED;
}
private boolean isSameProfileGroup(@UserIdInt int callerUserId, @UserIdInt int userId) {
@@ -4899,58 +4897,42 @@ public class PermissionManagerService extends IPermissionManager.Stub {
@Override
public void setDialerAppPackagesProvider(PackagesProvider provider) {
- synchronized (mLock) {
- mDefaultPermissionGrantPolicy.setDialerAppPackagesProvider(provider);
- }
+ mDefaultPermissionGrantPolicy.setDialerAppPackagesProvider(provider);
}
@Override
public void setLocationExtraPackagesProvider(PackagesProvider provider) {
- synchronized (mLock) {
- mDefaultPermissionGrantPolicy.setLocationExtraPackagesProvider(provider);
- }
+ mDefaultPermissionGrantPolicy.setLocationExtraPackagesProvider(provider);
}
@Override
public void setLocationPackagesProvider(PackagesProvider provider) {
- synchronized (mLock) {
- mDefaultPermissionGrantPolicy.setLocationPackagesProvider(provider);
- }
+ mDefaultPermissionGrantPolicy.setLocationPackagesProvider(provider);
}
@Override
public void setSimCallManagerPackagesProvider(PackagesProvider provider) {
- synchronized (mLock) {
- mDefaultPermissionGrantPolicy.setSimCallManagerPackagesProvider(provider);
- }
+ mDefaultPermissionGrantPolicy.setSimCallManagerPackagesProvider(provider);
}
@Override
public void setSmsAppPackagesProvider(PackagesProvider provider) {
- synchronized (mLock) {
- mDefaultPermissionGrantPolicy.setSmsAppPackagesProvider(provider);
- }
+ mDefaultPermissionGrantPolicy.setSmsAppPackagesProvider(provider);
}
@Override
public void setSyncAdapterPackagesProvider(SyncAdapterPackagesProvider provider) {
- synchronized (mLock) {
- mDefaultPermissionGrantPolicy.setSyncAdapterPackagesProvider(provider);
- }
+ mDefaultPermissionGrantPolicy.setSyncAdapterPackagesProvider(provider);
}
@Override
public void setUseOpenWifiAppPackagesProvider(PackagesProvider provider) {
- synchronized (mLock) {
- mDefaultPermissionGrantPolicy.setUseOpenWifiAppPackagesProvider(provider);
- }
+ mDefaultPermissionGrantPolicy.setUseOpenWifiAppPackagesProvider(provider);
}
@Override
public void setVoiceInteractionPackagesProvider(PackagesProvider provider) {
- synchronized (mLock) {
- mDefaultPermissionGrantPolicy.setVoiceInteractionPackagesProvider(provider);
- }
+ mDefaultPermissionGrantPolicy.setVoiceInteractionPackagesProvider(provider);
}
@Override
@@ -4982,36 +4964,28 @@ public class PermissionManagerService extends IPermissionManager.Stub {
@Override
public void grantDefaultPermissionsToDefaultSimCallManager(String packageName, int userId) {
- synchronized (mLock) {
- mDefaultPermissionGrantPolicy
- .grantDefaultPermissionsToDefaultSimCallManager(packageName, userId);
- }
+ mDefaultPermissionGrantPolicy.grantDefaultPermissionsToDefaultSimCallManager(
+ packageName, userId);
}
@Override
public void grantDefaultPermissionsToDefaultUseOpenWifiApp(String packageName, int userId) {
- synchronized (mLock) {
- mDefaultPermissionGrantPolicy
- .grantDefaultPermissionsToDefaultUseOpenWifiApp(packageName, userId);
- }
+ mDefaultPermissionGrantPolicy.grantDefaultPermissionsToDefaultUseOpenWifiApp(
+ packageName, userId);
}
@Override
public void grantDefaultPermissionsToDefaultBrowser(String packageName, int userId) {
- synchronized (mLock) {
- mDefaultPermissionGrantPolicy
- .grantDefaultPermissionsToDefaultBrowser(packageName, userId);
- }
+ mDefaultPermissionGrantPolicy.grantDefaultPermissionsToDefaultBrowser(packageName,
+ userId);
}
@Override
public void onNewUserCreated(int userId) {
mDefaultPermissionGrantPolicy.grantDefaultPermissions(userId);
- synchronized (mLock) {
- // NOTE: This adds UPDATE_PERMISSIONS_REPLACE_PKG
- PermissionManagerService.this.updateAllPermissions(
- StorageManager.UUID_PRIVATE_INTERNAL, true, mDefaultPermissionCallback);
- }
+ // NOTE: This adds UPDATE_PERMISSIONS_REPLACE_PKG
+ PermissionManagerService.this.updateAllPermissions(StorageManager.UUID_PRIVATE_INTERNAL,
+ true, mDefaultPermissionCallback);
}
@Override
diff --git a/services/core/java/com/android/server/pm/permission/PermissionSettings.java b/services/core/java/com/android/server/pm/permission/PermissionSettings.java
index 355e24326c8e..eea8ac737b86 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionSettings.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionSettings.java
@@ -88,12 +88,14 @@ public class PermissionSettings {
}
public void addAppOpPackage(String permName, String packageName) {
- ArraySet<String> pkgs = mAppOpPermissionPackages.get(permName);
- if (pkgs == null) {
- pkgs = new ArraySet<>();
- mAppOpPermissionPackages.put(permName, pkgs);
+ synchronized (mLock) {
+ ArraySet<String> pkgs = mAppOpPermissionPackages.get(permName);
+ if (pkgs == null) {
+ pkgs = new ArraySet<>();
+ mAppOpPermissionPackages.put(permName, pkgs);
+ }
+ pkgs.add(packageName);
}
- pkgs.add(packageName);
}
/**
diff --git a/services/core/java/com/android/server/pm/permission/TEST_MAPPING b/services/core/java/com/android/server/pm/permission/TEST_MAPPING
index c0d71ac26853..65dc320eadc2 100644
--- a/services/core/java/com/android/server/pm/permission/TEST_MAPPING
+++ b/services/core/java/com/android/server/pm/permission/TEST_MAPPING
@@ -18,21 +18,24 @@
]
},
{
- "name": "CtsAppSecurityHostTestCases",
+ "name": "CtsPermission2TestCases",
"options": [
{
- "include-filter": "android.appsecurity.cts.AppSecurityTests#rebootWithDuplicatePermission"
+ "include-filter": "android.permission2.cts.RestrictedPermissionsTest"
+ },
+ {
+ "include-filter": "android.permission.cts.PermissionMaxSdkVersionTest"
}
]
},
{
- "name": "CtsPermission2TestCases",
+ "name": "CtsPermissionHostTestCases"
+ },
+ {
+ "name": "CtsAppSecurityHostTestCases",
"options": [
{
- "include-filter": "android.permission2.cts.RestrictedPermissionsTest"
- },
- {
- "include-filter": "android.permission.cts.PermissionMaxSdkVersionTest"
+ "include-filter": "android.appsecurity.cts.AppSecurityTests#rebootWithDuplicatePermission"
}
]
},
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 4c4680b17372..a2b46a08dc42 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -3208,6 +3208,7 @@ public final class PowerManagerService extends SystemService
// If we're stuck in a really low-level reboot loop, and a
// rescue party is trying to prompt the user for a factory data
// reset, we must GET TO DA CHOPPA!
+ // No check point from ShutdownCheckPoints will be dumped at this state.
PowerManagerService.lowLevelReboot(reason);
} else {
throw new IllegalStateException("Too early to call shutdown() or reboot()");
@@ -5114,6 +5115,7 @@ public final class PowerManagerService extends SystemService
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.RECOVERY, null);
}
+ ShutdownCheckPoints.recordCheckPoint(Binder.getCallingPid(), reason);
final long ident = Binder.clearCallingIdentity();
try {
shutdownOrRebootInternal(HALT_MODE_REBOOT, confirm, reason, wait);
@@ -5132,10 +5134,11 @@ public final class PowerManagerService extends SystemService
public void rebootSafeMode(boolean confirm, boolean wait) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.REBOOT, null);
+ String reason = PowerManager.REBOOT_SAFE_MODE;
+ ShutdownCheckPoints.recordCheckPoint(Binder.getCallingPid(), reason);
final long ident = Binder.clearCallingIdentity();
try {
- shutdownOrRebootInternal(HALT_MODE_REBOOT_SAFE_MODE, confirm,
- PowerManager.REBOOT_SAFE_MODE, wait);
+ shutdownOrRebootInternal(HALT_MODE_REBOOT_SAFE_MODE, confirm, reason, wait);
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -5151,6 +5154,7 @@ public final class PowerManagerService extends SystemService
public void shutdown(boolean confirm, String reason, boolean wait) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.REBOOT, null);
+ ShutdownCheckPoints.recordCheckPoint(Binder.getCallingPid(), reason);
final long ident = Binder.clearCallingIdentity();
try {
shutdownOrRebootInternal(HALT_MODE_SHUTDOWN, confirm, reason, wait);
diff --git a/services/core/java/com/android/server/power/ShutdownCheckPoints.java b/services/core/java/com/android/server/power/ShutdownCheckPoints.java
index e6d0dddf710c..05ee7dfb4cae 100644
--- a/services/core/java/com/android/server/power/ShutdownCheckPoints.java
+++ b/services/core/java/com/android/server/power/ShutdownCheckPoints.java
@@ -90,18 +90,19 @@ public final class ShutdownCheckPoints {
}
/** Records the stack trace of this {@link Thread} as a shutdown check point. */
- public static void recordCheckPoint() {
- INSTANCE.recordCheckPointInternal();
+ public static void recordCheckPoint(@Nullable String reason) {
+ INSTANCE.recordCheckPointInternal(reason);
}
/** Records the pid of the caller process as a shutdown check point. */
- public static void recordCheckPoint(int callerProcessId) {
- INSTANCE.recordCheckPointInternal(callerProcessId);
+ public static void recordCheckPoint(int callerProcessId, @Nullable String reason) {
+ INSTANCE.recordCheckPointInternal(callerProcessId, reason);
}
/** Records the {@link android.content.Intent} name and package as a shutdown check point. */
- public static void recordCheckPoint(String intentName, String packageName) {
- INSTANCE.recordCheckPointInternal(intentName, packageName);
+ public static void recordCheckPoint(
+ String intentName, String packageName, @Nullable String reason) {
+ INSTANCE.recordCheckPointInternal(intentName, packageName, reason);
}
/** Serializes the recorded check points and writes them to given {@code printWriter}. */
@@ -119,24 +120,24 @@ public final class ShutdownCheckPoints {
}
@VisibleForTesting
- void recordCheckPointInternal() {
- recordCheckPointInternal(new SystemServerCheckPoint(mInjector));
+ void recordCheckPointInternal(@Nullable String reason) {
+ recordCheckPointInternal(new SystemServerCheckPoint(mInjector, reason));
Slog.v(TAG, "System server shutdown checkpoint recorded");
}
@VisibleForTesting
- void recordCheckPointInternal(int callerProcessId) {
+ void recordCheckPointInternal(int callerProcessId, @Nullable String reason) {
recordCheckPointInternal(callerProcessId == Process.myPid()
- ? new SystemServerCheckPoint(mInjector)
- : new BinderCheckPoint(mInjector, callerProcessId));
+ ? new SystemServerCheckPoint(mInjector, reason)
+ : new BinderCheckPoint(mInjector, callerProcessId, reason));
Slog.v(TAG, "Binder shutdown checkpoint recorded with pid=" + callerProcessId);
}
@VisibleForTesting
- void recordCheckPointInternal(String intentName, String packageName) {
+ void recordCheckPointInternal(String intentName, String packageName, @Nullable String reason) {
recordCheckPointInternal("android".equals(packageName)
- ? new SystemServerCheckPoint(mInjector)
- : new IntentCheckPoint(mInjector, intentName, packageName));
+ ? new SystemServerCheckPoint(mInjector, reason)
+ : new IntentCheckPoint(mInjector, intentName, packageName, reason));
Slog.v(TAG, String.format("Shutdown intent checkpoint recorded intent=%s from package=%s",
intentName, packageName));
}
@@ -182,14 +183,20 @@ public final class ShutdownCheckPoints {
private abstract static class CheckPoint {
private final long mTimestamp;
+ @Nullable private final String mReason;
- CheckPoint(Injector injector) {
+ CheckPoint(Injector injector, @Nullable String reason) {
mTimestamp = injector.currentTimeMillis();
+ mReason = reason;
}
final void dump(PrintWriter printWriter) {
printWriter.print("Shutdown request from ");
printWriter.print(getOrigin());
+ if (mReason != null) {
+ printWriter.print(" for reason ");
+ printWriter.print(mReason);
+ }
printWriter.print(" at ");
printWriter.print(DATE_FORMAT.format(new Date(mTimestamp)));
printWriter.println(" (epoch=" + mTimestamp + ")");
@@ -206,8 +213,8 @@ public final class ShutdownCheckPoints {
private final StackTraceElement[] mStackTraceElements;
- SystemServerCheckPoint(Injector injector) {
- super(injector);
+ SystemServerCheckPoint(Injector injector, @Nullable String reason) {
+ super(injector, reason);
mStackTraceElements = Thread.currentThread().getStackTrace();
}
@@ -263,8 +270,8 @@ public final class ShutdownCheckPoints {
private final int mCallerProcessId;
private final IActivityManager mActivityManager;
- BinderCheckPoint(Injector injector, int callerProcessId) {
- super(injector);
+ BinderCheckPoint(Injector injector, int callerProcessId, @Nullable String reason) {
+ super(injector, reason);
mCallerProcessId = callerProcessId;
mActivityManager = injector.activityManager();
}
@@ -307,8 +314,9 @@ public final class ShutdownCheckPoints {
private final String mIntentName;
private final String mPackageName;
- IntentCheckPoint(Injector injector, String intentName, String packageName) {
- super(injector);
+ IntentCheckPoint(
+ Injector injector, String intentName, String packageName, @Nullable String reason) {
+ super(injector, reason);
mIntentName = intentName;
mPackageName = packageName;
}
diff --git a/services/core/java/com/android/server/power/ShutdownThread.java b/services/core/java/com/android/server/power/ShutdownThread.java
index 2621d8b46494..e94575c43363 100644
--- a/services/core/java/com/android/server/power/ShutdownThread.java
+++ b/services/core/java/com/android/server/power/ShutdownThread.java
@@ -65,7 +65,7 @@ public final class ShutdownThread extends Thread {
private static final int RADIOS_STATE_POLL_SLEEP_MS = 100;
// maximum time we wait for the shutdown broadcast before going on.
private static final int MAX_BROADCAST_TIME = 10 * 1000;
- private static final int MAX_CHECK_POINTS_DUMP_WAIT_TIME = 20 * 1000;
+ private static final int MAX_CHECK_POINTS_DUMP_WAIT_TIME = 10 * 1000;
private static final int MAX_RADIO_WAIT_TIME = 12 * 1000;
private static final int MAX_UNCRYPT_WAIT_TIME = 15 * 60 * 1000;
// constants for progress bar. the values are roughly estimated based on timeout.
@@ -165,6 +165,10 @@ public final class ShutdownThread extends Thread {
}
}
+ // Add checkpoint for this shutdown attempt. The user might still cancel the dialog, but
+ // this point preserves the system trace of the trigger point of the ShutdownThread.
+ ShutdownCheckPoints.recordCheckPoint(/* reason= */ null);
+
final int longPressBehavior = context.getResources().getInteger(
com.android.internal.R.integer.config_longPressOnPowerBehavior);
final int resourceId = mRebootSafeMode
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index 93ea5e3a3c2b..9bc8afa3561f 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -67,6 +67,7 @@ import com.android.server.UiThread;
import com.android.server.inputmethod.InputMethodManagerInternal;
import com.android.server.notification.NotificationDelegate;
import com.android.server.policy.GlobalActionsProvider;
+import com.android.server.power.ShutdownCheckPoints;
import com.android.server.power.ShutdownThread;
import java.io.FileDescriptor;
@@ -1182,13 +1183,14 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D
@Override
public void shutdown() {
enforceStatusBarService();
+ String reason = PowerManager.SHUTDOWN_USER_REQUESTED;
+ ShutdownCheckPoints.recordCheckPoint(Binder.getCallingPid(), reason);
long identity = Binder.clearCallingIdentity();
try {
mNotificationDelegate.prepareForPossibleShutdown();
// ShutdownThread displays UI, so give it a UI context.
mHandler.post(() ->
- ShutdownThread.shutdown(getUiContext(),
- PowerManager.SHUTDOWN_USER_REQUESTED, false));
+ ShutdownThread.shutdown(getUiContext(), reason, false));
} finally {
Binder.restoreCallingIdentity(identity);
}
@@ -1200,6 +1202,10 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D
@Override
public void reboot(boolean safeMode) {
enforceStatusBarService();
+ String reason = safeMode
+ ? PowerManager.REBOOT_SAFE_MODE
+ : PowerManager.SHUTDOWN_USER_REQUESTED;
+ ShutdownCheckPoints.recordCheckPoint(Binder.getCallingPid(), reason);
long identity = Binder.clearCallingIdentity();
try {
mNotificationDelegate.prepareForPossibleShutdown();
@@ -1208,8 +1214,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D
if (safeMode) {
ShutdownThread.rebootSafeMode(getUiContext(), true);
} else {
- ShutdownThread.reboot(getUiContext(),
- PowerManager.SHUTDOWN_USER_REQUESTED, false);
+ ShutdownThread.reboot(getUiContext(), reason, false);
}
});
} finally {
diff --git a/services/core/java/com/android/server/storage/StorageUserConnection.java b/services/core/java/com/android/server/storage/StorageUserConnection.java
index ed5706752cb2..1c29c69239f6 100644
--- a/services/core/java/com/android/server/storage/StorageUserConnection.java
+++ b/services/core/java/com/android/server/storage/StorageUserConnection.java
@@ -29,11 +29,13 @@ import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
+import android.os.HandlerThread;
import android.os.IBinder;
import android.os.ParcelFileDescriptor;
import android.os.ParcelableException;
import android.os.RemoteCallback;
import android.os.UserHandle;
+import android.os.UserManagerInternal;
import android.os.storage.StorageManagerInternal;
import android.os.storage.StorageVolume;
import android.service.storage.ExternalStorageService;
@@ -62,19 +64,27 @@ import java.util.concurrent.TimeoutException;
public final class StorageUserConnection {
private static final String TAG = "StorageUserConnection";
- public static final int REMOTE_TIMEOUT_SECONDS = 20;
+ private static final int DEFAULT_REMOTE_TIMEOUT_SECONDS = 20;
private final Object mLock = new Object();
private final Context mContext;
private final int mUserId;
private final StorageSessionController mSessionController;
private final ActiveConnection mActiveConnection = new ActiveConnection();
+ private final boolean mIsDemoUser;
@GuardedBy("mLock") private final Map<String, Session> mSessions = new HashMap<>();
+ @GuardedBy("mLock") @Nullable private HandlerThread mHandlerThread;
public StorageUserConnection(Context context, int userId, StorageSessionController controller) {
mContext = Objects.requireNonNull(context);
mUserId = Preconditions.checkArgumentNonnegative(userId);
mSessionController = controller;
+ mIsDemoUser = LocalServices.getService(UserManagerInternal.class)
+ .getUserInfo(userId).isDemo();
+ if (mIsDemoUser) {
+ mHandlerThread = new HandlerThread("StorageUserConnectionThread-" + mUserId);
+ mHandlerThread.start();
+ }
}
/**
@@ -181,6 +191,9 @@ public final class StorageUserConnection {
*/
public void close() {
mActiveConnection.close();
+ if (mIsDemoUser) {
+ mHandlerThread.quit();
+ }
}
/** Returns all created sessions. */
@@ -200,7 +213,7 @@ public final class StorageUserConnection {
private void waitForLatch(CountDownLatch latch, String reason) throws TimeoutException {
try {
- if (!latch.await(REMOTE_TIMEOUT_SECONDS, TimeUnit.SECONDS)) {
+ if (!latch.await(DEFAULT_REMOTE_TIMEOUT_SECONDS, TimeUnit.SECONDS)) {
// TODO(b/140025078): Call ActivityManager ANR API?
Slog.wtf(TAG, "Failed to bind to the ExternalStorageService for user " + mUserId);
throw new TimeoutException("Latch wait for " + reason + " elapsed");
@@ -416,15 +429,32 @@ public final class StorageUserConnection {
};
Slog.i(TAG, "Binding to the ExternalStorageService for user " + mUserId);
- if (mContext.bindServiceAsUser(new Intent().setComponent(name), mServiceConnection,
- Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT,
- UserHandle.of(mUserId))) {
- Slog.i(TAG, "Bound to the ExternalStorageService for user " + mUserId);
- return mLatch;
+ if (mIsDemoUser) {
+ // Schedule on a worker thread for demo user to avoid deadlock
+ if (mContext.bindServiceAsUser(new Intent().setComponent(name),
+ mServiceConnection,
+ Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT,
+ mHandlerThread.getThreadHandler(),
+ UserHandle.of(mUserId))) {
+ Slog.i(TAG, "Bound to the ExternalStorageService for user " + mUserId);
+ return mLatch;
+ } else {
+ mIsConnecting = false;
+ throw new ExternalStorageServiceException(
+ "Failed to bind to the ExternalStorageService for user " + mUserId);
+ }
} else {
- mIsConnecting = false;
- throw new ExternalStorageServiceException(
- "Failed to bind to the ExternalStorageService for user " + mUserId);
+ if (mContext.bindServiceAsUser(new Intent().setComponent(name),
+ mServiceConnection,
+ Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT,
+ UserHandle.of(mUserId))) {
+ Slog.i(TAG, "Bound to the ExternalStorageService for user " + mUserId);
+ return mLatch;
+ } else {
+ mIsConnecting = false;
+ throw new ExternalStorageServiceException(
+ "Failed to bind to the ExternalStorageService for user " + mUserId);
+ }
}
}
}
diff --git a/services/core/java/com/android/server/twilight/TwilightService.java b/services/core/java/com/android/server/twilight/TwilightService.java
index 88a60ddc5a1e..47ab12742e9d 100644
--- a/services/core/java/com/android/server/twilight/TwilightService.java
+++ b/services/core/java/com/android/server/twilight/TwilightService.java
@@ -23,7 +23,6 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
-import android.icu.impl.CalendarAstronomer;
import android.icu.util.Calendar;
import android.location.Location;
import android.location.LocationListener;
@@ -38,6 +37,8 @@ import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
import com.android.server.SystemService;
+import com.ibm.icu.impl.CalendarAstronomer;
+
import java.util.Objects;
/**
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 63ece0465993..024ef874757b 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -3655,13 +3655,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
}
- @Override
- protected void reparentSurfaceControl(Transaction t, SurfaceControl newParent) {
- if (!mSurfaceAnimator.hasLeash()) {
- t.reparent(mSurfaceControl, newParent);
- }
- }
-
void logStartActivity(int tag, Task task) {
final Uri data = intent.getData();
final String strData = data != null ? data.toSafeString() : null;
@@ -5926,10 +5919,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// stack, i.e. the hierarchy of the surfaces is unchanged.
if (inPinnedWindowingMode()) {
return getStack().getSurfaceControl();
- } else if (WindowManagerService.sHierarchicalAnimations) {
- return super.getAnimationLeashParent();
} else {
- return getAppAnimationLayer();
+ return super.getAnimationLeashParent();
}
}
@@ -6017,11 +6008,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
mAnimationBoundsLayer = createAnimationBoundsLayer(t);
// Crop to stack bounds.
- if (!WindowManagerService.sHierarchicalAnimations) {
- // For Hierarchical animation, we don't need to set window crop since the leash
- // surface size has already same as the animating container.
- t.setWindowCrop(mAnimationBoundsLayer, mTmpRect);
- }
t.setLayer(leash, 0);
t.setLayer(mAnimationBoundsLayer, getAnimationLayer());
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index e84f040931bb..f7cb0146ea52 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -118,6 +118,7 @@ import com.android.internal.app.HeavyWeightSwitcherActivity;
import com.android.internal.app.IVoiceInteractor;
import com.android.server.am.PendingIntentRecord;
import com.android.server.pm.InstantAppResolver;
+import com.android.server.power.ShutdownCheckPoints;
import com.android.server.uri.NeededUriGrants;
import com.android.server.wm.ActivityMetricsLogger.LaunchingState;
import com.android.server.wm.ActivityStackSupervisor.PendingActivityLaunch;
@@ -647,6 +648,19 @@ class ActivityStarter {
mRequest.resolveActivity(mSupervisor);
}
+ // Add checkpoint for this shutdown or reboot attempt, so we can record the original
+ // intent action and package name.
+ if (mRequest.intent != null) {
+ String intentAction = mRequest.intent.getAction();
+ String callingPackage = mRequest.callingPackage;
+ if (intentAction != null && callingPackage != null
+ && (Intent.ACTION_REQUEST_SHUTDOWN.equals(intentAction)
+ || Intent.ACTION_SHUTDOWN.equals(intentAction)
+ || Intent.ACTION_REBOOT.equals(intentAction))) {
+ ShutdownCheckPoints.recordCheckPoint(intentAction, callingPackage, null);
+ }
+ }
+
int res;
synchronized (mService.mGlobalLock) {
final boolean globalConfigWillChange = mRequest.globalConfig != null
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
index a903bcd3d728..777ddda89e9d 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
@@ -221,6 +221,14 @@ public abstract class ActivityTaskManagerInternal {
boolean allowBackgroundActivityStart);
/**
+ * Callback to be called on certain activity start scenarios.
+ *
+ * @see BackgroundActivityStartCallback
+ */
+ public abstract void setBackgroundActivityStartCallback(
+ @Nullable BackgroundActivityStartCallback callback);
+
+ /**
* Start activity {@code intent} without calling user-id check.
*
* - DO NOT call it with the calling UID cleared.
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 029b5547ae29..c4af3e2c04c9 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -145,7 +145,6 @@ import android.app.IActivityTaskManager;
import android.app.IApplicationThread;
import android.app.IAssistDataReceiver;
import android.app.INotificationManager;
-import android.app.IRequestFinishCallback;
import android.app.ITaskStackListener;
import android.app.Notification;
import android.app.NotificationManager;
@@ -675,6 +674,9 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
WindowOrganizerController mWindowOrganizerController;
TaskOrganizerController mTaskOrganizerController;
+ @Nullable
+ private BackgroundActivityStartCallback mBackgroundActivityStartCallback;
+
private int mDeviceOwnerUid = Process.INVALID_UID;
private final class FontScaleSettingObserver extends ContentObserver {
@@ -1001,6 +1003,11 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
return config;
}
+ @Nullable
+ public BackgroundActivityStartCallback getBackgroundActivityStartCallback() {
+ return mBackgroundActivityStartCallback;
+ }
+
private void start() {
LocalServices.addService(ActivityTaskManagerInternal.class, mInternal);
}
@@ -2464,7 +2471,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
}
@Override
- public void onBackPressedOnTaskRoot(IBinder token, IRequestFinishCallback callback) {
+ public void onBackPressedOnTaskRoot(IBinder token) {
synchronized (mGlobalLock) {
ActivityRecord r = ActivityRecord.isInStackLocked(token);
if (r == null) {
@@ -2478,18 +2485,13 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
// callback
} else if (stack != null && (stack.isSingleTaskInstance())) {
// Single-task stacks are used for activities which are presented in floating
- // windows above full screen activities. Instead of directly finishing the
- // task, a task change listener is used to notify SystemUI so the action can be
- // handled specially.
+ // windows above full screen activities. A task change listener is used to notify
+ // SystemUI so the back action can be handled specially.
final Task task = r.getTask();
mTaskChangeNotificationController
.notifyBackPressedOnTaskRoot(task.getTaskInfo());
} else {
- try {
- callback.requestFinish();
- } catch (RemoteException e) {
- Slog.e(TAG, "Failed to invoke request finish callback", e);
- }
+ moveActivityTaskToBack(token, false /* nonRoot */);
}
}
}
@@ -2835,7 +2837,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
}
if (toTop) {
- taskDisplayArea.positionStackAt(POSITION_TOP, primarySplitTask,
+ taskDisplayArea.positionChildAt(POSITION_TOP, primarySplitTask,
false /* includingParents */);
}
WindowContainerTransaction wct = new WindowContainerTransaction();
@@ -6142,6 +6144,11 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
return false;
}
+ public void setBackgroundActivityStartCallback(
+ @Nullable BackgroundActivityStartCallback backgroundActivityStartCallback) {
+ mBackgroundActivityStartCallback = backgroundActivityStartCallback;
+ }
+
@Override
public int startActivitiesAsPackage(String packageName, @Nullable String featureId,
int userId, Intent[] intents, Bundle bOptions) {
diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java
index d60d098071cc..5720e9b7f193 100644
--- a/services/core/java/com/android/server/wm/AppTransitionController.java
+++ b/services/core/java/com/android/server/wm/AppTransitionController.java
@@ -411,10 +411,6 @@ public class AppTransitionController {
}
}
- if (!WindowManagerService.sHierarchicalAnimations) {
- return new ArraySet<>(candidates);
- }
-
final ArraySet<ActivityRecord> otherApps = visible ? closingApps : openingApps;
// Ancestors of closing apps while finding animation targets for opening apps, or ancestors
// of opening apps while finding animation targets for closing apps.
diff --git a/services/core/java/com/android/server/wm/BackgroundActivityStartCallback.java b/services/core/java/com/android/server/wm/BackgroundActivityStartCallback.java
new file mode 100644
index 000000000000..4e742b96c8d0
--- /dev/null
+++ b/services/core/java/com/android/server/wm/BackgroundActivityStartCallback.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm;
+
+import android.os.IBinder;
+
+/**
+ * Callback to be called when a background activity start is allowed exclusively because of the
+ * token provided in {@link #getToken()}.
+ */
+public interface BackgroundActivityStartCallback {
+ /**
+ * The token that allowed the activity start that triggered {@link
+ * #onExclusiveTokenActivityStart()}.
+ *
+ * Ideally this should just return a final variable, don't do anything costly here (don't hold
+ * any locks).
+ */
+ IBinder getToken();
+
+ /**
+ * Called when the background activity start happens.
+ */
+ void onExclusiveTokenActivityStart(String packageName);
+}
diff --git a/services/core/java/com/android/server/wm/ConfigurationContainer.java b/services/core/java/com/android/server/wm/ConfigurationContainer.java
index 98f57c5c31da..13033a6fcf81 100644
--- a/services/core/java/com/android/server/wm/ConfigurationContainer.java
+++ b/services/core/java/com/android/server/wm/ConfigurationContainer.java
@@ -93,9 +93,17 @@ public abstract class ConfigurationContainer<E extends ConfigurationContainer> {
private final Rect mTmpRect = new Rect();
static final int BOUNDS_CHANGE_NONE = 0;
- // Return value from {@link setBounds} indicating the position of the override bounds changed.
+
+ /**
+ * Return value from {@link #setBounds(Rect)} indicating the position of the override bounds
+ * changed.
+ */
static final int BOUNDS_CHANGE_POSITION = 1;
- // Return value from {@link setBounds} indicating the size of the override bounds changed.
+
+ /**
+ * Return value from {@link #setBounds(Rect)} indicating the size of the override bounds
+ * changed.
+ */
static final int BOUNDS_CHANGE_SIZE = 1 << 1;
/**
@@ -226,6 +234,11 @@ public abstract class ConfigurationContainer<E extends ConfigurationContainer> {
return equivalentBounds(getRequestedOverrideBounds(), bounds);
}
+ /** Similar to {@link #equivalentRequestedOverrideBounds(Rect)}, but compares max bounds. */
+ public boolean equivalentRequestedOverrideMaxBounds(Rect bounds) {
+ return equivalentBounds(getRequestedOverrideMaxBounds(), bounds);
+ }
+
/**
* Returns whether the two bounds are equal to each other or are a combination of null or empty.
*/
@@ -238,7 +251,6 @@ public abstract class ConfigurationContainer<E extends ConfigurationContainer> {
/**
* Returns the effective bounds of this container, inheriting the first non-empty bounds set in
* its ancestral hierarchy, including itself.
- * @return
*/
public Rect getBounds() {
mReturnBounds.set(getConfiguration().windowConfiguration.getBounds());
@@ -249,6 +261,12 @@ public abstract class ConfigurationContainer<E extends ConfigurationContainer> {
outBounds.set(getBounds());
}
+ /** Similar to {@link #getBounds()}, but reports the max bounds. */
+ public Rect getMaxBounds() {
+ mReturnBounds.set(getConfiguration().windowConfiguration.getMaxBounds());
+ return mReturnBounds;
+ }
+
/**
* Sets {@code out} to the top-left corner of the bounds as returned by {@link #getBounds()}.
*/
@@ -273,6 +291,13 @@ public abstract class ConfigurationContainer<E extends ConfigurationContainer> {
return mReturnBounds;
}
+ /** Similar to {@link #getRequestedOverrideBounds()}, but returns the max bounds. */
+ public Rect getRequestedOverrideMaxBounds() {
+ mReturnBounds.set(getRequestedOverrideConfiguration().windowConfiguration.getMaxBounds());
+
+ return mReturnBounds;
+ }
+
/**
* Returns {@code true} if the {@link WindowConfiguration} in the requested override
* {@link Configuration} specifies bounds.
@@ -283,7 +308,7 @@ public abstract class ConfigurationContainer<E extends ConfigurationContainer> {
/**
* Sets the passed in {@link Rect} to the current bounds.
- * @see {@link #getRequestedOverrideBounds()}.
+ * @see #getRequestedOverrideBounds()
*/
public void getRequestedOverrideBounds(Rect outBounds) {
outBounds.set(getRequestedOverrideBounds());
@@ -295,19 +320,25 @@ public abstract class ConfigurationContainer<E extends ConfigurationContainer> {
* {@link #getRequestedOverrideBounds()}. If
* an empty {@link Rect} or null is specified, this container will be considered to match its
* parent bounds {@see #matchParentBounds} and will inherit bounds from its parent.
+ *
* @param bounds The bounds defining the container size.
+ *
* @return a bitmask representing the types of changes made to the bounds.
*/
public int setBounds(Rect bounds) {
int boundsChange = diffRequestedOverrideBounds(bounds);
+ final boolean overrideMaxBounds = providesMaxBounds()
+ && diffRequestedOverrideMaxBounds(bounds) != BOUNDS_CHANGE_NONE;
- if (boundsChange == BOUNDS_CHANGE_NONE) {
+ if (boundsChange == BOUNDS_CHANGE_NONE && !overrideMaxBounds) {
return boundsChange;
}
-
mRequestsTmpConfig.setTo(getRequestedOverrideConfiguration());
mRequestsTmpConfig.windowConfiguration.setBounds(bounds);
+ if (overrideMaxBounds) {
+ mRequestsTmpConfig.windowConfiguration.setMaxBounds(bounds);
+ }
onRequestedOverrideConfigurationChanged(mRequestsTmpConfig);
return boundsChange;
@@ -318,6 +349,40 @@ public abstract class ConfigurationContainer<E extends ConfigurationContainer> {
return setBounds(mTmpRect);
}
+ /**
+ * Returns {@code true} if this {@link ConfigurationContainer} provides the maximum bounds to
+ * its child {@link ConfigurationContainer}s. Returns {@code false}, otherwise.
+ * <p>
+ * The maximum bounds is how large a window can be expanded. Currently only
+ * {@link DisplayContent} and {@link DisplayArea} effect this property.
+ * </p>
+ */
+ protected boolean providesMaxBounds() {
+ return false;
+ }
+
+ int diffRequestedOverrideMaxBounds(Rect bounds) {
+ if (equivalentRequestedOverrideMaxBounds(bounds)) {
+ return BOUNDS_CHANGE_NONE;
+ }
+
+ int boundsChange = BOUNDS_CHANGE_NONE;
+
+ final Rect existingBounds = getRequestedOverrideMaxBounds();
+
+ if (bounds == null || existingBounds.left != bounds.left
+ || existingBounds.top != bounds.top) {
+ boundsChange |= BOUNDS_CHANGE_POSITION;
+ }
+
+ if (bounds == null || existingBounds.width() != bounds.width()
+ || existingBounds.height() != bounds.height()) {
+ boundsChange |= BOUNDS_CHANGE_SIZE;
+ }
+
+ return boundsChange;
+ }
+
int diffRequestedOverrideBounds(Rect bounds) {
if (equivalentRequestedOverrideBounds(bounds)) {
return BOUNDS_CHANGE_NONE;
@@ -340,10 +405,6 @@ public abstract class ConfigurationContainer<E extends ConfigurationContainer> {
return boundsChange;
}
- boolean hasOverrideConfiguration() {
- return mHasOverrideConfiguration;
- }
-
public WindowConfiguration getWindowConfiguration() {
return mFullConfiguration.windowConfiguration;
}
@@ -368,7 +429,7 @@ public abstract class ConfigurationContainer<E extends ConfigurationContainer> {
/** Sets the always on top flag for this configuration container.
* When you call this function, make sure that the following functions are called as well to
* keep proper z-order.
- * - {@Link DisplayContent#positionStackAt(POSITION_TOP, TaskStack)};
+ * - {@link TaskDisplayArea#positionChildAt(int POSITION_TOP, Task, boolean)};
* */
public void setAlwaysOnTop(boolean alwaysOnTop) {
mRequestsTmpConfig.setTo(getRequestedOverrideConfiguration());
diff --git a/services/core/java/com/android/server/wm/DisplayArea.java b/services/core/java/com/android/server/wm/DisplayArea.java
index 546c5d4c29de..6ffb48282017 100644
--- a/services/core/java/com/android/server/wm/DisplayArea.java
+++ b/services/core/java/com/android/server/wm/DisplayArea.java
@@ -25,6 +25,7 @@ import static android.window.DisplayAreaOrganizer.FEATURE_UNDEFINED;
import static android.window.DisplayAreaOrganizer.FEATURE_WINDOW_TOKENS;
import static com.android.internal.util.Preconditions.checkState;
+import static com.android.server.wm.DisplayAreaProto.IS_TASK_DISPLAY_AREA;
import static com.android.server.wm.DisplayAreaProto.NAME;
import static com.android.server.wm.DisplayAreaProto.WINDOW_CONTAINER;
import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ORIENTATION;
@@ -194,6 +195,7 @@ public class DisplayArea<T extends WindowContainer> extends WindowContainer<T> {
final long token = proto.start(fieldId);
super.dumpDebug(proto, WINDOW_CONTAINER, logLevel);
proto.write(NAME, mName);
+ proto.write(IS_TASK_DISPLAY_AREA, isTaskDisplayArea());
proto.end(token);
}
@@ -349,6 +351,15 @@ public class DisplayArea<T extends WindowContainer> extends WindowContainer<T> {
return info;
}
+ @Override
+ public boolean providesMaxBounds() {
+ return true;
+ }
+
+ protected boolean isTaskDisplayArea() {
+ return false;
+ }
+
/**
* DisplayArea that contains WindowTokens, and orders them according to their type.
*/
diff --git a/services/core/java/com/android/server/wm/DisplayAreaPolicy.java b/services/core/java/com/android/server/wm/DisplayAreaPolicy.java
index 33eb3ce57373..be18d0a9a6df 100644
--- a/services/core/java/com/android/server/wm/DisplayAreaPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayAreaPolicy.java
@@ -37,18 +37,19 @@ import java.util.ArrayList;
import java.util.List;
/**
- * Policy that manages DisplayAreas.
+ * Policy that manages {@link DisplayArea}.
*/
public abstract class DisplayAreaPolicy {
protected final WindowManagerService mWmService;
/**
- * The root DisplayArea. Attach all DisplayAreas to this area (directly or indirectly).
+ * The {@link RootDisplayArea} of the whole logical display. All {@link DisplayArea}s must be
+ * (direct or indirect) descendants of this area.
*/
protected final RootDisplayArea mRoot;
/**
- * Construct a new {@link DisplayAreaPolicy}
+ * Constructs a new {@link DisplayAreaPolicy}
*
* @param wmService the window manager service instance
* @param root the root display area under which the policy operates
@@ -59,9 +60,10 @@ public abstract class DisplayAreaPolicy {
}
/**
- * Called to ask the policy to attach the given WindowToken to the DisplayArea hierarchy.
+ * Called to ask the policy to attach the given {@link WindowToken} to the {@link DisplayArea}
+ * hierarchy.
*
- * This must attach the token to mRoot (or one of its descendants).
+ * <p>This must attach the token to {@link #mRoot} (or one of its descendants).
*/
public abstract void addWindow(WindowToken token);
@@ -121,13 +123,14 @@ public abstract class DisplayAreaPolicy {
/**
* Provider for {@link DisplayAreaPolicy} instances.
*
- * By implementing this interface and overriding the
+ * <p>By implementing this interface and overriding the
* {@code config_deviceSpecificDisplayAreaPolicyProvider}, a device-specific implementations
* of {@link DisplayAreaPolicy} can be supplied.
*/
public interface Provider {
/**
- * Instantiates a new DisplayAreaPolicy. It should set up the {@link DisplayArea} hierarchy.
+ * Instantiates a new {@link DisplayAreaPolicy}. It should set up the {@link DisplayArea}
+ * hierarchy.
*
* @see DisplayAreaPolicy#DisplayAreaPolicy
*/
diff --git a/services/core/java/com/android/server/wm/DisplayAreaPolicyBuilder.java b/services/core/java/com/android/server/wm/DisplayAreaPolicyBuilder.java
index 681b21cfc829..b6cff625da5d 100644
--- a/services/core/java/com/android/server/wm/DisplayAreaPolicyBuilder.java
+++ b/services/core/java/com/android/server/wm/DisplayAreaPolicyBuilder.java
@@ -46,31 +46,90 @@ import java.util.function.BiFunction;
* A builder for instantiating a complex {@link DisplayAreaPolicy}
*
* <p>Given a set of features (that each target a set of window types), it builds the necessary
- * DisplayArea hierarchy.
+ * {@link DisplayArea} hierarchy.
*
- * <p>Example: <br />
+ * <p>Example:
*
- * <pre>
- * // Feature for targeting everything below the magnification overlay:
- * new DisplayAreaPolicyBuilder(...)
- * .addFeature(new Feature.Builder(..., "Magnification")
- * .upTo(TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY)
- * .build())
- * .build(...)
+ * <pre class="prettyprint">
+ * // Build root hierarchy of the logical display.
+ * DisplayAreaPolicyBuilder.HierarchyBuilder rootHierarchy =
+ * new DisplayAreaPolicyBuilder.HierarchyBuilder(root)
+ * // Feature for targeting everything below the magnification overlay
+ * .addFeature(new DisplayAreaPolicyBuilder.Feature.Builder(wmService.mPolicy,
+ * "WindowedMagnification", FEATURE_WINDOWED_MAGNIFICATION)
+ * .upTo(TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY)
+ * .except(TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY)
+ * // Make the DA dimmable so that the magnify window also mirrors the
+ * // dim layer
+ * .setNewDisplayAreaSupplier(DisplayArea.Dimmable::new)
+ * .build())
+ * .setImeContainer(imeContainer)
+ * .setTaskDisplayAreas(rootTdaList);
*
- * // Builds a policy with the following hierarchy:
- * - RootDisplayArea
- * - Magnification
- * - DisplayArea.Tokens (Wallpapers are attached here)
- * - TaskDisplayArea
- * - DisplayArea.Tokens (windows above Tasks up to IME are attached here)
- * - ImeContainers
- * - DisplayArea.Tokens (windows above IME up to TYPE_ACCESSIBILITY_OVERLAY attached here)
- * - DisplayArea.Tokens (TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY and up are attached here)
+ * // Build root hierarchy of front and rear DisplayAreaGroup.
+ * RootDisplayArea frontRoot = new RootDisplayArea(wmService, "FrontRoot", FEATURE_FRONT_ROOT);
+ * DisplayAreaPolicyBuilder.HierarchyBuilder frontGroupHierarchy =
+ * new DisplayAreaPolicyBuilder.HierarchyBuilder(frontRoot)
+ * // (Optional) .addFeature(...)
+ * .setTaskDisplayAreas(frontTdaList);
*
+ * RootDisplayArea rearRoot = new RootDisplayArea(wmService, "RearRoot", FEATURE_REAR_ROOT);
+ * DisplayAreaPolicyBuilder.HierarchyBuilder rearGroupHierarchy =
+ * new DisplayAreaPolicyBuilder.HierarchyBuilder(rearRoot)
+ * // (Optional) .addFeature(...)
+ * .setTaskDisplayAreas(rearTdaList);
+ *
+ * // Define the function to select root for window to attach.
+ * BiFunction<WindowToken, Bundle, RootDisplayArea> selectRootForWindowFunc =
+ * (windowToken, bundle) -> {
+ * if (bundle == null) {
+ * return root;
+ * }
+ * // OEMs need to define the condition.
+ * if (...) {
+ * return frontRoot;
+ * }
+ * if (...) {
+ * return rearRoot;
+ * }
+ * return root;
+ * };
+ *
+ * return new DisplayAreaPolicyBuilder()
+ * .setRootHierarchy(rootHierarchy)
+ * .addDisplayAreaGroupHierarchy(frontGroupHierarchy)
+ * .addDisplayAreaGroupHierarchy(rearGroupHierarchy)
+ * .setSelectRootForWindowFunc(selectRootForWindowFunc)
+ * .build(wmService, content);
* </pre>
*
- * // TODO(b/158713595): document more complex scenarios where we need multiple areas per feature.
+ * This builds a policy with the following hierarchy:
+ * <pre class="prettyprint">
+ * - RootDisplayArea (DisplayContent)
+ * - WindowedMagnification
+ * - DisplayArea.Tokens (Wallpapers can be attached here)
+ * - TaskDisplayArea
+ * - RootDisplayArea (FrontRoot)
+ * - DisplayArea.Tokens (Wallpapers can be attached here)
+ * - TaskDisplayArea
+ * - DisplayArea.Tokens (windows above Tasks up to IME can be attached here)
+ * - DisplayArea.Tokens (windows above IME can be attached here)
+ * - RootDisplayArea (RearRoot)
+ * - DisplayArea.Tokens (Wallpapers can be attached here)
+ * - TaskDisplayArea
+ * - DisplayArea.Tokens (windows above Tasks up to IME can be attached here)
+ * - DisplayArea.Tokens (windows above IME can be attached here)
+ * - DisplayArea.Tokens (windows above Tasks up to IME can be attached here)
+ * - ImeContainers
+ * - DisplayArea.Tokens (windows above IME up to TYPE_ACCESSIBILITY_OVERLAY can be
+ * attached here)
+ * - DisplayArea.Tokens (TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY and up can be attached
+ * here)
+ * </pre>
+ * When a {@link WindowToken} of Wallpaper needs to be attached, the policy will call the OEM
+ * defined {@link #mSelectRootForWindowFunc} to get a {@link RootDisplayArea}. It will then place
+ * the window to the corresponding {@link DisplayArea.Tokens} under the returned root
+ * {@link RootDisplayArea}.
*/
class DisplayAreaPolicyBuilder {
@Nullable private HierarchyBuilder mRootHierarchyBuilder;
@@ -396,7 +455,7 @@ class DisplayAreaPolicyBuilder {
/**
* Returns the id of the feature.
*
- * Must be unique among the features added to a {@link DisplayAreaPolicyBuilder}.
+ * <p>Must be unique among the features added to a {@link DisplayAreaPolicyBuilder}.
*
* @see android.window.DisplayAreaOrganizer#FEATURE_SYSTEM_FIRST
* @see android.window.DisplayAreaOrganizer#FEATURE_VENDOR_FIRST
@@ -425,7 +484,7 @@ class DisplayAreaPolicyBuilder {
* For example, {@code all().except(TYPE_STATUS_BAR)} expresses that a feature should
* apply to all types except TYPE_STATUS_BAR.
*
- * The builder starts out with the feature not applying to any types.
+ * <p>The builder starts out with the feature not applying to any types.
*
* @param name the name of the feature.
* @param id of the feature. {@see Feature#getId}
@@ -599,7 +658,7 @@ class DisplayAreaPolicyBuilder {
* Whether to skip creating a {@link DisplayArea.Tokens} if {@link #mExisting} is
* {@code null}.
*
- * This will be set for {@link HierarchyBuilder#LEAF_TYPE_IME_CONTAINERS} and
+ * <p>This will be set for {@link HierarchyBuilder#LEAF_TYPE_IME_CONTAINERS} and
* {@link HierarchyBuilder#LEAF_TYPE_TASK_CONTAINERS}, because we don't want to create
* {@link DisplayArea.Tokens} for them even if they are not set.
*/
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 0b1f4d9e1613..fc170538994c 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -1930,6 +1930,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
final DisplayInfo displayInfo = updateDisplayAndOrientation(config.uiMode, config);
calculateBounds(displayInfo, mTmpBounds);
config.windowConfiguration.setBounds(mTmpBounds);
+ config.windowConfiguration.setMaxBounds(mTmpBounds);
config.windowConfiguration.setWindowingMode(getWindowingMode());
config.windowConfiguration.setDisplayWindowingMode(getWindowingMode());
@@ -2544,10 +2545,6 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
return mDisplayAreaPolicy.getDefaultTaskDisplayArea();
}
- void positionDisplayAt(int position, boolean includingParents) {
- getParent().positionChildAt(position, this, includingParents);
- }
-
/**
* Returns true if the input point is within an app window.
*/
@@ -5393,6 +5390,11 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
});
}
+ @Override
+ public boolean providesMaxBounds() {
+ return true;
+ }
+
/** The entry for proceeding to handle {@link #mFixedRotationLaunchingApp}. */
class FixedRotationTransitionListener extends WindowManagerInternal.AppTransitionListener {
@@ -5403,6 +5405,9 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
*/
private ActivityRecord mAnimatingRecents;
+ /** Whether {@link #mAnimatingRecents} is going to be the top activity. */
+ private boolean mRecentsWillBeTop;
+
/**
* If the recents activity has a fixed orientation which is different from the current top
* activity, it will be rotated before being shown so we avoid a screen rotation animation
@@ -5428,10 +5433,12 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
* If {@link #mAnimatingRecents} still has fixed rotation, it should be moved to top so we
* don't clear {@link #mFixedRotationLaunchingApp} that will be handled by transition.
*/
- void onFinishRecentsAnimation(boolean moveRecentsToBack) {
+ void onFinishRecentsAnimation() {
final ActivityRecord animatingRecents = mAnimatingRecents;
+ final boolean recentsWillBeTop = mRecentsWillBeTop;
mAnimatingRecents = null;
- if (!moveRecentsToBack) {
+ mRecentsWillBeTop = false;
+ if (recentsWillBeTop) {
// The recents activity will be the top, such as staying at recents list or
// returning to home (if home and recents are the same activity).
return;
@@ -5454,6 +5461,10 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
}
}
+ void notifyRecentsWillBeTop() {
+ mRecentsWillBeTop = true;
+ }
+
/**
* Return {@code true} if there is an ongoing animation to the "Recents" activity and this
* activity as a fixed orientation so shouldn't be rotated.
@@ -5474,6 +5485,14 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
if (r == null || r == mAnimatingRecents) {
return;
}
+ if (mAnimatingRecents != null && mRecentsWillBeTop) {
+ // The activity is not the recents and it should be moved to back later, so it is
+ // better to keep its current appearance for the next transition. Otherwise the
+ // display orientation may be updated too early and the layout procedures at the
+ // end of finishing recents animation is skipped. That causes flickering because
+ // the surface of closing app hasn't updated to invisible.
+ return;
+ }
if (mFixedRotationLaunchingApp == null) {
// In most cases this is a no-op if the activity doesn't have fixed rotation.
// Otherwise it could be from finishing recents animation while the display has
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 0e24fc8bd307..4f6f75d924c4 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -356,6 +356,8 @@ public class DisplayPolicy {
private WindowState mFocusedWindow;
private WindowState mLastFocusedWindow;
+ private WindowState mSystemUiControllingWindow;
+
// The states of decor windows from the last layout. These are used to generate another display
// layout in different bounds but with the same states.
private boolean mLastNavVisible;
@@ -3436,6 +3438,7 @@ public class DisplayPolicy {
}
}
final WindowState win = winCandidate;
+ mSystemUiControllingWindow = win;
mDisplayContent.getInsetsPolicy().updateBarControlTarget(win);
@@ -3740,8 +3743,12 @@ public class DisplayPolicy {
& WindowManager.LayoutParams.FLAG_FULLSCREEN) != 0;
final boolean hideStatusBarSysui =
(vis & View.SYSTEM_UI_FLAG_FULLSCREEN) != 0;
- final boolean hideNavBarSysui =
- (vis & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0;
+ final boolean hideNavBarSysui = (vis & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0
+ // We shouldn't rely on the system UI visibilities anymore because the window can
+ // use the new API (e.g., WindowInsetsController.hide) to hide navigation bar.
+ // TODO(b/149813814): clean up the system UI flag usages in this function.
+ || !win.getRequestedInsetsState().getSourceOrDefaultVisibility(
+ ITYPE_NAVIGATION_BAR);
final boolean transientStatusBarAllowed = getStatusBar() != null
&& (notificationShadeHasFocus || (!mForceShowSystemBars
@@ -3755,15 +3762,16 @@ public class DisplayPolicy {
&& now - mPendingPanicGestureUptime <= PANIC_GESTURE_EXPIRATION;
final DisplayPolicy defaultDisplayPolicy =
mService.getDefaultDisplayContentLocked().getDisplayPolicy();
- if (pendingPanic && hideNavBarSysui && !isKeyguardShowing()
+ if (pendingPanic && hideNavBarSysui && win != mNotificationShade
+ && getInsetsPolicy().isHidden(ITYPE_NAVIGATION_BAR)
// TODO (b/111955725): Show keyguard presentation on all external displays
&& defaultDisplayPolicy.isKeyguardDrawComplete()) {
// The user performed the panic gesture recently, we're about to hide the bars,
// we're no longer on the Keyguard and the screen is ready. We can now request the bars.
mPendingPanicGestureUptime = 0;
- mStatusBarController.showTransient();
if (!isNavBarEmpty(vis)) {
- mNavigationBarController.showTransient();
+ mDisplayContent.getInsetsPolicy().showTransient(IntArray.wrap(
+ new int[] {ITYPE_NAVIGATION_BAR}));
}
}
@@ -3908,6 +3916,9 @@ public class DisplayPolicy {
}
private boolean isImmersiveMode(WindowState win) {
+ if (win == null) {
+ return false;
+ }
final int behavior = win.mAttrs.insetsFlags.behavior;
return getNavigationBar() != null
&& canHideNavigationBar()
@@ -3942,11 +3953,7 @@ public class DisplayPolicy {
return;
}
mPendingPanicGestureUptime = SystemClock.uptimeMillis();
- if (!isNavBarEmpty(mLastSystemUiFlags)) {
- mNavigationBarController.showTransient();
- mDisplayContent.getInsetsPolicy().showTransient(IntArray.wrap(
- new int[] {ITYPE_NAVIGATION_BAR}));
- }
+ updateSystemUiVisibilityLw();
}
}
};
@@ -3955,7 +3962,7 @@ public class DisplayPolicy {
// Detect user pressing the power button in panic when an application has
// taken over the whole screen.
boolean panic = mImmersiveModeConfirmation.onPowerKeyDown(isScreenOn,
- SystemClock.elapsedRealtime(), isImmersiveMode(mLastSystemUiFlags),
+ SystemClock.elapsedRealtime(), isImmersiveMode(mSystemUiControllingWindow),
isNavBarEmpty(mLastSystemUiFlags));
if (panic) {
mHandler.post(mHiddenNavPanic);
diff --git a/services/core/java/com/android/server/wm/InputConsumerImpl.java b/services/core/java/com/android/server/wm/InputConsumerImpl.java
index 3b39b6ba18c5..852b367259c1 100644
--- a/services/core/java/com/android/server/wm/InputConsumerImpl.java
+++ b/services/core/java/com/android/server/wm/InputConsumerImpl.java
@@ -88,6 +88,7 @@ class InputConsumerImpl implements IBinder.DeathRecipient {
mWindowHandle.ownerUid = Process.myUid();
mWindowHandle.inputFeatures = 0;
mWindowHandle.scaleFactor = 1.0f;
+ mWindowHandle.trustedOverlay = true;
mInputSurface = mService.makeSurfaceBuilder(mService.mRoot.getDisplayContent(displayId).getSession())
.setContainerLayer()
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index 0216db471843..20f1b9f53013 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -27,7 +27,18 @@ import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
import static android.view.WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_DISABLE_WALLPAPER_TOUCH_EVENTS;
+import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY;
+import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY;
+import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
+import static android.view.WindowManager.LayoutParams.TYPE_INPUT_CONSUMER;
+import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
+import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
+import static android.view.WindowManager.LayoutParams.TYPE_MAGNIFICATION_OVERLAY;
+import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
+import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL;
+import static android.view.WindowManager.LayoutParams.TYPE_NOTIFICATION_SHADE;
import static android.view.WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY;
+import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_FOCUS_LIGHT;
@@ -67,9 +78,6 @@ final class InputMonitor {
private boolean mUpdateInputWindowsPending;
private boolean mUpdateInputWindowsImmediately;
- // Currently focused input window handle.
- private InputWindowHandle mFocusedInputWindowHandle;
-
private boolean mDisableWallpaperTouchEvents;
private final Rect mTmpRect = new Rect();
private final UpdateInputForAllWindowsConsumer mUpdateInputForAllWindowsConsumer;
@@ -309,10 +317,6 @@ final class InputMonitor {
Slog.d(TAG_WM, "addInputWindowHandle: "
+ child + ", " + inputWindowHandle);
}
-
- if (hasFocus) {
- mFocusedInputWindowHandle = inputWindowHandle;
- }
}
void setUpdateInputWindowsNeededLw() {
@@ -578,6 +582,7 @@ final class InputMonitor {
inputWindowHandle.portalToDisplayId = INVALID_DISPLAY;
inputWindowHandle.touchableRegion.setEmpty();
inputWindowHandle.setTouchableRegionCrop(null);
+ inputWindowHandle.trustedOverlay = isTrustedOverlay(type);
}
/**
@@ -592,4 +597,17 @@ final class InputMonitor {
populateOverlayInputInfo(inputWindowHandle, name, TYPE_SECURE_SYSTEM_OVERLAY, true);
t.setInputWindowInfo(sc, inputWindowHandle);
}
+
+ static boolean isTrustedOverlay(int type) {
+ return type == TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY
+ || type == TYPE_INPUT_METHOD || type == TYPE_INPUT_METHOD_DIALOG
+ || type == TYPE_MAGNIFICATION_OVERLAY || type == TYPE_STATUS_BAR
+ || type == TYPE_NOTIFICATION_SHADE
+ || type == TYPE_NAVIGATION_BAR
+ || type == TYPE_NAVIGATION_BAR_PANEL
+ || type == TYPE_SECURE_SYSTEM_OVERLAY
+ || type == TYPE_DOCK_DIVIDER
+ || type == TYPE_ACCESSIBILITY_OVERLAY
+ || type == TYPE_INPUT_CONSUMER;
+ }
}
diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index f5bd4cd866a6..6b3a5d6bf18c 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -702,6 +702,11 @@ public class RecentsAnimationController implements DeathRecipient {
"cleanupAnimation(): Notify animation finished mPendingAnimations=%d "
+ "reorderMode=%d",
mPendingAnimations.size(), reorderMode);
+ if (reorderMode != REORDER_MOVE_TO_ORIGINAL_POSITION) {
+ // Notify the state at the beginning because the removeAnimation may notify the
+ // transition is finished. This is a signal that there will be a next transition.
+ mDisplayContent.mFixedRotationTransitionListener.notifyRecentsWillBeTop();
+ }
for (int i = mPendingAnimations.size() - 1; i >= 0; i--) {
final TaskAnimationAdapter taskAdapter = mPendingAnimations.get(i);
if (reorderMode == REORDER_MOVE_TO_TOP || reorderMode == REORDER_KEEP_IN_PLACE) {
@@ -742,8 +747,7 @@ public class RecentsAnimationController implements DeathRecipient {
mTargetActivityRecord.token);
}
}
- mDisplayContent.mFixedRotationTransitionListener.onFinishRecentsAnimation(
- reorderMode == REORDER_MOVE_TO_ORIGINAL_POSITION /* moveRecentsToBack */);
+ mDisplayContent.mFixedRotationTransitionListener.onFinishRecentsAnimation();
// Notify that the animation has ended
if (mStatusBar != null) {
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index e6e92ea9e489..897b68073bd2 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -129,7 +129,6 @@ import static com.android.server.wm.Task.ActivityState.STARTED;
import static com.android.server.wm.Task.ActivityState.STOPPED;
import static com.android.server.wm.Task.ActivityState.STOPPING;
import static com.android.server.wm.TaskProto.ACTIVITY_TYPE;
-import static com.android.server.wm.TaskProto.ANIMATING_BOUNDS;
import static com.android.server.wm.TaskProto.BOUNDS;
import static com.android.server.wm.TaskProto.CREATED_BY_ORGANIZER;
import static com.android.server.wm.TaskProto.DISPLAY_ID;
@@ -600,16 +599,6 @@ class Task extends WindowContainer<WindowContainer> {
SurfaceControl.Transaction mMainWindowSizeChangeTransaction;
Task mMainWindowSizeChangeTask;
- // If this is true, we are in the bounds animating mode. The task will be down or upscaled to
- // perfectly fit the region it would have been cropped to. We may also avoid certain logic we
- // would otherwise apply while resizing, while resizing in the bounds animating mode.
- private boolean mBoundsAnimating = false;
- // Set when an animation has been requested but has not yet started from the UI thread. This is
- // cleared when the animation actually starts.
- private boolean mBoundsAnimatingRequested = false;
- private Rect mBoundsAnimationTarget = new Rect();
- private Rect mBoundsAnimationSourceHintBounds = new Rect();
-
Rect mPreAnimationBounds = new Rect();
private final AnimatingActivityRegistry mAnimatingActivityRegistry =
@@ -2384,6 +2373,15 @@ class Task extends WindowContainer<WindowContainer> {
saveLaunchingStateIfNeeded();
final boolean taskOrgChanged = updateTaskOrganizerState(false /* forceUpdate */);
+ if (taskOrgChanged) {
+ updateSurfacePosition(getSyncTransaction());
+ if (!isOrganized()) {
+ // Surface-size update was skipped before (since internally it no-ops if
+ // isOrganized() is true); however, now that this is not organized, the surface
+ // size needs to be updated by WM.
+ updateSurfaceSize(getSyncTransaction());
+ }
+ }
// If the task organizer has changed, then it will already be receiving taskAppeared with
// the latest task-info thus the task-info won't have changed.
if (!taskOrgChanged && isOrganized()) {
@@ -2459,7 +2457,7 @@ class Task extends WindowContainer<WindowContainer> {
// Since always on top is only on when the stack is freeform or pinned, the state
// can be toggled when the windowing mode changes. We must make sure the stack is
// placed properly when always on top state changes.
- taskDisplayArea.positionStackAtTop(this, false /* includingParents */);
+ taskDisplayArea.positionChildAt(POSITION_TOP, this, false /* includingParents */);
}
}
@@ -3367,7 +3365,7 @@ class Task extends WindowContainer<WindowContainer> {
final int boundsChange = super.setBounds(bounds);
mRotation = rotation;
- updateSurfacePosition();
+ updateSurfacePositionNonOrganized();
return boundsChange;
}
@@ -3732,14 +3730,9 @@ class Task extends WindowContainer<WindowContainer> {
}
@Override
- public SurfaceControl getAnimationLeashParent() {
- if (WindowManagerService.sHierarchicalAnimations) {
- return super.getAnimationLeashParent();
- }
- // Currently, only the recents animation will create animation leashes for tasks. In this
- // case, reparent the task to the home animation layer while it is being animated to allow
- // the home activity to reorder the app windows relative to its own.
- return getAppAnimationLayer(ANIMATION_LAYER_HOME);
+ void resetSurfacePositionForAnimationLeash(SurfaceControl.Transaction t) {
+ if (isOrganized()) return;
+ super.resetSurfacePositionForAnimationLeash(t);
}
@Override
@@ -4960,7 +4953,9 @@ class Task extends WindowContainer<WindowContainer> {
*/
boolean updateTaskOrganizerState(boolean forceUpdate) {
if (!isRootTask()) {
- return false;
+ final boolean result = setTaskOrganizer(null);
+ mLastTaskOrganizerWindowingMode = -1;
+ return result;
}
final int windowingMode = getWindowingMode();
@@ -4979,7 +4974,7 @@ class Task extends WindowContainer<WindowContainer> {
final ITaskOrganizer org =
mWmService.mAtmService.mTaskOrganizerController.getTaskOrganizer(windowingMode);
final boolean result = setTaskOrganizer(org);
- mLastTaskOrganizerWindowingMode = windowingMode;
+ mLastTaskOrganizerWindowingMode = org != null ? windowingMode : -1;
return result;
}
@@ -5340,7 +5335,8 @@ class Task extends WindowContainer<WindowContainer> {
}
if (isRootTask()) {
- taskDisplayArea.positionStackAtTop(this, false /* includingParents */, reason);
+ taskDisplayArea.positionChildAt(POSITION_TOP, this, false /* includingParents */,
+ reason);
}
if (task == null) {
task = this;
@@ -5368,7 +5364,8 @@ class Task extends WindowContainer<WindowContainer> {
if (parentTask != null) {
parentTask.moveToBack(reason, this);
} else {
- displayArea.positionStackAtBottom(this, reason);
+ displayArea.positionChildAt(POSITION_BOTTOM, this, false /*includingParents*/,
+ reason);
}
if (task != null && task != this) {
positionChildAtBottom(task);
@@ -7113,14 +7110,6 @@ class Task extends WindowContainer<WindowContainer> {
forAllTasks(c, true /* traverseTopToBottom */);
c.recycle();
- if (mBoundsAnimating) {
- // Force to update task surface bounds and relayout windows, since configBounds
- // remains unchanged during bounds animation.
- updateSurfaceBounds();
- getDisplay().setLayoutNeeded();
- mWmService.requestTraversal();
- }
-
if (!deferResume) {
ensureVisibleActivitiesConfiguration(topRunningActivity(), preserveWindows);
}
@@ -7448,7 +7437,7 @@ class Task extends WindowContainer<WindowContainer> {
// always on top windows. Since the position the stack should be inserted into is calculated
// properly in {@link DisplayContent#getTopInsertPosition()} in both cases, we can just
// request that the stack is put at top here.
- taskDisplayArea.positionStackAtTop(this, false /* includingParents */);
+ taskDisplayArea.positionChildAt(POSITION_TOP, this, false /* includingParents */);
}
/** NOTE: Should only be called from {@link Task#reparent}. */
@@ -7493,7 +7482,7 @@ class Task extends WindowContainer<WindowContainer> {
final Task task = getBottomMostTask();
setWindowingMode(WINDOWING_MODE_UNDEFINED);
- getDisplayArea().positionStackAtTop(this, false /* includingParents */);
+ getDisplayArea().positionChildAt(POSITION_TOP, this, false /* includingParents */);
mStackSupervisor.scheduleUpdatePictureInPictureModeIfNeeded(task, this);
MetricsLoggerWrapper.logPictureInPictureFullScreen(mAtmService.mContext,
@@ -7522,20 +7511,6 @@ class Task extends WindowContainer<WindowContainer> {
}
/**
- * @return the final bounds for the bounds animation.
- */
- void getFinalAnimationBounds(Rect outBounds) {
- outBounds.set(mBoundsAnimationTarget);
- }
-
- /**
- * @return the final source bounds for the bounds animation.
- */
- void getFinalAnimationSourceHintBounds(Rect outBounds) {
- outBounds.set(mBoundsAnimationSourceHintBounds);
- }
-
- /**
* Put a Task in this stack. Used for adding only.
* When task is added to top of the stack, the entire branch of the hierarchy (including stack
* and display) will be brought to top.
@@ -7619,7 +7594,7 @@ class Task extends WindowContainer<WindowContainer> {
private void updateSurfaceBounds() {
updateSurfaceSize(getSyncTransaction());
- updateSurfacePosition();
+ updateSurfacePositionNonOrganized();
scheduleAnimation();
}
@@ -7690,10 +7665,6 @@ class Task extends WindowContainer<WindowContainer> {
getDisplayContent().getPinnedStackController().setActions(actions);
}
- public boolean isForceScaled() {
- return mBoundsAnimating;
- }
-
/** Returns true if a removal action is still being deferred. */
boolean handleCompleteDeferredRemoval() {
if (isAnimating(TRANSITION | CHILDREN)) {
@@ -7780,8 +7751,6 @@ class Task extends WindowContainer<WindowContainer> {
mLastNonFullscreenBounds.dumpDebug(proto, LAST_NON_FULLSCREEN_BOUNDS);
}
- proto.write(ANIMATING_BOUNDS, mBoundsAnimating);
-
if (mSurfaceControl != null) {
proto.write(SURFACE_WIDTH, mSurfaceControl.getWidth());
proto.write(SURFACE_HEIGHT, mSurfaceControl.getHeight());
diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java
index 4473bd69681b..a847744247c7 100644
--- a/services/core/java/com/android/server/wm/TaskDisplayArea.java
+++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java
@@ -303,15 +303,18 @@ final class TaskDisplayArea extends DisplayArea<Task> {
}
@Override
- void addChild(Task stack, int position) {
- if (DEBUG_STACK) Slog.d(TAG_WM, "Set stack=" + stack + " on taskDisplayArea=" + this);
- addStackReferenceIfNeeded(stack);
- position = findPositionForStack(position, stack, true /* adding */);
+ void addChild(Task task, int position) {
+ if (DEBUG_STACK) Slog.d(TAG_WM, "Set task=" + task + " on taskDisplayArea=" + this);
+ if (mDisplayContent.mSingleTaskInstance && getStackCount() == 1) {
+ throw new IllegalStateException("addChild: Can only have one task on display=" + this);
+ }
- super.addChild(stack, position);
- mAtmService.updateSleepIfNeededLocked();
+ addStackReferenceIfNeeded(task);
+ position = findPositionForStack(position, task, true /* adding */);
- positionStackAt(stack, position);
+ super.addChild(task, position);
+ mAtmService.updateSleepIfNeededLocked();
+ onStackOrderChanged(task);
}
@Override
@@ -328,19 +331,42 @@ final class TaskDisplayArea extends DisplayArea<Task> {
return true;
}
+ void positionChildAt(int position, Task child, boolean includingParents,
+ String updateLastFocusedTaskReason) {
+ final Task prevFocusedTask = updateLastFocusedTaskReason != null ? getFocusedStack() : null;
+
+ positionChildAt(position, child, includingParents);
+
+ if (updateLastFocusedTaskReason == null) {
+ return;
+ }
+
+ final Task currentFocusedStack = getFocusedStack();
+ if (currentFocusedStack == prevFocusedTask) {
+ return;
+ }
+
+ mLastFocusedStack = prevFocusedTask;
+ EventLogTags.writeWmFocusedStack(mRootWindowContainer.mCurrentUser,
+ mDisplayContent.mDisplayId,
+ currentFocusedStack == null ? -1 : currentFocusedStack.getRootTaskId(),
+ mLastFocusedStack == null ? -1 : mLastFocusedStack.getRootTaskId(),
+ updateLastFocusedTaskReason);
+ }
+
@Override
void positionChildAt(int position, Task child, boolean includingParents) {
final boolean moveToTop = position >= getChildCount() - 1;
final boolean moveToBottom = position <= 0;
+ final int oldPosition = mChildren.indexOf(child);
if (child.getWindowConfiguration().isAlwaysOnTop() && !moveToTop) {
// This stack is always-on-top, override the default behavior.
Slog.w(TAG_WM, "Ignoring move of always-on-top stack=" + this + " to bottom");
// Moving to its current position, as we must call super but we don't want to
// perform any meaningful action.
- final int currentPosition = mChildren.indexOf(child);
- super.positionChildAt(currentPosition, child, false /* includingParents */);
+ super.positionChildAt(oldPosition, child, false /* includingParents */);
return;
}
// We don't allow untrusted display to top when task stack moves to top,
@@ -358,7 +384,7 @@ final class TaskDisplayArea extends DisplayArea<Task> {
child.updateTaskMovement(moveToTop);
- mDisplayContent.setLayoutNeeded();
+ mDisplayContent.layoutAndAssignWindowLayersIfNeeded();
// The insert position may be adjusted to non-top when there is always-on-top stack. Since
// the original position is preferred to be top, the stack should have higher priority when
@@ -373,6 +399,10 @@ final class TaskDisplayArea extends DisplayArea<Task> {
// Update the top resumed activity because the preferred top focusable task may be changed.
mAtmService.mStackSupervisor.updateTopResumedActivityIfNeeded();
+
+ if (mChildren.indexOf(child) != oldPosition) {
+ onStackOrderChanged(child);
+ }
}
@Override
@@ -800,66 +830,6 @@ final class TaskDisplayArea extends DisplayArea<Task> {
}
}
- void positionStackAt(int position, Task child, boolean includingParents) {
- positionChildAt(position, child, includingParents);
- mDisplayContent.layoutAndAssignWindowLayersIfNeeded();
- }
-
- void positionStackAtTop(Task stack, boolean includingParents) {
- positionStackAtTop(stack, includingParents, null /* updateLastFocusedStackReason */);
- }
-
- void positionStackAtTop(Task stack, boolean includingParents,
- String updateLastFocusedStackReason) {
- positionStackAt(stack, getStackCount(), includingParents,
- updateLastFocusedStackReason);
- }
-
- void positionStackAtBottom(Task stack) {
- positionStackAtBottom(stack, null /* updateLastFocusedStackReason */);
- }
-
- void positionStackAtBottom(Task stack, String updateLastFocusedStackReason) {
- positionStackAt(stack, 0, false /* includingParents */,
- updateLastFocusedStackReason);
- }
-
- void positionStackAt(Task stack, int position) {
- positionStackAt(stack, position, false /* includingParents */,
- null /* updateLastFocusedStackReason */);
- }
-
- void positionStackAt(Task stack, int position, boolean includingParents,
- String updateLastFocusedStackReason) {
- // TODO: Keep in sync with WindowContainer.positionChildAt(), once we change that to adjust
- // the position internally, also update the logic here
- final Task prevFocusedStack = updateLastFocusedStackReason != null
- ? getFocusedStack() : null;
- final boolean wasContained = mChildren.contains(stack);
- if (mDisplayContent.mSingleTaskInstance && getStackCount() == 1 && !wasContained) {
- throw new IllegalStateException(
- "positionStackAt: Can only have one task on display=" + this);
- }
-
- // Since positionChildAt() is called during the creation process of pinned stacks,
- // ActivityStack#getStack() can be null.
- positionStackAt(position, stack, includingParents);
-
- if (updateLastFocusedStackReason != null) {
- final Task currentFocusedStack = getFocusedStack();
- if (currentFocusedStack != prevFocusedStack) {
- mLastFocusedStack = prevFocusedStack;
- EventLogTags.writeWmFocusedStack(mRootWindowContainer.mCurrentUser,
- mDisplayContent.mDisplayId,
- currentFocusedStack == null ? -1 : currentFocusedStack.getRootTaskId(),
- mLastFocusedStack == null ? -1 : mLastFocusedStack.getRootTaskId(),
- updateLastFocusedStackReason);
- }
- }
-
- onStackOrderChanged(stack);
- }
-
/**
* Moves/reparents `task` to the back of whatever container the home stack is in. This is for
* when we just want to move a task to "the back" vs. a specific place. The primary use-case
@@ -872,7 +842,7 @@ final class TaskDisplayArea extends DisplayArea<Task> {
if (homeParentTask == null) {
// reparent throws if parent didn't change...
if (task.getParent() == this) {
- positionStackAtBottom(task);
+ positionChildAt(POSITION_BOTTOM, task, false /*includingParents*/);
} else {
task.reparent(this, false /* onTop */);
}
@@ -1091,7 +1061,7 @@ final class TaskDisplayArea extends DisplayArea<Task> {
if (launchRootTask != null) {
launchRootTask.addChild(stack, onTop ? POSITION_TOP : POSITION_BOTTOM);
if (onTop) {
- positionStackAtTop(launchRootTask, false /* includingParents */);
+ positionChildAt(POSITION_TOP, launchRootTask, false /* includingParents */);
}
} else {
addChild(stack, onTop ? POSITION_TOP : POSITION_BOTTOM);
@@ -1324,7 +1294,13 @@ final class TaskDisplayArea extends DisplayArea<Task> {
}
void onSplitScreenModeDismissed() {
- onSplitScreenModeDismissed(null /* toTop */);
+ // The focused task could be a non-resizeable fullscreen root task that is on top of the
+ // other split-screen tasks, therefore had to dismiss split-screen, make sure the current
+ // focused root task can still be on top after dismissal
+ final Task rootTask = getFocusedStack();
+ final Task toTop =
+ rootTask != null && !rootTask.inSplitScreenWindowingMode() ? rootTask : null;
+ onSplitScreenModeDismissed(toTop);
}
void onSplitScreenModeDismissed(Task toTop) {
@@ -1666,15 +1642,11 @@ final class TaskDisplayArea extends DisplayArea<Task> {
return;
}
- final boolean isRootTask = stack.isRootTask();
- if (isRootTask) {
- // Move the stack to the bottom to not affect the following visibility checks
- positionStackAtBottom(stack);
- } else {
- stack.getParent().positionChildAt(POSITION_BOTTOM, stack, false /* includingParents */);
- }
+ // Move the stack to the bottom to not affect the following visibility checks
+ stack.getParent().positionChildAt(POSITION_BOTTOM, stack, false /* includingParents */);
// Find the next position where the stack should be placed
+ final boolean isRootTask = stack.isRootTask();
final int numStacks = isRootTask ? getStackCount() : stack.getParent().getChildCount();
for (int stackNdx = 0; stackNdx < numStacks; stackNdx++) {
final Task s = isRootTask ? getStackAt(stackNdx)
@@ -1688,11 +1660,7 @@ final class TaskDisplayArea extends DisplayArea<Task> {
if (s.shouldBeVisible(null) && isValidWindowingMode) {
// Move the provided stack to behind this stack
final int position = Math.max(0, stackNdx - 1);
- if (isRootTask) {
- positionStackAt(stack, position);
- } else {
- stack.getParent().positionChildAt(position, stack, false /*includingParents */);
- }
+ stack.getParent().positionChildAt(position, stack, false /*includingParents */);
break;
}
}
@@ -1722,11 +1690,7 @@ final class TaskDisplayArea extends DisplayArea<Task> {
final int insertIndex = stackIndex <= behindStackIndex
? behindStackIndex - 1 : behindStackIndex;
final int position = Math.max(0, insertIndex);
- if (stack.isRootTask()) {
- positionStackAt(stack, position);
- } else {
- parent.positionChildAt(position, stack, false /* includingParents */);
- }
+ parent.positionChildAt(position, stack, false /* includingParents */);
}
boolean hasPinnedTask() {
@@ -1880,6 +1844,10 @@ final class TaskDisplayArea extends DisplayArea<Task> {
return lastReparentedStack;
}
+ @Override
+ protected boolean isTaskDisplayArea() {
+ return true;
+ }
@Override
void dump(PrintWriter pw, String prefix, boolean dumpAll) {
diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java
index 9d0bac9dd290..6377a2169b34 100644
--- a/services/core/java/com/android/server/wm/WindowAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowAnimator.java
@@ -68,7 +68,6 @@ public class WindowAnimator {
Object mLastWindowFreezeSource;
SparseArray<DisplayContentsAnimator> mDisplayContentsAnimators = new SparseArray<>(2);
-
private boolean mInitialized = false;
// When set to true the animator will go over all windows after an animation frame is posted and
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index d0785ff9a9ac..a3a4e407fffd 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -51,7 +51,6 @@ import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import static com.android.server.wm.WindowManagerService.logWithStack;
-import static com.android.server.wm.WindowManagerService.sHierarchicalAnimations;
import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_AFTER_ANIM;
import android.annotation.CallSuper;
@@ -320,7 +319,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
@Override
public void onConfigurationChanged(Configuration newParentConfig) {
super.onConfigurationChanged(newParentConfig);
- updateSurfacePosition();
+ updateSurfacePositionNonOrganized();
scheduleAnimation();
}
@@ -418,7 +417,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
setSurfaceControl(b.setCallsite("WindowContainer.setInitialSurfaceControlProperties").build());
getSyncTransaction().show(mSurfaceControl);
onSurfaceShown(getSyncTransaction());
- updateSurfacePosition();
+ updateSurfacePositionNonOrganized();
}
/**
@@ -2022,7 +2021,9 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
}
protected void reparentSurfaceControl(Transaction t, SurfaceControl newParent) {
- mSurfaceAnimator.reparent(t, newParent);
+ // Don't reparent active leashes since the animator won't know about the change.
+ if (mSurfaceFreezer.hasLeash() || mSurfaceAnimator.hasLeash()) return;
+ t.reparent(getSurfaceControl(), newParent);
}
void assignChildLayers(Transaction t) {
@@ -2364,10 +2365,6 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
final Rect screenBounds = getAnimationBounds(appStackClipMode);
mTmpRect.set(screenBounds);
getAnimationPosition(mTmpPoint);
- if (!sHierarchicalAnimations) {
- // Non-hierarchical animation uses position in global coordinates.
- mTmpPoint.set(mTmpRect.left, mTmpRect.top);
- }
mTmpRect.offsetTo(0, 0);
final RemoteAnimationController controller =
@@ -2703,14 +2700,19 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
}
}
- final void updateSurfacePosition() {
+ final void updateSurfacePositionNonOrganized() {
+ // Avoid fighting with the organizer over Surface position.
+ if (isOrganized()) return;
updateSurfacePosition(getSyncTransaction());
}
+ /**
+ * Only for use internally (see PROTECTED annotation). This should only be used over
+ * {@link #updateSurfacePositionNonOrganized} when the surface position needs to be
+ * updated even if organized (eg. while changing to organized).
+ */
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PROTECTED)
void updateSurfacePosition(Transaction t) {
- // Avoid fighting with the organizer over Surface position.
- if (isOrganized()) return;
-
if (mSurfaceControl == null || mSurfaceAnimator.hasLeash()) {
return;
}
@@ -2750,13 +2752,6 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
}
void getRelativePosition(Point outPos) {
- // In addition to updateSurfacePosition, we keep other code that sets
- // position from fighting with the organizer
- if (isOrganized()) {
- outPos.set(0, 0);
- return;
- }
-
final Rect dispBounds = getBounds();
outPos.set(dispBounds.left, dispBounds.top);
final WindowContainer parent = getParent();
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 2dd25c969d0d..9acaa9eca245 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -395,25 +395,9 @@ public class WindowManagerService extends IWindowManager.Stub
// trying to apply a new one.
private static final boolean ALWAYS_KEEP_CURRENT = true;
- /**
- * If set, new app transition framework which supports setting animation on any element
- * in a surface is used.
- * <p>
- * Only set this to non-zero once the new app transition framework is productionalized.
- * </p>
- */
- private static final String HIERARCHICAL_ANIMATIONS_PROPERTY =
- "persist.wm.hierarchical_animations";
-
private static final String DISABLE_TRIPLE_BUFFERING_PROPERTY =
"ro.sf.disable_triple_buffer";
- /**
- * @see #HIERARCHICAL_ANIMATIONS_PROPERTY
- */
- static boolean sHierarchicalAnimations =
- SystemProperties.getBoolean(HIERARCHICAL_ANIMATIONS_PROPERTY, true);
-
static boolean sEnableTripleBuffering = !SystemProperties.getBoolean(
DISABLE_TRIPLE_BUFFERING_PROPERTY, false);
@@ -2931,8 +2915,8 @@ public class WindowManagerService extends IWindowManager.Stub
synchronized (mGlobalLock) {
final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
if (displayContent != null && mRoot.getTopChild() != displayContent) {
- displayContent.positionDisplayAt(WindowContainer.POSITION_TOP,
- true /* includingParents */);
+ displayContent.getParent().positionChildAt(WindowContainer.POSITION_TOP,
+ displayContent, true /* includingParents */);
}
}
syncInputTransactions();
@@ -8017,7 +8001,7 @@ public class WindowManagerService extends IWindowManager.Stub
final DisplayContent displayContent = touchedWindow.getDisplayContent();
if (!displayContent.isOnTop()) {
- displayContent.positionDisplayAt(WindowContainer.POSITION_TOP,
+ displayContent.getParent().positionChildAt(WindowContainer.POSITION_TOP, displayContent,
true /* includingParents */);
}
handleTaskFocusChange(touchedWindow.getTask());
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index 4c5ac937b988..d25a64890337 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -241,13 +241,26 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
final int configMask = change.getConfigSetMask() & CONTROLLABLE_CONFIGS;
final int windowMask = change.getWindowSetMask() & CONTROLLABLE_WINDOW_CONFIGS;
int effects = 0;
+ final int windowingMode = change.getWindowingMode();
if (configMask != 0) {
- Configuration c = new Configuration(container.getRequestedOverrideConfiguration());
- c.setTo(change.getConfiguration(), configMask, windowMask);
- container.onRequestedOverrideConfigurationChanged(c);
- // TODO(b/145675353): remove the following once we could apply new bounds to the
- // pinned stack together with its children.
- resizePinnedStackIfNeeded(container, configMask, windowMask, c);
+ if (windowingMode > -1 && windowingMode != container.getWindowingMode()) {
+ // Special handling for when we are setting a windowingMode in the same transaction.
+ // Setting the windowingMode is going to call onConfigurationChanged so we don't
+ // need it called right now. Additionally, some logic requires everything in the
+ // configuration to change at the same time (ie. surface-freezer requires bounds
+ // and mode to change at the same time).
+ final Configuration c = container.getRequestedOverrideConfiguration();
+ c.setTo(change.getConfiguration(), configMask, windowMask);
+ } else {
+ final Configuration c =
+ new Configuration(container.getRequestedOverrideConfiguration());
+ c.setTo(change.getConfiguration(), configMask, windowMask);
+ container.onRequestedOverrideConfigurationChanged(c);
+ // TODO(b/145675353): remove the following once we could apply new bounds to the
+ // pinned stack together with its children.
+ }
+ resizePinnedStackIfNeeded(container, configMask, windowMask,
+ container.getRequestedOverrideConfiguration());
effects |= TRANSACT_EFFECTS_CLIENT_CONFIG;
}
if ((change.getChangeMask() & WindowContainerTransaction.Change.CHANGE_FOCUSABLE) != 0) {
@@ -256,7 +269,6 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
}
}
- final int windowingMode = change.getWindowingMode();
if (windowingMode > -1) {
container.setWindowingMode(windowingMode);
}
@@ -345,29 +357,17 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
final Task rootTask = (Task) (
(newParent != null && !(newParent instanceof TaskDisplayArea))
? newParent : task.getRootTask());
- if (hop.getToTop()) {
- as.getDisplayArea().positionStackAtTop(rootTask,
- false /* includingParents */);
- } else {
- as.getDisplayArea().positionStackAtBottom(rootTask);
- }
+ as.getDisplayArea().positionChildAt(
+ hop.getToTop() ? POSITION_TOP : POSITION_BOTTOM, rootTask,
+ false /* includingParents */);
}
} else {
throw new RuntimeException("Reparenting leaf Tasks is not supported now. " + task);
}
} else {
- // Ugh, of course ActivityStack has its own special reorder logic...
- if (task.isRootTask()) {
- if (hop.getToTop()) {
- as.getDisplayArea().positionStackAtTop(as, false /* includingParents */);
- } else {
- as.getDisplayArea().positionStackAtBottom(as);
- }
- } else {
- task.getParent().positionChildAt(
- hop.getToTop() ? POSITION_TOP : POSITION_BOTTOM,
- task, false /* includingParents */);
- }
+ task.getParent().positionChildAt(
+ hop.getToTop() ? POSITION_TOP : POSITION_BOTTOM,
+ task, false /* includingParents */);
}
return TRANSACT_EFFECTS_LIFECYCLE;
}
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index da9c7f3ea1b5..6ba8769842f6 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -55,11 +55,14 @@ import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.ServiceInfo;
import android.content.res.Configuration;
+import android.os.Binder;
import android.os.Build;
+import android.os.IBinder;
import android.os.Message;
import android.os.Process;
import android.os.RemoteException;
import android.os.SystemClock;
+import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Log;
import android.util.Slog;
@@ -98,6 +101,11 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
final ApplicationInfo mInfo;
final String mName;
final int mUid;
+
+ // A set of tokens that currently contribute to this process being temporarily allowed
+ // to start activities even if it's not in the foreground. The values of this map are optional
+ // (can be null) and are used to trace back the grant to the notification token mechanism.
+ private final ArrayMap<Binder, IBinder> mBackgroundActivityStartTokens = new ArrayMap<>();
// The process of this application; 0 if none
private volatile int mPid;
// user of process.
@@ -160,9 +168,6 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
private volatile boolean mPerceptible;
// Set to true when process was launched with a wrapper attached
private volatile boolean mUsingWrapper;
- // Set to true if this process is currently temporarily allowed to start activities even if
- // it's not in the foreground
- private volatile boolean mAllowBackgroundActivityStarts;
// Set of UIDs of clients currently bound to this process
private volatile ArraySet<Integer> mBoundClientUids = new ArraySet<Integer>();
@@ -208,6 +213,9 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
/** Whether our process is currently running a {@link IRemoteAnimationRunner} */
private boolean mRunningRemoteAnimation;
+ @Nullable
+ private BackgroundActivityStartCallback mBackgroundActivityStartCallback;
+
public WindowProcessController(@NonNull ActivityTaskManagerService atm, ApplicationInfo info,
String name, int uid, int userId, Object owner, WindowProcessListener listener) {
mInfo = info;
@@ -218,6 +226,7 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
mListener = listener;
mAtm = atm;
mDisplayId = INVALID_DISPLAY;
+ mBackgroundActivityStartCallback = mAtm.getBackgroundActivityStartCallback();
boolean isSysUiPackage = info.packageName.equals(
mAtm.getSysUiServiceComponentLocked().getPackageName());
@@ -449,19 +458,39 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
mLastActivityFinishTime = finishTime;
}
- public void setAllowBackgroundActivityStarts(boolean allowBackgroundActivityStarts) {
- mAllowBackgroundActivityStarts = allowBackgroundActivityStarts;
+ /**
+ * Allows background activity starts using token {@code entity}. Optionally, you can provide
+ * {@code originatingToken} if you have one such originating token, this is useful for tracing
+ * back the grant in the case of the notification token.
+ */
+ public void addAllowBackgroundActivityStartsToken(Binder entity,
+ @Nullable IBinder originatingToken) {
+ synchronized (mAtm.mGlobalLock) {
+ mBackgroundActivityStartTokens.put(entity, originatingToken);
+ }
}
- boolean areBackgroundActivityStartsAllowed() {
- // allow if the flag was explicitly set
- if (mAllowBackgroundActivityStarts) {
- if (DEBUG_ACTIVITY_STARTS) {
- Slog.d(TAG, "[WindowProcessController(" + mPid
- + ")] Activity start allowed: mAllowBackgroundActivityStarts = true");
- }
- return true;
+ /**
+ * Removes token {@code entity} that allowed background activity starts added via {@link
+ * #addAllowBackgroundActivityStartsToken(Binder, IBinder)}.
+ */
+ public void removeAllowBackgroundActivityStartsToken(Binder entity) {
+ synchronized (mAtm.mGlobalLock) {
+ mBackgroundActivityStartTokens.remove(entity);
+ }
+ }
+
+ /**
+ * Returns true if background activity starts are allowed by any token added via {@link
+ * #addAllowBackgroundActivityStartsToken(Binder, IBinder)}.
+ */
+ public boolean areBackgroundActivityStartsAllowedByToken() {
+ synchronized (mAtm.mGlobalLock) {
+ return !mBackgroundActivityStartTokens.isEmpty();
}
+ }
+
+ boolean areBackgroundActivityStartsAllowed() {
// allow if any activity in the caller has either started or finished very recently, and
// it must be started or finished after last stop app switches time.
final long now = SystemClock.uptimeMillis();
@@ -510,9 +539,32 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
}
return true;
}
+ // allow if the flag was explicitly set
+ if (!mBackgroundActivityStartTokens.isEmpty()) {
+ onBackgroundStartAllowedByToken();
+ if (DEBUG_ACTIVITY_STARTS) {
+ Slog.d(TAG, "[WindowProcessController(" + mPid
+ + ")] Activity start allowed: process allowed by token");
+ }
+ return true;
+ }
return false;
}
+ private void onBackgroundStartAllowedByToken() {
+ if (mBackgroundActivityStartCallback == null) {
+ return;
+ }
+ IBinder callbackToken = mBackgroundActivityStartCallback.getToken();
+ for (IBinder token : mBackgroundActivityStartTokens.values()) {
+ if (token != callbackToken) {
+ return;
+ }
+ }
+ mAtm.mH.post(() ->
+ mBackgroundActivityStartCallback.onExclusiveTokenActivityStart(mInfo.packageName));
+ }
+
private boolean isBoundByForegroundUid() {
for (int i = mBoundClientUids.size() - 1; i >= 0; --i) {
if (mAtm.isUidForeground(mBoundClientUids.valueAt(i))) {
@@ -1434,6 +1486,13 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
if (mVrThreadTid != 0) {
pw.print(prefix); pw.print("mVrThreadTid="); pw.println(mVrThreadTid);
}
+ if (mBackgroundActivityStartTokens.size() > 0) {
+ pw.print(prefix); pw.println("Background activity start tokens:");
+ for (int i = 0; i < mBackgroundActivityStartTokens.size(); i++) {
+ pw.print(prefix); pw.print(" - ");
+ pw.println(mBackgroundActivityStartTokens.keyAt(i));
+ }
+ }
}
pw.println(prefix + " Configuration=" + getConfiguration());
pw.println(prefix + " OverrideConfiguration=" + getRequestedOverrideConfiguration());
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 9ab157210dbd..ef78420a3646 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -63,7 +63,6 @@ import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS;
import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY;
-import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY;
@@ -88,7 +87,6 @@ import static android.view.WindowManager.LayoutParams.TYPE_PRIORITY_PHONE;
import static android.view.WindowManager.LayoutParams.TYPE_PRIVATE_PRESENTATION;
import static android.view.WindowManager.LayoutParams.TYPE_SCREENSHOT;
import static android.view.WindowManager.LayoutParams.TYPE_SEARCH_BAR;
-import static android.view.WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_ADDITIONAL;
import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL;
@@ -954,17 +952,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
mInputWindowHandle.trustedOverlay =
(mAttrs.privateFlags & PRIVATE_FLAG_TRUSTED_OVERLAY) != 0
&& mOwnerCanAddInternalSystemWindow;
- mInputWindowHandle.trustedOverlay |=
- mAttrs.type == TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY
- || mAttrs.type == TYPE_INPUT_METHOD || mAttrs.type == TYPE_INPUT_METHOD_DIALOG
- || mAttrs.type == TYPE_MAGNIFICATION_OVERLAY || mAttrs.type == TYPE_STATUS_BAR
- || mAttrs.type == TYPE_NOTIFICATION_SHADE
- || mAttrs.type == TYPE_NAVIGATION_BAR
- || mAttrs.type == TYPE_NAVIGATION_BAR_PANEL
- || mAttrs.type == TYPE_SECURE_SYSTEM_OVERLAY
- || mAttrs.type == TYPE_DOCK_DIVIDER
- || mAttrs.type == TYPE_ACCESSIBILITY_OVERLAY
- || mAttrs.type == TYPE_INPUT_CONSUMER;
+ mInputWindowHandle.trustedOverlay |= InputMonitor.isTrustedOverlay(mAttrs.type);
// Make sure we initial all fields before adding to parentWindow, to prevent exception
// during onDisplayChanged.
@@ -5394,7 +5382,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
void prepareSurfaces() {
mIsDimming = false;
applyDims();
- updateSurfacePosition();
+ updateSurfacePositionNonOrganized();
// Send information to SufaceFlinger about the priority of the current window.
updateFrameRateSelectionPriorityIfNeeded();
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 77fee851889e..d0101adaabad 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -208,16 +208,6 @@ class WindowStateAnimator {
int mAttrType;
- boolean mForceScaleUntilResize;
-
- // WindowState.mHScale and WindowState.mVScale contain the
- // scale according to client specified layout parameters (e.g.
- // one layout size, with another surface size, creates such scaling).
- // Here we track an additional scaling factor used to follow stack
- // scaling (as in the case of the Pinned stack animation).
- float mExtraHScale = (float) 1.0;
- float mExtraVScale = (float) 1.0;
-
// An offset in pixel of the surface contents from the window position. Used for Wallpaper
// to provide the effect of scrolling within a large surface. We just use these values as
// a cache.
@@ -247,11 +237,6 @@ class WindowStateAnimator {
private final SurfaceControl.Transaction mPostDrawTransaction =
new SurfaceControl.Transaction();
- // Set to true after the first frame of the Pinned stack animation
- // and reset after the last to ensure we only reset mForceScaleUntilResize
- // once per animation.
- boolean mPipAnimationStarted = false;
-
private final Point mTmpPos = new Point();
WindowStateAnimator(final WindowState win) {
@@ -870,11 +855,6 @@ class WindowStateAnimator {
calculateSurfaceBounds(w, attrs, mTmpSize);
- mExtraHScale = (float) 1.0;
- mExtraVScale = (float) 1.0;
-
- boolean wasForceScaled = mForceScaleUntilResize;
-
// Once relayout has been called at least once, we need to make sure
// we only resize the client surface during calls to relayout. For
// clients which use indeterminate measure specs (MATCH_PARENT),
@@ -889,7 +869,6 @@ class WindowStateAnimator {
} else {
mSurfaceResized = false;
}
- mForceScaleUntilResize = mForceScaleUntilResize && !mSurfaceResized;
// If we are undergoing seamless rotation, the surface has already
// been set up to persist at it's old location. We need to freeze
// updates until a resize occurs.
@@ -913,184 +892,54 @@ class WindowStateAnimator {
final Rect insets = attrs.surfaceInsets;
- if (isForceScaled()) {
- int hInsets = insets.left + insets.right;
- int vInsets = insets.top + insets.bottom;
- float surfaceContentWidth = surfaceWidth - hInsets;
- float surfaceContentHeight = surfaceHeight - vInsets;
- if (!mForceScaleUntilResize) {
- mSurfaceController.forceScaleableInTransaction(true);
- }
-
- int posX = 0;
- int posY = 0;
- task.getRootTask().getDimBounds(mTmpStackBounds);
-
- boolean allowStretching = false;
- task.getRootTask().getFinalAnimationSourceHintBounds(mTmpSourceBounds);
- // If we don't have source bounds, we can attempt to use the content insets
- // if we have content insets.
- if (mTmpSourceBounds.isEmpty() && (mWin.mLastRelayoutContentInsets.width() > 0
- || mWin.mLastRelayoutContentInsets.height() > 0)) {
- mTmpSourceBounds.set(task.getRootTask().mPreAnimationBounds);
- mTmpSourceBounds.inset(mWin.mLastRelayoutContentInsets);
- allowStretching = true;
- }
-
- // Make sure that what we're animating to and from is actually the right size in case
- // the window cannot take up the full screen.
- mTmpStackBounds.intersectUnchecked(w.getParentFrame());
- mTmpSourceBounds.intersectUnchecked(w.getParentFrame());
- mTmpAnimatingBounds.intersectUnchecked(w.getParentFrame());
-
- if (!mTmpSourceBounds.isEmpty()) {
- // Get the final target stack bounds, if we are not animating, this is just the
- // current stack bounds
- task.getRootTask().getFinalAnimationBounds(mTmpAnimatingBounds);
-
- // Calculate the current progress and interpolate the difference between the target
- // and source bounds
- float finalWidth = mTmpAnimatingBounds.width();
- float initialWidth = mTmpSourceBounds.width();
- float tw = (surfaceContentWidth - mTmpStackBounds.width())
- / (surfaceContentWidth - mTmpAnimatingBounds.width());
- float th = tw;
- mExtraHScale = (initialWidth + tw * (finalWidth - initialWidth)) / initialWidth;
- if (allowStretching) {
- float finalHeight = mTmpAnimatingBounds.height();
- float initialHeight = mTmpSourceBounds.height();
- th = (surfaceContentHeight - mTmpStackBounds.height())
- / (surfaceContentHeight - mTmpAnimatingBounds.height());
- mExtraVScale = (initialHeight + tw * (finalHeight - initialHeight))
- / initialHeight;
+ if (!w.mSeamlesslyRotated) {
+ // Used to offset the WSA when stack position changes before a resize.
+ int xOffset = mXOffset;
+ int yOffset = mYOffset;
+ if (mOffsetPositionForStackResize) {
+ if (relayout) {
+ // Once a relayout is called, reset the offset back to 0 and defer
+ // setting it until a new frame with the updated size. This ensures that
+ // the WS position is reset (so the stack position is shown) at the same
+ // time that the buffer size changes.
+ setOffsetPositionForStackResize(false);
+ mSurfaceController.deferTransactionUntil(mWin.getClientViewRootSurface(),
+ mWin.getFrameNumber());
} else {
- mExtraVScale = mExtraHScale;
- }
-
- // Adjust the position to account for the inset bounds
- posX -= (int) (tw * mExtraHScale * mTmpSourceBounds.left);
- posY -= (int) (th * mExtraVScale * mTmpSourceBounds.top);
-
- // In pinned mode the clip rectangle applied to us by our stack has been
- // expanded outwards to allow for shadows. However in case of source bounds set
- // we need to crop to within the surface. The code above has scaled and positioned
- // the surface to fit the unexpanded stack bounds, but now we need to reapply
- // the cropping that the stack would have applied if it weren't expanded. This
- // can be different in each direction based on the source bounds.
- clipRect = mTmpClipRect;
- clipRect.set((int)((insets.left + mTmpSourceBounds.left) * tw),
- (int)((insets.top + mTmpSourceBounds.top) * th),
- insets.left + (int)(surfaceWidth
- - (tw* (surfaceWidth - mTmpSourceBounds.right))),
- insets.top + (int)(surfaceHeight
- - (th * (surfaceHeight - mTmpSourceBounds.bottom))));
- } else {
- // We want to calculate the scaling based on the content area, not based on
- // the entire surface, so that we scale in sync with windows that don't have insets.
- mExtraHScale = mTmpStackBounds.width() / surfaceContentWidth;
- mExtraVScale = mTmpStackBounds.height() / surfaceContentHeight;
-
- // Since we are scaled to fit in our previously desired crop, we can now
- // expose the whole window in buffer space, and not risk extending
- // past where the system would have cropped us
- clipRect = null;
- }
-
- // In the case of ForceScaleToStack we scale entire tasks together,
- // and so we need to scale our offsets relative to the task bounds
- // or parent and child windows would fall out of alignment.
- posX -= (int) (attrs.x * (1 - mExtraHScale));
- posY -= (int) (attrs.y * (1 - mExtraVScale));
-
- // Imagine we are scaling down. As we scale the buffer down, we decrease the
- // distance between the surface top left, and the start of the surface contents
- // (previously it was surfaceInsets.left pixels in screen space but now it
- // will be surfaceInsets.left*mExtraHScale). This means in order to keep the
- // non inset content at the same position, we have to shift the whole window
- // forward. Likewise for scaling up, we've increased this distance, and we need
- // to shift by a negative number to compensate.
- posX += insets.left * (1 - mExtraHScale);
- posY += insets.top * (1 - mExtraVScale);
-
- mSurfaceController.setPositionInTransaction((float) Math.floor(posX),
- (float) Math.floor(posY), recoveringMemory);
-
- // Various surfaces in the scaled stack may resize at different times.
- // We need to ensure for each surface, that we disable transformation matrix
- // scaling in the same transaction which we resize the surface in.
- // As we are in SCALING_MODE_SCALE_TO_WINDOW, SurfaceFlinger will
- // then take over the scaling until the new buffer arrives, and things
- // will be seamless.
- if (mPipAnimationStarted == false) {
- mForceScaleUntilResize = true;
- mPipAnimationStarted = true;
- }
- } else {
- mPipAnimationStarted = false;
-
- if (!w.mSeamlesslyRotated) {
- // Used to offset the WSA when stack position changes before a resize.
- int xOffset = mXOffset;
- int yOffset = mYOffset;
- if (mOffsetPositionForStackResize) {
- if (relayout) {
- // Once a relayout is called, reset the offset back to 0 and defer
- // setting it until a new frame with the updated size. This ensures that
- // the WS position is reset (so the stack position is shown) at the same
- // time that the buffer size changes.
- setOffsetPositionForStackResize(false);
- mSurfaceController.deferTransactionUntil(mWin.getClientViewRootSurface(),
- mWin.getFrameNumber());
- } else {
- final Task stack = mWin.getRootTask();
- mTmpPos.x = 0;
- mTmpPos.y = 0;
- if (stack != null) {
- stack.getRelativePosition(mTmpPos);
- }
-
- xOffset = -mTmpPos.x;
- yOffset = -mTmpPos.y;
-
- // Crop also needs to be extended so the bottom isn't cut off when the WSA
- // position is moved.
- if (clipRect != null) {
- clipRect.right += mTmpPos.x;
- clipRect.bottom += mTmpPos.y;
- }
+ final Task stack = mWin.getRootTask();
+ mTmpPos.x = 0;
+ mTmpPos.y = 0;
+ if (stack != null) {
+ stack.getRelativePosition(mTmpPos);
+ }
+ xOffset = -mTmpPos.x;
+ yOffset = -mTmpPos.y;
+ // Crop also needs to be extended so the bottom isn't cut off when the WSA
+ // position is moved.
+ if (clipRect != null) {
+ clipRect.right += mTmpPos.x;
+ clipRect.bottom += mTmpPos.y;
}
- }
- if (!mIsWallpaper) {
- mSurfaceController.setPositionInTransaction(xOffset, yOffset, recoveringMemory);
- } else {
- setWallpaperPositionAndScale(
- xOffset, yOffset, mWallpaperScale, recoveringMemory);
}
}
+ if (!mIsWallpaper) {
+ mSurfaceController.setPositionInTransaction(xOffset, yOffset, recoveringMemory);
+ } else {
+ setWallpaperPositionAndScale(
+ xOffset, yOffset, mWallpaperScale, recoveringMemory);
+ }
}
- // If we are ending the scaling mode. We switch to SCALING_MODE_FREEZE
- // to prevent further updates until buffer latch.
- // We also need to freeze the Surface geometry until a buffer
- // comes in at the new size (normally position and crop are unfrozen).
- // deferTransactionUntil accomplishes this for us.
- if (wasForceScaled && !mForceScaleUntilResize) {
- mSurfaceController.deferTransactionUntil(mWin.getClientViewRootSurface(),
- mWin.getFrameNumber());
- mSurfaceController.forceScaleableInTransaction(false);
- }
-
-
if (!w.mSeamlesslyRotated) {
// Wallpaper is already updated above when calling setWallpaperPositionAndScale so
// we only need to consider the non-wallpaper case here.
if (!mIsWallpaper) {
applyCrop(clipRect, recoveringMemory);
mSurfaceController.setMatrixInTransaction(
- mDsDx * w.mHScale * mExtraHScale,
- mDtDx * w.mVScale * mExtraVScale,
- mDtDy * w.mHScale * mExtraHScale,
- mDsDy * w.mVScale * mExtraVScale, recoveringMemory);
+ mDsDx * w.mHScale,
+ mDtDx * w.mVScale,
+ mDtDy * w.mHScale,
+ mDsDy * w.mVScale, recoveringMemory);
}
}
@@ -1177,10 +1026,10 @@ class WindowStateAnimator {
} else {
prepared =
mSurfaceController.prepareToShowInTransaction(mShownAlpha,
- mDsDx * w.mHScale * mExtraHScale,
- mDtDx * w.mVScale * mExtraVScale,
- mDtDy * w.mHScale * mExtraHScale,
- mDsDy * w.mVScale * mExtraVScale,
+ mDsDx * w.mHScale,
+ mDtDx * w.mVScale,
+ mDtDy * w.mHScale,
+ mDsDy * w.mVScale,
recoveringMemory);
}
@@ -1287,10 +1136,10 @@ class WindowStateAnimator {
mSurfaceController.setPositionInTransaction(mWin.mTmpMatrixArray[MTRANS_X],
mWin.mTmpMatrixArray[MTRANS_Y], recoveringMemory);
mSurfaceController.setMatrixInTransaction(
- mDsDx * mWin.mTmpMatrixArray[MSCALE_X] * mWin.mHScale * mExtraHScale,
- mDtDx * mWin.mTmpMatrixArray[MSKEW_Y] * mWin.mVScale * mExtraVScale,
- mDtDy * mWin.mTmpMatrixArray[MSKEW_X] * mWin.mHScale * mExtraHScale,
- mDsDy * mWin.mTmpMatrixArray[MSCALE_Y] * mWin.mVScale * mExtraVScale,
+ mDsDx * mWin.mTmpMatrixArray[MSCALE_X] * mWin.mHScale,
+ mDtDx * mWin.mTmpMatrixArray[MSKEW_Y] * mWin.mVScale,
+ mDtDy * mWin.mTmpMatrixArray[MSKEW_X] * mWin.mHScale,
+ mDsDy * mWin.mTmpMatrixArray[MSCALE_Y] * mWin.mVScale,
recoveringMemory);
applyCrop(null, recoveringMemory);
}
@@ -1570,18 +1419,6 @@ class WindowStateAnimator {
}
}
- /** The force-scaled state for a given window can persist past
- * the state for it's stack as the windows complete resizing
- * independently of one another.
- */
- boolean isForceScaled() {
- final Task task = mWin.getTask();
- if (task != null && task.getRootTask().isForceScaled()) {
- return true;
- }
- return mForceScaleUntilResize;
- }
-
void detachChildren() {
// Do not detach children of starting windows, as their lifecycle is well under control and
diff --git a/services/core/jni/com_android_server_fingerprint_FingerprintService.cpp b/services/core/jni/com_android_server_fingerprint_FingerprintService.cpp
index 503f0cf993d4..3dfce3aec059 100644
--- a/services/core/jni/com_android_server_fingerprint_FingerprintService.cpp
+++ b/services/core/jni/com_android_server_fingerprint_FingerprintService.cpp
@@ -235,7 +235,7 @@ static jint nativeOpenHal(JNIEnv* env, jobject clazz) {
return 0;
}
- // Sanity check - remove
+ // Soundness check - remove
if (gContext.device->notify != hal_notify_callback) {
ALOGE("NOTIFY not set properly: %p != %p", gContext.device->notify, hal_notify_callback);
}
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index 10523a2adbb2..784366318319 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -239,9 +239,9 @@ public:
void notifySwitch(nsecs_t when, uint32_t switchValues, uint32_t switchMask,
uint32_t policyFlags) override;
void notifyConfigurationChanged(nsecs_t when) override;
- std::chrono::nanoseconds notifyAnr(const sp<InputApplicationHandle>& inputApplicationHandle,
- const sp<IBinder>& token,
- const std::string& reason) override;
+ std::chrono::nanoseconds notifyAnr(
+ const std::shared_ptr<InputApplicationHandle>& inputApplicationHandle,
+ const sp<IBinder>& token, const std::string& reason) override;
void notifyInputChannelBroken(const sp<IBinder>& token) override;
void notifyFocusChanged(const sp<IBinder>& oldToken, const sp<IBinder>& newToken) override;
bool filterInputEvent(const InputEvent* inputEvent, uint32_t policyFlags) override;
@@ -682,8 +682,8 @@ void NativeInputManager::notifyConfigurationChanged(nsecs_t when) {
checkAndClearExceptionFromCallback(env, "notifyConfigurationChanged");
}
-static jobject getInputApplicationHandleObjLocalRef(JNIEnv* env,
- const sp<InputApplicationHandle>& inputApplicationHandle) {
+static jobject getInputApplicationHandleObjLocalRef(
+ JNIEnv* env, const std::shared_ptr<InputApplicationHandle>& inputApplicationHandle) {
if (inputApplicationHandle == nullptr) {
return nullptr;
}
@@ -694,8 +694,8 @@ static jobject getInputApplicationHandleObjLocalRef(JNIEnv* env,
}
std::chrono::nanoseconds NativeInputManager::notifyAnr(
- const sp<InputApplicationHandle>& inputApplicationHandle, const sp<IBinder>& token,
- const std::string& reason) {
+ const std::shared_ptr<InputApplicationHandle>& inputApplicationHandle,
+ const sp<IBinder>& token, const std::string& reason) {
#if DEBUG_INPUT_DISPATCHER_POLICY
ALOGD("notifyANR");
#endif
@@ -780,8 +780,12 @@ void NativeInputManager::displayRemoved(JNIEnv* env, int32_t displayId) {
void NativeInputManager::setFocusedApplication(JNIEnv* env, int32_t displayId,
jobject applicationHandleObj) {
- sp<InputApplicationHandle> applicationHandle =
+ if (!applicationHandleObj) {
+ return;
+ }
+ std::shared_ptr<InputApplicationHandle> applicationHandle =
android_view_InputApplicationHandle_getHandle(env, applicationHandleObj);
+ applicationHandle->updateInfo();
mInputManager->getDispatcher()->setFocusedApplication(displayId, applicationHandle);
}
diff --git a/services/core/jni/stats/PowerStatsPuller.cpp b/services/core/jni/stats/PowerStatsPuller.cpp
index d8f6faac0ffb..7f788c226c7b 100644
--- a/services/core/jni/stats/PowerStatsPuller.cpp
+++ b/services/core/jni/stats/PowerStatsPuller.cpp
@@ -135,16 +135,11 @@ AStatsManager_PullAtomCallbackReturn PowerStatsPuller::Pull(int32_t atomTag,
}
const RailInfo& rail = gRailInfo[energyData.index];
- AStatsEvent* event =
- AStatsEventList_addStatsEvent(data);
- AStatsEvent_setAtomId(
- event,
- android::util::ON_DEVICE_POWER_MEASUREMENT);
- AStatsEvent_writeString(event, rail.subsysName.c_str());
- AStatsEvent_writeString(event, rail.railName.c_str());
- AStatsEvent_writeInt64(event, energyData.timestamp);
- AStatsEvent_writeInt64(event, energyData.energy);
- AStatsEvent_build(event);
+ android::util::addAStatsEvent(
+ data,
+ android::util::ON_DEVICE_POWER_MEASUREMENT,
+ rail.subsysName.c_str(), rail.railName.c_str(),
+ energyData.timestamp, energyData.energy);
ALOGV("power.stat: %s.%s: %llu, %llu",
rail.subsysName.c_str(), rail.railName.c_str(),
diff --git a/services/core/jni/stats/SubsystemSleepStatePuller.cpp b/services/core/jni/stats/SubsystemSleepStatePuller.cpp
index 45afb5eb7aa9..1ba98ef8dab7 100644
--- a/services/core/jni/stats/SubsystemSleepStatePuller.cpp
+++ b/services/core/jni/stats/SubsystemSleepStatePuller.cpp
@@ -194,17 +194,13 @@ static AStatsManager_PullAtomCallbackReturn getIPowerStatsDataLocked(int32_t ato
}
for (auto result : results) {
for (auto stateResidency : result.stateResidencyData) {
- AStatsEvent* event = AStatsEventList_addStatsEvent(data);
- AStatsEvent_setAtomId(event, android::util::SUBSYSTEM_SLEEP_STATE);
- AStatsEvent_writeString(event,
- gEntityNames.at(result.powerEntityId).c_str());
- AStatsEvent_writeString(event,
- gStateNames.at(result.powerEntityId)
- .at(stateResidency.powerEntityStateId)
- .c_str());
- AStatsEvent_writeInt64(event, stateResidency.totalStateEntryCount);
- AStatsEvent_writeInt64(event, stateResidency.totalTimeInStateMs);
- AStatsEvent_build(event);
+ android::util::addAStatsEvent(data, android::util::SUBSYSTEM_SLEEP_STATE,
+ gEntityNames.at(result.powerEntityId).c_str(),
+ gStateNames.at(result.powerEntityId)
+ .at(stateResidency.powerEntityStateId)
+ .c_str(),
+ stateResidency.totalStateEntryCount,
+ stateResidency.totalTimeInStateMs);
}
}
success = true;
@@ -259,26 +255,21 @@ static AStatsManager_PullAtomCallbackReturn getIPowerDataLocked(int32_t atomTag,
for (size_t i = 0; i < states.size(); i++) {
const PowerStatePlatformSleepState& state = states[i];
- AStatsEvent* event = AStatsEventList_addStatsEvent(data);
- AStatsEvent_setAtomId(event, android::util::SUBSYSTEM_SLEEP_STATE);
- AStatsEvent_writeString(event, state.name.c_str());
- AStatsEvent_writeString(event, "");
- AStatsEvent_writeInt64(event, state.totalTransitions);
- AStatsEvent_writeInt64(event, state.residencyInMsecSinceBoot);
- AStatsEvent_build(event);
+ android::util::addAStatsEvent(data, android::util::SUBSYSTEM_SLEEP_STATE,
+ state.name.c_str(), "",
+ state.totalTransitions,
+ state.residencyInMsecSinceBoot);
ALOGV("powerstate: %s, %lld, %lld, %d", state.name.c_str(),
(long long)state.residencyInMsecSinceBoot,
(long long)state.totalTransitions,
state.supportedOnlyInSuspend ? 1 : 0);
for (const auto& voter : state.voters) {
- AStatsEvent* event = AStatsEventList_addStatsEvent(data);
- AStatsEvent_setAtomId(event, android::util::SUBSYSTEM_SLEEP_STATE);
- AStatsEvent_writeString(event, state.name.c_str());
- AStatsEvent_writeString(event, voter.name.c_str());
- AStatsEvent_writeInt64(event, voter.totalNumberOfTimesVotedSinceBoot);
- AStatsEvent_writeInt64(event, voter.totalTimeInMsecVotedForSinceBoot);
- AStatsEvent_build(event);
+ android::util::addAStatsEvent(data,
+ android::util::SUBSYSTEM_SLEEP_STATE,
+ state.name.c_str(), voter.name.c_str(),
+ voter.totalNumberOfTimesVotedSinceBoot,
+ voter.totalTimeInMsecVotedForSinceBoot);
ALOGV("powerstatevoter: %s, %s, %lld, %lld", state.name.c_str(),
voter.name.c_str(),
@@ -305,14 +296,13 @@ static AStatsManager_PullAtomCallbackReturn getIPowerDataLocked(int32_t atomTag,
for (size_t j = 0; j < subsystem.states.size(); j++) {
const PowerStateSubsystemSleepState& state =
subsystem.states[j];
- AStatsEvent* event = AStatsEventList_addStatsEvent(data);
- AStatsEvent_setAtomId(event,
- android::util::SUBSYSTEM_SLEEP_STATE);
- AStatsEvent_writeString(event, subsystem.name.c_str());
- AStatsEvent_writeString(event, state.name.c_str());
- AStatsEvent_writeInt64(event, state.totalTransitions);
- AStatsEvent_writeInt64(event, state.residencyInMsecSinceBoot);
- AStatsEvent_build(event);
+ android::util::
+ addAStatsEvent(data,
+ android::util::SUBSYSTEM_SLEEP_STATE,
+ subsystem.name.c_str(),
+ state.name.c_str(),
+ state.totalTransitions,
+ state.residencyInMsecSinceBoot);
ALOGV("subsystemstate: %s, %s, %lld, %lld, %lld",
subsystem.name.c_str(), state.name.c_str(),
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index a2e310a27fe0..ae6ccda71558 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -1119,7 +1119,7 @@ public final class SystemServer {
t.traceEnd();
t.traceBegin("InstallSystemProviders");
- mActivityManagerService.installSystemProviders();
+ mActivityManagerService.getContentProviderHelper().installSystemProviders();
// Now that SettingsProvider is ready, reactivate SQLiteCompatibilityWalFlags
SQLiteCompatibilityWalFlags.reset();
t.traceEnd();
diff --git a/services/tests/servicestests/src/com/android/server/GestureLauncherServiceTest.java b/services/tests/servicestests/src/com/android/server/GestureLauncherServiceTest.java
index 6f37ff5ef329..c91bb93fc559 100644
--- a/services/tests/servicestests/src/com/android/server/GestureLauncherServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/GestureLauncherServiceTest.java
@@ -28,11 +28,13 @@ import static org.mockito.Mockito.when;
import android.app.StatusBarManager;
import android.content.Context;
+import android.content.Intent;
import android.content.res.Resources;
import android.os.Looper;
import android.os.UserHandle;
import android.platform.test.annotations.Presubmit;
import android.provider.Settings;
+import android.telecom.TelecomManager;
import android.test.mock.MockContentResolver;
import android.util.MutableBoolean;
import android.view.KeyEvent;
@@ -80,6 +82,7 @@ public class GestureLauncherServiceTest {
private @Mock Context mContext;
private @Mock Resources mResources;
private @Mock StatusBarManagerInternal mStatusBarManagerInternal;
+ private @Mock TelecomManager mTelecomManager;
private @Mock MetricsLogger mMetricsLogger;
private MockContentResolver mContentResolver;
private GestureLauncherService mGestureLauncherService;
@@ -104,6 +107,8 @@ public class GestureLauncherServiceTest {
mContentResolver = new MockContentResolver(mContext);
mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
when(mContext.getContentResolver()).thenReturn(mContentResolver);
+ when(mContext.getSystemService(Context.TELECOM_SERVICE)).thenReturn(mTelecomManager);
+ when(mTelecomManager.createLaunchEmergencyDialerIntent(null)).thenReturn(new Intent());
mGestureLauncherService = new GestureLauncherService(mContext, mMetricsLogger);
}
@@ -176,6 +181,13 @@ public class GestureLauncherServiceTest {
}
@Test
+ public void testHandlePanicGesture_userSetupComplete() {
+ withUserSetupCompleteValue(true);
+
+ assertTrue(mGestureLauncherService.handlePanicButtonGesture());
+ }
+
+ @Test
public void testHandleCameraLaunchGesture_userSetupNotComplete() {
withUserSetupCompleteValue(false);
@@ -184,6 +196,13 @@ public class GestureLauncherServiceTest {
}
@Test
+ public void testHandlePanicGesture_userSetupNotComplete() {
+ withUserSetupCompleteValue(false);
+
+ assertFalse(mGestureLauncherService.handlePanicButtonGesture());
+ }
+
+ @Test
public void testInterceptPowerKeyDown_firstPowerDownCameraPowerGestureOnInteractive() {
withCameraDoubleTapPowerEnableConfigValue(true);
withCameraDoubleTapPowerDisableSettingValue(0);
diff --git a/services/tests/servicestests/src/com/android/server/am/BroadcastRecordTest.java b/services/tests/servicestests/src/com/android/server/am/BroadcastRecordTest.java
index a871ec64af3b..5bef877e2f39 100644
--- a/services/tests/servicestests/src/com/android/server/am/BroadcastRecordTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/BroadcastRecordTest.java
@@ -195,7 +195,8 @@ public class BroadcastRecordTest {
false /* sticky */,
false /* initialSticky */,
userId,
- false, /* allowBackgroundActivityStarts */
+ false /* allowBackgroundActivityStarts */,
+ null /* activityStartsToken */,
false /* timeoutExempt */ );
}
}
diff --git a/services/tests/servicestests/src/com/android/server/attention/AttentionManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/attention/AttentionManagerServiceTest.java
index 0dfdd4862d2b..922d71554426 100644
--- a/services/tests/servicestests/src/com/android/server/attention/AttentionManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/attention/AttentionManagerServiceTest.java
@@ -99,6 +99,7 @@ public class AttentionManagerServiceTest {
AttentionCheck attentionCheck = new AttentionCheck(mMockAttentionCallbackInternal,
mSpyAttentionManager);
mSpyAttentionManager.mCurrentAttentionCheck = attentionCheck;
+ mSpyAttentionManager.mService = new MockIAttentionService();
}
@Test
@@ -115,6 +116,7 @@ public class AttentionManagerServiceTest {
@Test
public void testCheckAttention_returnFalseWhenPowerManagerNotInteract() throws RemoteException {
+ doReturn(true).when(mSpyAttentionManager).isAttentionServiceSupported();
doReturn(false).when(mMockIPowerManager).isInteractive();
AttentionCallbackInternal callback = Mockito.mock(AttentionCallbackInternal.class);
assertThat(mSpyAttentionManager.checkAttention(mTimeout, callback)).isFalse();
@@ -122,9 +124,11 @@ public class AttentionManagerServiceTest {
@Test
public void testCheckAttention_callOnSuccess() throws RemoteException {
- doReturn(true).when(mSpyAttentionManager).isServiceEnabled();
+ doReturn(true).when(mSpyAttentionManager).isAttentionServiceSupported();
+ doReturn(true).when(mSpyAttentionManager).isServiceAvailable();
doReturn(true).when(mMockIPowerManager).isInteractive();
doNothing().when(mSpyAttentionManager).freeIfInactiveLocked();
+ mSpyAttentionManager.mCurrentAttentionCheck = null;
AttentionCallbackInternal callback = Mockito.mock(AttentionCallbackInternal.class);
mSpyAttentionManager.checkAttention(mTimeout, callback);
diff --git a/services/tests/servicestests/src/com/android/server/backup/DataChangedJournalTest.java b/services/tests/servicestests/src/com/android/server/backup/DataChangedJournalTest.java
index 0e918db321e3..9daa4ba3c9c8 100644
--- a/services/tests/servicestests/src/com/android/server/backup/DataChangedJournalTest.java
+++ b/services/tests/servicestests/src/com/android/server/backup/DataChangedJournalTest.java
@@ -39,7 +39,7 @@ import org.mockito.MockitoAnnotations;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
-import java.util.ArrayList;
+import java.io.IOException;
import java.util.function.Consumer;
@SmallTest
@@ -90,7 +90,13 @@ public class DataChangedJournalTest {
@Test
public void equals_isTrueForTheSameFile() throws Exception {
- assertThat(mJournal.equals(new DataChangedJournal(mFile))).isTrue();
+ assertEqualsBothWaysAndHashCode(mJournal, new DataChangedJournal(mFile));
+ }
+
+ private static <T> void assertEqualsBothWaysAndHashCode(T a, T b) {
+ assertEquals(a, b);
+ assertEquals(b, a);
+ assertEquals(a.hashCode(), b.hashCode());
}
@Test
@@ -117,9 +123,7 @@ public class DataChangedJournalTest {
DataChangedJournal.newJournal(folder);
DataChangedJournal.newJournal(folder);
- ArrayList<DataChangedJournal> journals = DataChangedJournal.listJournals(folder);
-
- assertThat(journals).hasSize(2);
+ assertThat(DataChangedJournal.listJournals(folder)).hasSize(2);
}
@Test
@@ -131,6 +135,16 @@ public class DataChangedJournalTest {
assertThat(folder.listFiles()).hasLength(1);
}
+ @Test(expected = NullPointerException.class)
+ public void newJournal_nullJournalDir() throws IOException {
+ DataChangedJournal.newJournal(null);
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void nullFile() {
+ new DataChangedJournal(null);
+ }
+
@Test
public void toString_isSameAsFileToString() throws Exception {
assertThat(mJournal.toString()).isEqualTo(mFile.toString());
@@ -140,6 +154,6 @@ public class DataChangedJournalTest {
public void listJournals_invalidJournalFile_returnsEmptyList() throws Exception {
when(invalidFile.listFiles()).thenReturn(null);
- assertEquals(0, DataChangedJournal.listJournals(invalidFile).size());
+ assertThat(DataChangedJournal.listJournals(invalidFile)).isEmpty();
}
}
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/ActiveSourceActionTest.java b/services/tests/servicestests/src/com/android/server/hdmi/ActiveSourceActionTest.java
index 50086affcbc5..870a27417cd2 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/ActiveSourceActionTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/ActiveSourceActionTest.java
@@ -144,6 +144,26 @@ public class ActiveSourceActionTest {
}
@Test
+ public void playbackDevice_updatesActiveSourceState() {
+ HdmiCecLocalDevicePlayback playbackDevice = new HdmiCecLocalDevicePlayback(
+ mHdmiControlService);
+ playbackDevice.init();
+ mLocalDevices.add(playbackDevice);
+ mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
+ mTestLooper.dispatchAll();
+
+ HdmiCecFeatureAction action = new com.android.server.hdmi.ActiveSourceAction(
+ playbackDevice, ADDR_TV);
+ playbackDevice.addAndStartAction(action);
+ mTestLooper.dispatchAll();
+
+ assertThat(playbackDevice.getActiveSource().logicalAddress).isEqualTo(
+ playbackDevice.mAddress);
+ assertThat(playbackDevice.getActiveSource().physicalAddress).isEqualTo(mPhysicalAddress);
+ assertThat(playbackDevice.mIsActiveSource).isTrue();
+ }
+
+ @Test
public void audioDevice_sendsActiveSource_noMenuStatus() {
HdmiCecLocalDeviceAudioSystem audioDevice = new HdmiCecLocalDeviceAudioSystem(
mHdmiControlService);
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
index 35f9ca5cce68..9b2f2b659493 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
@@ -15,6 +15,7 @@
*/
package com.android.server.hdmi;
+import static com.android.server.hdmi.Constants.ADDR_BROADCAST;
import static com.android.server.hdmi.Constants.ADDR_PLAYBACK_1;
import static com.android.server.hdmi.Constants.ADDR_TV;
import static com.android.server.hdmi.HdmiControlService.INITIATED_BY_ENABLE_CEC;
@@ -22,6 +23,7 @@ import static com.android.server.hdmi.HdmiControlService.INITIATED_BY_ENABLE_CEC
import static com.google.common.truth.Truth.assertThat;
import android.content.Context;
+import android.hardware.hdmi.HdmiControlManager;
import android.os.Handler;
import android.os.IPowerManager;
import android.os.IThermalService;
@@ -29,6 +31,7 @@ import android.os.Looper;
import android.os.PowerManager;
import android.os.test.TestLooper;
import android.platform.test.annotations.Presubmit;
+import android.provider.Settings.Global;
import android.sysprop.HdmiProperties;
import android.view.KeyEvent;
@@ -324,29 +327,117 @@ public class HdmiCecLocalDevicePlaybackTest {
}
@Test
- public void handleOnStandby_ScreenOff_NotActiveSource() {
+ public void handleOnStandby_ScreenOff_NotActiveSource_ToTv() {
+ mHdmiCecLocalDevicePlayback.mService.writeStringSetting(
+ Global.HDMI_CONTROL_SEND_STANDBY_ON_SLEEP,
+ HdmiControlManager.SEND_STANDBY_ON_SLEEP_TO_TV);
mHdmiCecLocalDevicePlayback.setIsActiveSource(false);
mHdmiCecLocalDevicePlayback.setAutoDeviceOff(true);
mHdmiCecLocalDevicePlayback.onStandby(false, HdmiControlService.STANDBY_SCREEN_OFF);
mTestLooper.dispatchAll();
- HdmiCecMessage standbyMessage = HdmiCecMessageBuilder.buildStandby(
+ HdmiCecMessage standbyMessageToTv = HdmiCecMessageBuilder.buildStandby(
mHdmiCecLocalDevicePlayback.mAddress, ADDR_TV);
+ HdmiCecMessage standbyMessageBroadcast = HdmiCecMessageBuilder.buildStandby(
+ mHdmiCecLocalDevicePlayback.mAddress, ADDR_BROADCAST);
- assertThat(mNativeWrapper.getResultMessages()).doesNotContain(standbyMessage);
+ assertThat(mNativeWrapper.getResultMessages()).doesNotContain(standbyMessageToTv);
+ assertThat(mNativeWrapper.getResultMessages()).doesNotContain(standbyMessageBroadcast);
}
@Test
- public void handleOnStandby_ScreenOff_ActiveSource() {
+ public void handleOnStandby_ScreenOff_NotActiveSource_Broadcast() {
+ mHdmiCecLocalDevicePlayback.mService.writeStringSetting(
+ Global.HDMI_CONTROL_SEND_STANDBY_ON_SLEEP,
+ HdmiControlManager.SEND_STANDBY_ON_SLEEP_BROADCAST);
+ mHdmiCecLocalDevicePlayback.setIsActiveSource(false);
+ mHdmiCecLocalDevicePlayback.setAutoDeviceOff(true);
+ mHdmiCecLocalDevicePlayback.onStandby(false, HdmiControlService.STANDBY_SCREEN_OFF);
+ mTestLooper.dispatchAll();
+
+ HdmiCecMessage standbyMessageToTv = HdmiCecMessageBuilder.buildStandby(
+ mHdmiCecLocalDevicePlayback.mAddress, ADDR_TV);
+ HdmiCecMessage standbyMessageBroadcast = HdmiCecMessageBuilder.buildStandby(
+ mHdmiCecLocalDevicePlayback.mAddress, ADDR_BROADCAST);
+
+ assertThat(mNativeWrapper.getResultMessages()).doesNotContain(standbyMessageToTv);
+ assertThat(mNativeWrapper.getResultMessages()).doesNotContain(standbyMessageBroadcast);
+ }
+
+ @Test
+ public void handleOnStandby_ScreenOff_NotActiveSource_None() {
+ mHdmiCecLocalDevicePlayback.mService.writeStringSetting(
+ Global.HDMI_CONTROL_SEND_STANDBY_ON_SLEEP,
+ HdmiControlManager.SEND_STANDBY_ON_SLEEP_NONE);
+ mHdmiCecLocalDevicePlayback.setIsActiveSource(false);
+ mHdmiCecLocalDevicePlayback.setAutoDeviceOff(true);
+ mHdmiCecLocalDevicePlayback.onStandby(false, HdmiControlService.STANDBY_SCREEN_OFF);
+ mTestLooper.dispatchAll();
+
+ HdmiCecMessage standbyMessageToTv = HdmiCecMessageBuilder.buildStandby(
+ mHdmiCecLocalDevicePlayback.mAddress, ADDR_TV);
+ HdmiCecMessage standbyMessageBroadcast = HdmiCecMessageBuilder.buildStandby(
+ mHdmiCecLocalDevicePlayback.mAddress, ADDR_BROADCAST);
+
+ assertThat(mNativeWrapper.getResultMessages()).doesNotContain(standbyMessageToTv);
+ assertThat(mNativeWrapper.getResultMessages()).doesNotContain(standbyMessageBroadcast);
+ }
+
+ @Test
+ public void handleOnStandby_ScreenOff_ActiveSource_ToTv() {
+ mHdmiCecLocalDevicePlayback.mService.writeStringSetting(
+ Global.HDMI_CONTROL_SEND_STANDBY_ON_SLEEP,
+ HdmiControlManager.SEND_STANDBY_ON_SLEEP_TO_TV);
mHdmiCecLocalDevicePlayback.setIsActiveSource(true);
mHdmiCecLocalDevicePlayback.setAutoDeviceOff(true);
mHdmiCecLocalDevicePlayback.onStandby(false, HdmiControlService.STANDBY_SCREEN_OFF);
mTestLooper.dispatchAll();
- HdmiCecMessage standbyMessage = HdmiCecMessageBuilder.buildStandby(
+ HdmiCecMessage standbyMessageToTv = HdmiCecMessageBuilder.buildStandby(
mHdmiCecLocalDevicePlayback.mAddress, ADDR_TV);
+ HdmiCecMessage standbyMessageBroadcast = HdmiCecMessageBuilder.buildStandby(
+ mHdmiCecLocalDevicePlayback.mAddress, ADDR_BROADCAST);
- assertThat(mNativeWrapper.getResultMessages()).contains(standbyMessage);
+ assertThat(mNativeWrapper.getResultMessages()).contains(standbyMessageToTv);
+ assertThat(mNativeWrapper.getResultMessages()).doesNotContain(standbyMessageBroadcast);
+ }
+
+ @Test
+ public void handleOnStandby_ScreenOff_ActiveSource_Broadcast() {
+ mHdmiCecLocalDevicePlayback.mService.writeStringSetting(
+ Global.HDMI_CONTROL_SEND_STANDBY_ON_SLEEP,
+ HdmiControlManager.SEND_STANDBY_ON_SLEEP_BROADCAST);
+ mHdmiCecLocalDevicePlayback.setIsActiveSource(true);
+ mHdmiCecLocalDevicePlayback.setAutoDeviceOff(true);
+ mHdmiCecLocalDevicePlayback.onStandby(false, HdmiControlService.STANDBY_SCREEN_OFF);
+ mTestLooper.dispatchAll();
+
+ HdmiCecMessage standbyMessageToTv = HdmiCecMessageBuilder.buildStandby(
+ mHdmiCecLocalDevicePlayback.mAddress, ADDR_TV);
+ HdmiCecMessage standbyMessageBroadcast = HdmiCecMessageBuilder.buildStandby(
+ mHdmiCecLocalDevicePlayback.mAddress, ADDR_BROADCAST);
+
+ assertThat(mNativeWrapper.getResultMessages()).doesNotContain(standbyMessageToTv);
+ assertThat(mNativeWrapper.getResultMessages()).contains(standbyMessageBroadcast);
+ }
+
+ @Test
+ public void handleOnStandby_ScreenOff_ActiveSource_None() {
+ mHdmiCecLocalDevicePlayback.mService.writeStringSetting(
+ Global.HDMI_CONTROL_SEND_STANDBY_ON_SLEEP,
+ HdmiControlManager.SEND_STANDBY_ON_SLEEP_NONE);
+ mHdmiCecLocalDevicePlayback.setIsActiveSource(true);
+ mHdmiCecLocalDevicePlayback.setAutoDeviceOff(true);
+ mHdmiCecLocalDevicePlayback.onStandby(false, HdmiControlService.STANDBY_SCREEN_OFF);
+ mTestLooper.dispatchAll();
+
+ HdmiCecMessage standbyMessageToTv = HdmiCecMessageBuilder.buildStandby(
+ mHdmiCecLocalDevicePlayback.mAddress, ADDR_TV);
+ HdmiCecMessage standbyMessageBroadcast = HdmiCecMessageBuilder.buildStandby(
+ mHdmiCecLocalDevicePlayback.mAddress, ADDR_BROADCAST);
+
+ assertThat(mNativeWrapper.getResultMessages()).doesNotContain(standbyMessageToTv);
+ assertThat(mNativeWrapper.getResultMessages()).doesNotContain(standbyMessageBroadcast);
}
@Test
@@ -526,4 +617,19 @@ public class HdmiCecLocalDevicePlaybackTest {
assertThat(mNativeWrapper.getResultMessages()).contains(activeSource);
}
+
+ @Test
+ public void handleSetStreamPath_afterHotplug_hasCorrectActiveSource() {
+ mHdmiControlService.onHotplug(1, false);
+ mHdmiControlService.onHotplug(1, true);
+
+ HdmiCecMessage setStreamPath = HdmiCecMessageBuilder.buildSetStreamPath(ADDR_TV,
+ mPlaybackPhysicalAddress);
+ mHdmiCecLocalDevicePlayback.dispatchMessage(setStreamPath);
+ mTestLooper.dispatchAll();
+
+ assertThat(mHdmiCecLocalDevicePlayback.getActiveSource().logicalAddress).isEqualTo(
+ mHdmiCecLocalDevicePlayback.getDeviceInfo().getLogicalAddress());
+ assertThat(mHdmiCecLocalDevicePlayback.mIsActiveSource).isTrue();
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/job/JobSetTest.java b/services/tests/servicestests/src/com/android/server/job/JobSetTest.java
index 6b7634db8a60..62cc111e4dae 100644
--- a/services/tests/servicestests/src/com/android/server/job/JobSetTest.java
+++ b/services/tests/servicestests/src/com/android/server/job/JobSetTest.java
@@ -97,9 +97,9 @@ public class JobSetTest {
mJobSet.remove(testJob1);
mJobSet.remove(testJob2);
assertHaveSameJobs(mJobSet.mJobsPerSourceUid, mJobSet.mJobs);
- mJobSet.removeJobsOfNonUsers(new int[] {mContext.getUserId(), SECONDARY_USER_ID_1});
+ mJobSet.removeJobsOfUnlistedUsers(new int[] {mContext.getUserId(), SECONDARY_USER_ID_1});
assertHaveSameJobs(mJobSet.mJobsPerSourceUid, mJobSet.mJobs);
- mJobSet.removeJobsOfNonUsers(new int[] {mContext.getUserId()});
+ mJobSet.removeJobsOfUnlistedUsers(new int[] {mContext.getUserId()});
assertTrue("mJobs should be empty", mJobSet.mJobs.size() == 0);
assertTrue("mJobsPerSourceUid should be empty", mJobSet.mJobsPerSourceUid.size() == 0);
}
diff --git a/services/tests/servicestests/src/com/android/server/om/OverlayReferenceMapperTests.kt b/services/tests/servicestests/src/com/android/server/om/OverlayReferenceMapperTests.kt
index 78c708084d38..d888b9258d33 100644
--- a/services/tests/servicestests/src/com/android/server/om/OverlayReferenceMapperTests.kt
+++ b/services/tests/servicestests/src/com/android/server/om/OverlayReferenceMapperTests.kt
@@ -25,7 +25,6 @@ import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.Parameterized
-import org.testng.Assert.assertThrows
@RunWith(Parameterized::class)
class OverlayReferenceMapperTests {
@@ -160,9 +159,6 @@ class OverlayReferenceMapperTests {
expected.forEach { (actorPkgName, expectedPkgNames) ->
expectedPkgNames.forEach { expectedPkgName ->
if (deferRebuild) {
- assertThrows(IllegalStateException::class.java) {
- mapper.isValidActor(expectedPkgName, actorPkgName)
- }
mapper.rebuildIfDeferred()
deferRebuild = false
}
@@ -187,7 +183,7 @@ class OverlayReferenceMapperTests {
)
)
) = OverlayReferenceMapper(deferRebuild, object : OverlayReferenceMapper.Provider {
- override fun getActorPkg(actor: String?) =
+ override fun getActorPkg(actor: String) =
OverlayActorEnforcer.getPackageNameForActor(actor, namedActors).first
override fun getTargetToOverlayables(pkg: AndroidPackage) =
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
index fa9ee19cba9d..aa92ba49d190 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
@@ -57,6 +57,7 @@ import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
+import com.android.permission.persistence.RuntimePermissionsPersistence;
import com.android.server.LocalServices;
import com.android.server.pm.permission.PermissionSettings;
@@ -86,6 +87,8 @@ public class PackageManagerSettingsTests {
@Mock
PermissionSettings mPermissionSettings;
+ @Mock
+ RuntimePermissionsPersistence mRuntimePermissionsPersistence;
@Before
public void initializeMocks() {
@@ -106,7 +109,8 @@ public class PackageManagerSettingsTests {
writeOldFiles();
final Context context = InstrumentationRegistry.getContext();
final Object lock = new Object();
- Settings settings = new Settings(context.getFilesDir(), mPermissionSettings, lock);
+ Settings settings = new Settings(context.getFilesDir(), mPermissionSettings,
+ mRuntimePermissionsPersistence, lock);
assertThat(settings.readLPw(createFakeUsers()), is(true));
verifyKeySetMetaData(settings);
}
@@ -119,7 +123,8 @@ public class PackageManagerSettingsTests {
writeOldFiles();
final Context context = InstrumentationRegistry.getContext();
final Object lock = new Object();
- Settings settings = new Settings(context.getFilesDir(), mPermissionSettings, lock);
+ Settings settings = new Settings(context.getFilesDir(), mPermissionSettings,
+ mRuntimePermissionsPersistence, lock);
assertThat(settings.readLPw(createFakeUsers()), is(true));
// write out, read back in and verify the same
@@ -134,7 +139,8 @@ public class PackageManagerSettingsTests {
writeOldFiles();
final Context context = InstrumentationRegistry.getContext();
final Object lock = new Object();
- Settings settings = new Settings(context.getFilesDir(), mPermissionSettings, lock);
+ Settings settings = new Settings(context.getFilesDir(), mPermissionSettings,
+ mRuntimePermissionsPersistence, lock);
assertThat(settings.readLPw(createFakeUsers()), is(true));
assertThat(settings.getPackageLPr(PACKAGE_NAME_3), is(notNullValue()));
assertThat(settings.getPackageLPr(PACKAGE_NAME_1), is(notNullValue()));
@@ -155,12 +161,14 @@ public class PackageManagerSettingsTests {
writeOldFiles();
final Context context = InstrumentationRegistry.getContext();
final Object lock = new Object();
- Settings settings = new Settings(context.getFilesDir(), mPermissionSettings, lock);
+ Settings settings = new Settings(context.getFilesDir(), mPermissionSettings,
+ mRuntimePermissionsPersistence, lock);
assertThat(settings.readLPw(createFakeUsers()), is(true));
settings.writeLPr();
// Create Settings again to make it read from the new files
- settings = new Settings(context.getFilesDir(), mPermissionSettings, lock);
+ settings = new Settings(context.getFilesDir(), mPermissionSettings,
+ mRuntimePermissionsPersistence, lock);
assertThat(settings.readLPw(createFakeUsers()), is(true));
PackageSetting ps = settings.getPackageLPr(PACKAGE_NAME_2);
@@ -183,7 +191,7 @@ public class PackageManagerSettingsTests {
writePackageRestrictions_noSuspendingPackageXml(0);
final Object lock = new Object();
final Context context = InstrumentationRegistry.getTargetContext();
- final Settings settingsUnderTest = new Settings(context.getFilesDir(), null, lock);
+ final Settings settingsUnderTest = new Settings(context.getFilesDir(), null, null, lock);
settingsUnderTest.mPackages.put(PACKAGE_NAME_1, createPackageSetting(PACKAGE_NAME_1));
settingsUnderTest.mPackages.put(PACKAGE_NAME_2, createPackageSetting(PACKAGE_NAME_2));
settingsUnderTest.readPackageRestrictionsLPr(0);
@@ -206,7 +214,7 @@ public class PackageManagerSettingsTests {
writePackageRestrictions_noSuspendParamsMapXml(0);
final Object lock = new Object();
final Context context = InstrumentationRegistry.getTargetContext();
- final Settings settingsUnderTest = new Settings(context.getFilesDir(), null, lock);
+ final Settings settingsUnderTest = new Settings(context.getFilesDir(), null, null, lock);
settingsUnderTest.mPackages.put(PACKAGE_NAME_1, createPackageSetting(PACKAGE_NAME_1));
settingsUnderTest.readPackageRestrictionsLPr(0);
@@ -233,7 +241,8 @@ public class PackageManagerSettingsTests {
@Test
public void testReadWritePackageRestrictions_suspendInfo() {
final Context context = InstrumentationRegistry.getTargetContext();
- final Settings settingsUnderTest = new Settings(context.getFilesDir(), null, new Object());
+ final Settings settingsUnderTest = new Settings(context.getFilesDir(), null, null,
+ new Object());
final PackageSetting ps1 = createPackageSetting(PACKAGE_NAME_1);
final PackageSetting ps2 = createPackageSetting(PACKAGE_NAME_2);
final PackageSetting ps3 = createPackageSetting(PACKAGE_NAME_3);
@@ -330,7 +339,8 @@ public class PackageManagerSettingsTests {
@Test
public void testReadWritePackageRestrictions_distractionFlags() {
final Context context = InstrumentationRegistry.getTargetContext();
- final Settings settingsUnderTest = new Settings(context.getFilesDir(), null, new Object());
+ final Settings settingsUnderTest = new Settings(context.getFilesDir(), null, null,
+ new Object());
final PackageSetting ps1 = createPackageSetting(PACKAGE_NAME_1);
final PackageSetting ps2 = createPackageSetting(PACKAGE_NAME_2);
final PackageSetting ps3 = createPackageSetting(PACKAGE_NAME_3);
@@ -381,7 +391,8 @@ public class PackageManagerSettingsTests {
writeOldFiles();
final Context context = InstrumentationRegistry.getContext();
final Object lock = new Object();
- Settings settings = new Settings(context.getFilesDir(), mPermissionSettings, lock);
+ Settings settings = new Settings(context.getFilesDir(), mPermissionSettings,
+ mRuntimePermissionsPersistence, lock);
assertThat(settings.readLPw(createFakeUsers()), is(true));
// Enable/Disable a package
@@ -558,8 +569,8 @@ public class PackageManagerSettingsTests {
public void testUpdatePackageSetting03() {
final Context context = InstrumentationRegistry.getContext();
final Object lock = new Object();
- final Settings testSettings01 =
- new Settings(context.getFilesDir(), mPermissionSettings, lock);
+ final Settings testSettings01 = new Settings(context.getFilesDir(), mPermissionSettings,
+ mRuntimePermissionsPersistence, lock);
final SharedUserSetting testUserSetting01 = createSharedUserSetting(
testSettings01, "TestUser", 10064, 0 /*pkgFlags*/, 0 /*pkgPrivateFlags*/);
final PackageSetting testPkgSetting01 =
@@ -673,8 +684,8 @@ public class PackageManagerSettingsTests {
public void testCreateNewSetting03() {
final Context context = InstrumentationRegistry.getContext();
final Object lock = new Object();
- final Settings testSettings01 =
- new Settings(context.getFilesDir(), mPermissionSettings, lock);
+ final Settings testSettings01 = new Settings(context.getFilesDir(), mPermissionSettings,
+ mRuntimePermissionsPersistence, lock);
final SharedUserSetting testUserSetting01 = createSharedUserSetting(
testSettings01, "TestUser", 10064, 0 /*pkgFlags*/, 0 /*pkgPrivateFlags*/);
final PackageSetting testPkgSetting01 = Settings.createNewSetting(
diff --git a/services/tests/servicestests/src/com/android/server/power/ShutdownCheckPointsTest.java b/services/tests/servicestests/src/com/android/server/power/ShutdownCheckPointsTest.java
index a1f105604559..2230ddd8a4a7 100644
--- a/services/tests/servicestests/src/com/android/server/power/ShutdownCheckPointsTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/ShutdownCheckPointsTest.java
@@ -72,21 +72,32 @@ public class ShutdownCheckPointsTest {
@Test
public void testSystemServerEntry() {
mTestInjector.setCurrentTime(1000);
- mInstance.recordCheckPointInternal();
+ mInstance.recordCheckPointInternal("reason1");
assertTrue(dumpToString().startsWith(
- "Shutdown request from SYSTEM at 1970-01-01 00:00:01.000 UTC (epoch=1000)\n"
+ "Shutdown request from SYSTEM for reason reason1 "
+ + "at 1970-01-01 00:00:01.000 UTC (epoch=1000)\n"
+ "com.android.server.power.ShutdownCheckPointsTest"
+ ".testSystemServerEntry\n at "));
}
@Test
+ public void testSystemServerEntryWithoutReason() {
+ mTestInjector.setCurrentTime(1000);
+ mInstance.recordCheckPointInternal(null);
+
+ assertTrue(dumpToString().startsWith(
+ "Shutdown request from SYSTEM at 1970-01-01 00:00:01.000 UTC (epoch=1000)\n"));
+ }
+
+ @Test
public void testSystemServiceBinderEntry() {
mTestInjector.setCurrentTime(1000);
- mInstance.recordCheckPointInternal(Process.myPid());
+ mInstance.recordCheckPointInternal(Process.myPid(), "reason1");
assertTrue(dumpToString().startsWith(
- "Shutdown request from SYSTEM at 1970-01-01 00:00:01.000 UTC (epoch=1000)\n"
+ "Shutdown request from SYSTEM for reason reason1 "
+ + "at 1970-01-01 00:00:01.000 UTC (epoch=1000)\n"
+ "com.android.server.power.ShutdownCheckPointsTest"
+ ".testSystemServiceBinderEntry\n at "));
}
@@ -99,10 +110,11 @@ public class ShutdownCheckPointsTest {
when(mActivityManager.getRunningAppProcesses()).thenReturn(runningAppProcessInfos);
mTestInjector.setCurrentTime(1000);
- mInstance.recordCheckPointInternal(1);
+ mInstance.recordCheckPointInternal(1, "reason1");
assertEquals(
- "Shutdown request from BINDER at 1970-01-01 00:00:01.000 UTC (epoch=1000)\n"
+ "Shutdown request from BINDER for reason reason1 "
+ + "at 1970-01-01 00:00:01.000 UTC (epoch=1000)\n"
+ "com.android.server.power.ShutdownCheckPointsTest"
+ ".testCallerProcessBinderEntry\n"
+ "From process process_name (pid=1)\n\n",
@@ -114,10 +126,11 @@ public class ShutdownCheckPointsTest {
when(mActivityManager.getRunningAppProcesses()).thenThrow(new RemoteException("Error"));
mTestInjector.setCurrentTime(1000);
- mInstance.recordCheckPointInternal(1);
+ mInstance.recordCheckPointInternal(1, "reason1");
assertEquals(
- "Shutdown request from BINDER at 1970-01-01 00:00:01.000 UTC (epoch=1000)\n"
+ "Shutdown request from BINDER for reason reason1 "
+ + "at 1970-01-01 00:00:01.000 UTC (epoch=1000)\n"
+ "com.android.server.power.ShutdownCheckPointsTest"
+ ".testRemoteExceptionOnBinderEntry\n"
+ "From process ? (pid=1)\n\n",
@@ -127,10 +140,11 @@ public class ShutdownCheckPointsTest {
@Test
public void testUnknownProcessBinderEntry() {
mTestInjector.setCurrentTime(1000);
- mInstance.recordCheckPointInternal(1);
+ mInstance.recordCheckPointInternal(1, "reason1");
assertEquals(
- "Shutdown request from BINDER at 1970-01-01 00:00:01.000 UTC (epoch=1000)\n"
+ "Shutdown request from BINDER for reason reason1 "
+ + "at 1970-01-01 00:00:01.000 UTC (epoch=1000)\n"
+ "com.android.server.power.ShutdownCheckPointsTest"
+ ".testUnknownProcessBinderEntry\n"
+ "From process ? (pid=1)\n\n",
@@ -138,12 +152,22 @@ public class ShutdownCheckPointsTest {
}
@Test
+ public void testBinderEntryWithoutReason() throws RemoteException {
+ mTestInjector.setCurrentTime(1000);
+ mInstance.recordCheckPointInternal(1, null);
+
+ assertTrue(dumpToString().startsWith(
+ "Shutdown request from BINDER at 1970-01-01 00:00:01.000 UTC (epoch=1000)\n"));
+ }
+
+ @Test
public void testSystemServiceIntentEntry() {
mTestInjector.setCurrentTime(1000);
- mInstance.recordCheckPointInternal("some.intent", "android");
+ mInstance.recordCheckPointInternal("some.intent", "android", "reason1");
assertTrue(dumpToString().startsWith(
- "Shutdown request from SYSTEM at 1970-01-01 00:00:01.000 UTC (epoch=1000)\n"
+ "Shutdown request from SYSTEM for reason reason1 "
+ + "at 1970-01-01 00:00:01.000 UTC (epoch=1000)\n"
+ "com.android.server.power.ShutdownCheckPointsTest"
+ ".testSystemServiceIntentEntry\n at "));
}
@@ -151,39 +175,47 @@ public class ShutdownCheckPointsTest {
@Test
public void testIntentEntry() {
mTestInjector.setCurrentTime(1000);
- mInstance.recordCheckPointInternal("some.intent", "some.app");
+ mInstance.recordCheckPointInternal("some.intent", "some.app", "reason1");
assertEquals(
- "Shutdown request from INTENT at 1970-01-01 00:00:01.000 UTC (epoch=1000)\n"
+ "Shutdown request from INTENT for reason reason1 "
+ + "at 1970-01-01 00:00:01.000 UTC (epoch=1000)\n"
+ "Intent: some.intent\n"
+ "Package: some.app\n\n",
dumpToString());
}
@Test
+ public void testIntentEntryWithoutReason() {
+ mTestInjector.setCurrentTime(1000);
+ mInstance.recordCheckPointInternal("some.intent", "some.app", null);
+
+ assertTrue(dumpToString().startsWith(
+ "Shutdown request from INTENT at 1970-01-01 00:00:01.000 UTC (epoch=1000)\n"));
+ }
+
+ @Test
public void testMultipleEntries() {
mTestInjector.setCurrentTime(1000);
- mInstance.recordCheckPointInternal(1);
+ mInstance.recordCheckPointInternal(1, "reason1");
mTestInjector.setCurrentTime(2000);
- mInstance.recordCheckPointInternal(2);
+ mInstance.recordCheckPointInternal(2, "reason2");
mTestInjector.setCurrentTime(3000);
- mInstance.recordCheckPointInternal("intent", "app");
+ mInstance.recordCheckPointInternal("intent", "app", "reason3");
assertEquals(
- "Shutdown request from BINDER at 1970-01-01 00:00:01.000 UTC (epoch=1000)\n"
+ "Shutdown request from BINDER for reason reason1 "
+ + "at 1970-01-01 00:00:01.000 UTC (epoch=1000)\n"
+ "com.android.server.power.ShutdownCheckPointsTest.testMultipleEntries\n"
- + "From process ? (pid=1)\n"
- + "\n"
- + "Shutdown request from BINDER at 1970-01-01 00:00:02.000 UTC (epoch=2000)"
- + "\n"
+ + "From process ? (pid=1)\n\n"
+ + "Shutdown request from BINDER for reason reason2 "
+ + "at 1970-01-01 00:00:02.000 UTC (epoch=2000)\n"
+ "com.android.server.power.ShutdownCheckPointsTest.testMultipleEntries\n"
- + "From process ? (pid=2)\n"
- + "\n"
- + "Shutdown request from INTENT at 1970-01-01 00:00:03.000 UTC (epoch=3000)"
- + "\n"
+ + "From process ? (pid=2)\n\n"
+ + "Shutdown request from INTENT for reason reason3 "
+ + "at 1970-01-01 00:00:03.000 UTC (epoch=3000)\n"
+ "Intent: intent\n"
- + "Package: app\n"
- + "\n",
+ + "Package: app\n\n",
dumpToString());
}
@@ -193,23 +225,22 @@ public class ShutdownCheckPointsTest {
ShutdownCheckPoints limitedInstance = new ShutdownCheckPoints(mTestInjector);
mTestInjector.setCurrentTime(1000);
- limitedInstance.recordCheckPointInternal("intent.1", "app.1");
+ limitedInstance.recordCheckPointInternal("intent.1", "app.1", "reason1");
mTestInjector.setCurrentTime(2000);
- limitedInstance.recordCheckPointInternal("intent.2", "app.2");
+ limitedInstance.recordCheckPointInternal("intent.2", "app.2", "reason2");
mTestInjector.setCurrentTime(3000);
- limitedInstance.recordCheckPointInternal("intent.3", "app.3");
+ limitedInstance.recordCheckPointInternal("intent.3", "app.3", "reason3");
// Drops first intent.
assertEquals(
- "Shutdown request from INTENT at 1970-01-01 00:00:02.000 UTC (epoch=2000)\n"
+ "Shutdown request from INTENT for reason reason2 "
+ + "at 1970-01-01 00:00:02.000 UTC (epoch=2000)\n"
+ "Intent: intent.2\n"
- + "Package: app.2\n"
- + "\n"
- + "Shutdown request from INTENT at 1970-01-01 00:00:03.000 UTC (epoch=3000)"
- + "\n"
+ + "Package: app.2\n\n"
+ + "Shutdown request from INTENT for reason reason3 "
+ + "at 1970-01-01 00:00:03.000 UTC (epoch=3000)\n"
+ "Intent: intent.3\n"
- + "Package: app.3\n"
- + "\n",
+ + "Package: app.3\n\n",
dumpToString(limitedInstance));
}
@@ -219,11 +250,11 @@ public class ShutdownCheckPointsTest {
File baseFile = new File(tempDir, "checkpoints");
mTestInjector.setCurrentTime(1000);
- mInstance.recordCheckPointInternal("first.intent", "first.app");
+ mInstance.recordCheckPointInternal("first.intent", "first.app", "reason1");
dumpToFile(baseFile);
mTestInjector.setCurrentTime(2000);
- mInstance.recordCheckPointInternal("second.intent", "second.app");
+ mInstance.recordCheckPointInternal("second.intent", "second.app", "reason2");
dumpToFile(baseFile);
File[] dumpFiles = tempDir.listFiles();
@@ -231,16 +262,18 @@ public class ShutdownCheckPointsTest {
assertEquals(2, dumpFiles.length);
assertEquals(
- "Shutdown request from INTENT at 1970-01-01 00:00:01.000 UTC (epoch=1000)\n"
+ "Shutdown request from INTENT for reason reason1 "
+ + "at 1970-01-01 00:00:01.000 UTC (epoch=1000)\n"
+ "Intent: first.intent\n"
+ "Package: first.app\n\n",
readFileAsString(dumpFiles[0].getAbsolutePath()));
assertEquals(
- "Shutdown request from INTENT at 1970-01-01 00:00:01.000 UTC (epoch=1000)\n"
+ "Shutdown request from INTENT for reason reason1 "
+ + "at 1970-01-01 00:00:01.000 UTC (epoch=1000)\n"
+ "Intent: first.intent\n"
+ "Package: first.app\n\n"
- + "Shutdown request from INTENT at 1970-01-01 00:00:02.000 UTC (epoch=2000)"
- + "\n"
+ + "Shutdown request from INTENT for reason reason2 "
+ + "at 1970-01-01 00:00:02.000 UTC (epoch=2000)\n"
+ "Intent: second.intent\n"
+ "Package: second.app\n\n",
readFileAsString(dumpFiles[1].getAbsolutePath()));
@@ -254,21 +287,22 @@ public class ShutdownCheckPointsTest {
File baseFile = new File(tempDir, "checkpoints");
mTestInjector.setCurrentTime(1000);
- instance.recordCheckPointInternal("first.intent", "first.app");
+ instance.recordCheckPointInternal("first.intent", "first.app", "reason1");
dumpToFile(instance, baseFile);
mTestInjector.setCurrentTime(2000);
- instance.recordCheckPointInternal("second.intent", "second.app");
+ instance.recordCheckPointInternal("second.intent", "second.app", "reason2");
dumpToFile(instance, baseFile);
File[] dumpFiles = tempDir.listFiles();
assertEquals(1, dumpFiles.length);
assertEquals(
- "Shutdown request from INTENT at 1970-01-01 00:00:01.000 UTC (epoch=1000)\n"
+ "Shutdown request from INTENT for reason reason1 "
+ + "at 1970-01-01 00:00:01.000 UTC (epoch=1000)\n"
+ "Intent: first.intent\n"
+ "Package: first.app\n\n"
- + "Shutdown request from INTENT at 1970-01-01 00:00:02.000 UTC (epoch=2000)"
- + "\n"
+ + "Shutdown request from INTENT for reason reason2 "
+ + "at 1970-01-01 00:00:02.000 UTC (epoch=2000)\n"
+ "Intent: second.intent\n"
+ "Package: second.app\n\n",
readFileAsString(dumpFiles[0].getAbsolutePath()));
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 16aa87b3e59c..70006b4950f1 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -178,7 +178,6 @@ import com.android.server.wm.WindowManagerInternal;
import org.junit.After;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
@@ -385,7 +384,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
MockitoAnnotations.initMocks(this);
DeviceIdleInternal deviceIdleInternal = mock(DeviceIdleInternal.class);
- when(deviceIdleInternal.getNotificationWhitelistDuration()).thenReturn(3000L);
+ when(deviceIdleInternal.getNotificationAllowlistDuration()).thenReturn(3000L);
ActivityManagerInternal activityManagerInternal = mock(ActivityManagerInternal.class);
LocalServices.removeServiceForTest(UriGrantsManagerInternal.class);
@@ -3774,6 +3773,27 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
}
@Test
+ public void testEnqueuedAdjustmentAppliesAdjustments_MultiNotifications() throws Exception {
+ final NotificationRecord r1 = generateNotificationRecord(mTestNotificationChannel);
+ final NotificationRecord r2 = generateNotificationRecord(mTestNotificationChannel);
+ mService.addEnqueuedNotification(r1);
+ mService.addEnqueuedNotification(r2);
+ when(mAssistants.isSameUser(eq(null), anyInt())).thenReturn(true);
+
+ Bundle signals = new Bundle();
+ signals.putInt(Adjustment.KEY_IMPORTANCE,
+ IMPORTANCE_HIGH);
+ Adjustment adjustment = new Adjustment(
+ r1.getSbn().getPackageName(), r1.getKey(), signals,
+ "", r1.getUser().getIdentifier());
+
+ mBinderService.applyEnqueuedAdjustmentFromAssistant(null, adjustment);
+
+ assertEquals(IMPORTANCE_HIGH, r1.getImportance());
+ assertEquals(IMPORTANCE_HIGH, r2.getImportance());
+ }
+
+ @Test
public void testRestore() throws Exception {
int systemChecks = mService.countSystemChecks;
mBinderService.applyRestore(null, USER_SYSTEM);
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationShellCmdTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationShellCmdTest.java
index 00061931b18d..fcff228fb591 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationShellCmdTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationShellCmdTest.java
@@ -215,20 +215,14 @@ public class NotificationShellCmdTest extends UiServiceTestCase {
"Charlotte"
};
static final String[] MESSAGES = {
- "Shall I compare thee to a summer's day?",
- "Thou art more lovely and more temperate:",
- "Rough winds do shake the darling buds of May,",
- "And summer's lease hath all too short a date;",
- "Sometime too hot the eye of heaven shines,",
- "And often is his gold complexion dimm'd;",
- "And every fair from fair sometime declines,",
- "By chance or nature's changing course untrimm'd;",
- "But thy eternal summer shall not fade,",
- "Nor lose possession of that fair thou ow'st;",
- "Nor shall death brag thou wander'st in his shade,",
- "When in eternal lines to time thou grow'st:",
- " So long as men can breathe or eyes can see,",
- " So long lives this, and this gives life to thee.",
+ "Who has seen the wind?",
+ "Neither I nor you.",
+ "But when the leaves hang trembling,",
+ "The wind is passing through.",
+ "Who has seen the wind?",
+ "Neither you nor I.",
+ "But when the trees bow down their heads,",
+ "The wind is passing by."
};
@Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java
index c60abe8d51d1..f69d7c332382 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java
@@ -31,6 +31,7 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
import static com.android.server.wm.ActivityStackSupervisor.ON_TOP;
+import static com.android.server.wm.WindowContainer.POSITION_TOP;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -113,7 +114,7 @@ public class ActivityDisplayTests extends ActivityTestsBase {
@Test
public void testStackShouldNotBeFocusedAfterMovingToBackOrRemoving() {
// Create a display which only contains 2 stacks.
- final DisplayContent display = addNewDisplayContentAt(DisplayContent.POSITION_TOP);
+ final DisplayContent display = addNewDisplayContentAt(POSITION_TOP);
final Task stack1 = createFullscreenStackWithSimpleActivityAt(display);
final Task stack2 = createFullscreenStackWithSimpleActivityAt(display);
@@ -228,7 +229,8 @@ public class ActivityDisplayTests extends ActivityTestsBase {
final ActivityRecord activity = new ActivityBuilder(mService).setCreateTask(true)
.setStack(alwaysOnTopStack).build();
alwaysOnTopStack.setAlwaysOnTop(true);
- taskDisplayArea.positionStackAtTop(alwaysOnTopStack, false /* includingParents */);
+ taskDisplayArea.positionChildAt(POSITION_TOP, alwaysOnTopStack,
+ false /* includingParents */);
assertTrue(alwaysOnTopStack.isAlwaysOnTop());
// Ensure always on top state is synced to the children of the stack.
assertTrue(alwaysOnTopStack.getTopNonFinishingActivity().isAlwaysOnTop());
@@ -242,7 +244,8 @@ public class ActivityDisplayTests extends ActivityTestsBase {
final Task anotherAlwaysOnTopStack = taskDisplayArea.createStack(
WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD, true /* onTop */);
anotherAlwaysOnTopStack.setAlwaysOnTop(true);
- taskDisplayArea.positionStackAtTop(anotherAlwaysOnTopStack, false /* includingParents */);
+ taskDisplayArea.positionChildAt(POSITION_TOP, anotherAlwaysOnTopStack,
+ false /* includingParents */);
assertTrue(anotherAlwaysOnTopStack.isAlwaysOnTop());
int topPosition = taskDisplayArea.getStackCount() - 1;
// Ensure the new alwaysOnTop stack is put below the pinned stack, but on top of the
@@ -258,7 +261,8 @@ public class ActivityDisplayTests extends ActivityTestsBase {
assertEquals(nonAlwaysOnTopStack, taskDisplayArea.getStackAt(topPosition - 3));
anotherAlwaysOnTopStack.setAlwaysOnTop(false);
- taskDisplayArea.positionStackAtTop(anotherAlwaysOnTopStack, false /* includingParents */);
+ taskDisplayArea.positionChildAt(POSITION_TOP, anotherAlwaysOnTopStack,
+ false /* includingParents */);
assertFalse(anotherAlwaysOnTopStack.isAlwaysOnTop());
// Ensure, when always on top is turned off for a stack, the stack is put just below all
// other always on top stacks.
@@ -325,7 +329,7 @@ public class ActivityDisplayTests extends ActivityTestsBase {
// Reordering stacks while removing stacks.
doAnswer(invocation -> {
- taskDisplayArea.positionStackAtTop(stack3, false);
+ taskDisplayArea.positionChildAt(POSITION_TOP, stack3, false /*includingParents*/);
return true;
}).when(mSupervisor).removeTask(eq(task4), anyBoolean(), anyBoolean(), any());
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
index 5153af2b0d6b..775df74f88e0 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
@@ -48,6 +48,7 @@ import static com.android.server.wm.Task.STACK_VISIBILITY_INVISIBLE;
import static com.android.server.wm.Task.STACK_VISIBILITY_VISIBLE;
import static com.android.server.wm.Task.STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT;
import static com.android.server.wm.TaskDisplayArea.getStackAbove;
+import static com.android.server.wm.WindowContainer.POSITION_BOTTOM;
import static com.android.server.wm.WindowContainer.POSITION_TOP;
import static com.google.common.truth.Truth.assertThat;
@@ -210,7 +211,7 @@ public class ActivityStackTests extends ActivityTestsBase {
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME);
final Task secondaryTask = mDefaultTaskDisplayArea.createStack(
WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, ACTIVITY_TYPE_STANDARD, true /* onTop */);
- mDefaultTaskDisplayArea.positionStackAtTop(organizer.mPrimary,
+ mDefaultTaskDisplayArea.positionChildAt(POSITION_TOP, organizer.mPrimary,
false /* includingParents */);
// Move primary to back.
@@ -988,18 +989,14 @@ public class ActivityStackTests extends ActivityTestsBase {
@SuppressWarnings("TypeParameterUnusedInFormals")
private Task createStackForShouldBeVisibleTest(
TaskDisplayArea taskDisplayArea, int windowingMode, int activityType, boolean onTop) {
- final Task stack;
+ final Task task;
if (activityType == ACTIVITY_TYPE_HOME) {
// Home stack and activity are created in ActivityTestsBase#setupActivityManagerService
- stack = mDefaultTaskDisplayArea.getStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME);
- if (onTop) {
- mDefaultTaskDisplayArea.positionStackAtTop(stack,
- false /* includingParents */);
- } else {
- mDefaultTaskDisplayArea.positionStackAtBottom(stack);
- }
+ task = mDefaultTaskDisplayArea.getStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME);
+ mDefaultTaskDisplayArea.positionChildAt(onTop ? POSITION_TOP : POSITION_BOTTOM, task,
+ false /* includingParents */);
} else {
- stack = new StackBuilder(mRootWindowContainer)
+ task = new StackBuilder(mRootWindowContainer)
.setTaskDisplayArea(taskDisplayArea)
.setWindowingMode(windowingMode)
.setActivityType(activityType)
@@ -1007,7 +1004,7 @@ public class ActivityStackTests extends ActivityTestsBase {
.setCreateActivity(true)
.build();
}
- return stack;
+ return task;
}
@Test
@@ -1256,7 +1253,8 @@ public class ActivityStackTests extends ActivityTestsBase {
mDefaultTaskDisplayArea, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD,
true /* onTop */);
mDefaultTaskDisplayArea.registerStackOrderChangedListener(listener);
- mDefaultTaskDisplayArea.positionStackAtBottom(fullscreenStack1);
+ mDefaultTaskDisplayArea.positionChildAt(POSITION_BOTTOM, fullscreenStack1,
+ false /*includingParents*/);
} finally {
mDefaultTaskDisplayArea.unregisterStackOrderChangedListener(listener);
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
index 3772e2500c1b..d07000f30046 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -74,6 +74,7 @@ import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManagerInternal;
import android.graphics.Rect;
+import android.os.Binder;
import android.os.IBinder;
import android.os.Process;
import android.os.RemoteException;
@@ -665,7 +666,9 @@ public class ActivityStarterTests extends ActivityTestsBase {
mService.mStackSupervisor.setRecentTasks(recentTasks);
doReturn(callerIsRecents).when(recentTasks).isCallerRecents(callingUid);
// caller is temp allowed
- callerApp.setAllowBackgroundActivityStarts(callerIsTempAllowed);
+ if (callerIsTempAllowed) {
+ callerApp.addAllowBackgroundActivityStartsToken(new Binder(), null);
+ }
// caller is instrumenting with background activity starts privileges
callerApp.setInstrumenting(callerIsInstrumentingWithBackgroundActivityStartPrivileges,
callerIsInstrumentingWithBackgroundActivityStartPrivileges);
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
index d7baf8d05bd6..7adceade0b9b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
@@ -129,36 +129,6 @@ public class AppTransitionControllerTest extends WindowTestsBase {
}
@Test
- public void testGetAnimationTargets_noHierarchicalAnimations() {
- WindowManagerService.sHierarchicalAnimations = false;
-
- // [DisplayContent] -+- [TaskStack1] - [Task1] - [ActivityRecord1] (opening, invisible)
- // +- [TaskStack2] - [Task2] - [ActivityRecord2] (closing, visible)
- final Task stack1 = createTaskStackOnDisplay(mDisplayContent);
- final ActivityRecord activity1 = WindowTestUtils.createTestActivityRecord(stack1);
- activity1.setVisible(false);
- activity1.mVisibleRequested = true;
-
- final Task stack2 = createTaskStackOnDisplay(mDisplayContent);
- final ActivityRecord activity2 = WindowTestUtils.createTestActivityRecord(stack2);
-
- final ArraySet<ActivityRecord> opening = new ArraySet<>();
- opening.add(activity1);
- final ArraySet<ActivityRecord> closing = new ArraySet<>();
- closing.add(activity2);
-
- // Don't promote when the flag is disabled.
- assertEquals(
- new ArraySet<>(new WindowContainer[]{activity1}),
- AppTransitionController.getAnimationTargets(
- opening, closing, true /* visible */));
- assertEquals(
- new ArraySet<>(new WindowContainer[]{activity2}),
- AppTransitionController.getAnimationTargets(
- opening, closing, false /* visible */));
- }
-
- @Test
public void testGetAnimationTargets_visibilityAlreadyUpdated() {
// [DisplayContent] -+- [TaskStack1] - [Task1] - [ActivityRecord1] (opening, visible)
// +- [TaskStack2] - [Task2] - [ActivityRecord2] (closing, invisible)
@@ -177,17 +147,6 @@ public class AppTransitionControllerTest extends WindowTestsBase {
// No animation, since visibility of the opening and closing apps are already updated
// outside of AppTransition framework.
- WindowManagerService.sHierarchicalAnimations = false;
- assertEquals(
- new ArraySet<>(),
- AppTransitionController.getAnimationTargets(
- opening, closing, true /* visible */));
- assertEquals(
- new ArraySet<>(),
- AppTransitionController.getAnimationTargets(
- opening, closing, false /* visible */));
-
- WindowManagerService.sHierarchicalAnimations = true;
assertEquals(
new ArraySet<>(),
AppTransitionController.getAnimationTargets(
@@ -221,13 +180,12 @@ public class AppTransitionControllerTest extends WindowTestsBase {
// The visibility are already updated, but since forced transition is requested, it will
// be included.
- WindowManagerService.sHierarchicalAnimations = false;
assertEquals(
- new ArraySet<>(new WindowContainer[]{activity1}),
+ new ArraySet<>(new WindowContainer[]{activity1.getStack()}),
AppTransitionController.getAnimationTargets(
opening, closing, true /* visible */));
assertEquals(
- new ArraySet<>(new WindowContainer[]{activity2}),
+ new ArraySet<>(new WindowContainer[]{activity2.getStack()}),
AppTransitionController.getAnimationTargets(
opening, closing, false /* visible */));
}
@@ -247,13 +205,6 @@ public class AppTransitionControllerTest extends WindowTestsBase {
// Animate closing apps even if it's not visible when it is exiting before we had a chance
// to play the transition animation.
- WindowManagerService.sHierarchicalAnimations = false;
- assertEquals(
- new ArraySet<>(new WindowContainer[]{activity}),
- AppTransitionController.getAnimationTargets(
- new ArraySet<>(), closing, false /* visible */));
-
- WindowManagerService.sHierarchicalAnimations = true;
assertEquals(
new ArraySet<>(new WindowContainer[]{stack}),
AppTransitionController.getAnimationTargets(
@@ -292,17 +243,6 @@ public class AppTransitionControllerTest extends WindowTestsBase {
// Animate opening apps even if it's already visible in case its windows are being replaced.
// Don't animate closing apps if it's already invisible even though its windows are being
// replaced.
- WindowManagerService.sHierarchicalAnimations = false;
- assertEquals(
- new ArraySet<>(new WindowContainer[]{activity1}),
- AppTransitionController.getAnimationTargets(
- opening, closing, true /* visible */));
- assertEquals(
- new ArraySet<>(new WindowContainer[]{}),
- AppTransitionController.getAnimationTargets(
- opening, closing, false /* visible */));
-
- WindowManagerService.sHierarchicalAnimations = true;
assertEquals(
new ArraySet<>(new WindowContainer[]{stack1}),
AppTransitionController.getAnimationTargets(
@@ -315,8 +255,6 @@ public class AppTransitionControllerTest extends WindowTestsBase {
@Test
public void testGetAnimationTargets_openingClosingInDifferentTask() {
- WindowManagerService.sHierarchicalAnimations = true;
-
// [DisplayContent] -+- [TaskStack1] - [Task1] -+- [ActivityRecord1] (opening, invisible)
// | +- [ActivityRecord2] (invisible)
// |
@@ -361,8 +299,6 @@ public class AppTransitionControllerTest extends WindowTestsBase {
@Test
public void testGetAnimationTargets_openingClosingInSameTask() {
- WindowManagerService.sHierarchicalAnimations = true;
-
// [DisplayContent] - [TaskStack] - [Task] -+- [ActivityRecord1] (opening, invisible)
// +- [ActivityRecord2] (closing, visible)
final Task stack = createTaskStackOnDisplay(mDisplayContent);
@@ -393,8 +329,6 @@ public class AppTransitionControllerTest extends WindowTestsBase {
@Test
public void testGetAnimationTargets_animateOnlyTranslucentApp() {
- WindowManagerService.sHierarchicalAnimations = true;
-
// [DisplayContent] -+- [TaskStack1] - [Task1] -+- [ActivityRecord1] (opening, invisible)
// | +- [ActivityRecord2] (visible)
// |
@@ -439,8 +373,6 @@ public class AppTransitionControllerTest extends WindowTestsBase {
@Test
public void testGetAnimationTargets_animateTranslucentAndOpaqueApps() {
- WindowManagerService.sHierarchicalAnimations = true;
-
// [DisplayContent] -+- [TaskStack1] - [Task1] -+- [ActivityRecord1] (opening, invisible)
// | +- [ActivityRecord2] (opening, invisible)
// |
@@ -489,8 +421,6 @@ public class AppTransitionControllerTest extends WindowTestsBase {
@Test
public void testGetAnimationTargets_stackContainsMultipleTasks() {
- WindowManagerService.sHierarchicalAnimations = true;
-
// [DisplayContent] - [TaskStack] -+- [Task1] - [ActivityRecord1] (opening, invisible)
// +- [Task2] - [ActivityRecord2] (closing, visible)
final Task stack = createTaskStackOnDisplay(mDisplayContent);
diff --git a/services/tests/wmtests/src/com/android/server/wm/ConfigurationContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/ConfigurationContainerTests.java
index bcd937151046..5828d02948a1 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ConfigurationContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ConfigurationContainerTests.java
@@ -33,6 +33,7 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import android.content.res.Configuration;
+import android.graphics.Rect;
import android.platform.test.annotations.Presubmit;
import androidx.test.filters.SmallTest;
@@ -324,6 +325,47 @@ public class ConfigurationContainerTests {
assertEquals(100, listener.mOverrideConfiguration.smallestScreenWidthDp);
}
+ @Test
+ public void testSetMaxBoundsByHierarchy() {
+ final TestConfigurationContainer root =
+ new TestConfigurationContainer(true /* providesMaxBounds */);
+ final Rect bounds = new Rect(0, 0, 10, 10);
+ final TestConfigurationContainer child = new TestConfigurationContainer();
+ root.addChild(child);
+
+ root.setBounds(bounds);
+
+ assertEquals(bounds, root.getBounds());
+ assertEquals(bounds, root.getConfiguration().windowConfiguration.getBounds());
+ assertEquals(bounds, child.getBounds());
+ assertEquals(bounds, child.getConfiguration().windowConfiguration.getBounds());
+
+ assertEquals(bounds, root.getMaxBounds());
+ assertEquals(bounds, root.getConfiguration().windowConfiguration.getMaxBounds());
+ assertEquals(bounds, child.getMaxBounds());
+ assertEquals(bounds, child.getConfiguration().windowConfiguration.getMaxBounds());
+ }
+
+ @Test
+ public void testSetBoundsNotOverrideMaxBounds() {
+ final TestConfigurationContainer root = new TestConfigurationContainer();
+ final Rect bounds = new Rect(0, 0, 10, 10);
+ final TestConfigurationContainer child = new TestConfigurationContainer();
+ root.addChild(child);
+
+ root.setBounds(bounds);
+
+ assertEquals(bounds, root.getBounds());
+ assertEquals(bounds, root.getConfiguration().windowConfiguration.getBounds());
+ assertEquals(bounds, child.getBounds());
+ assertEquals(bounds, child.getConfiguration().windowConfiguration.getBounds());
+
+ assertTrue(root.getMaxBounds().isEmpty());
+ assertTrue(root.getConfiguration().windowConfiguration.getMaxBounds().isEmpty());
+ assertTrue(child.getMaxBounds().isEmpty());
+ assertTrue(child.getConfiguration().windowConfiguration.getMaxBounds().isEmpty());
+ }
+
/**
* Contains minimal implementation of {@link ConfigurationContainer}'s abstract behavior needed
* for testing.
@@ -333,6 +375,14 @@ public class ConfigurationContainerTests {
private List<TestConfigurationContainer> mChildren = new ArrayList<>();
private TestConfigurationContainer mParent;
+ private boolean mProvidesMaxBounds = false;
+
+ TestConfigurationContainer() {}
+
+ TestConfigurationContainer(boolean providesMaxBounds) {
+ mProvidesMaxBounds = providesMaxBounds;
+ }
+
TestConfigurationContainer addChild(TestConfigurationContainer childContainer) {
final ConfigurationContainer oldParent = childContainer.getParent();
childContainer.mParent = this;
@@ -369,6 +419,11 @@ public class ConfigurationContainerTests {
protected ConfigurationContainer getParent() {
return mParent;
}
+
+ @Override
+ public boolean providesMaxBounds() {
+ return mProvidesMaxBounds;
+ }
}
/**
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaTest.java b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaTest.java
index c8ed87db9d3e..e17601e99010 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaTest.java
@@ -16,6 +16,7 @@
package com.android.server.wm;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_PRESENTATION;
import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
@@ -40,8 +41,10 @@ import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions;
+import android.graphics.Rect;
import android.os.Binder;
import android.platform.test.annotations.Presubmit;
+import android.view.SurfaceControl;
import com.google.android.collect.Lists;
@@ -63,7 +66,6 @@ import java.util.function.Function;
*/
@Presubmit
public class DisplayAreaTest {
-
@Rule
public SystemServicesTestRule mWmsRule = new SystemServicesTestRule();
@@ -379,6 +381,42 @@ public class DisplayAreaTest {
assertThat(result).isEqualTo(tda1);
}
+ @Test
+ public void testSetMaxBounds() {
+ final Rect parentBounds = new Rect(0, 0, 100, 100);
+ final Rect childBounds1 = new Rect(parentBounds.left, parentBounds.top,
+ parentBounds.right / 2, parentBounds.bottom);
+ final Rect childBounds2 = new Rect(parentBounds.right / 2, parentBounds.top,
+ parentBounds.right, parentBounds.bottom);
+ TestDisplayArea parentDa = new TestDisplayArea(mWms, parentBounds);
+ TestDisplayArea childDa1 = new TestDisplayArea(mWms, childBounds1);
+ TestDisplayArea childDa2 = new TestDisplayArea(mWms, childBounds2);
+ parentDa.addChild(childDa1, 0);
+ parentDa.addChild(childDa2, 1);
+
+ assertEquals(parentBounds, parentDa.getMaxBounds());
+ assertEquals(childBounds1, childDa1.getMaxBounds());
+ assertEquals(childBounds2, childDa2.getMaxBounds());
+
+ final WindowToken windowToken = createWindowToken(TYPE_APPLICATION);
+ childDa1.addChild(windowToken, 0);
+
+ assertEquals("DisplayArea's children must have the same max bounds as itself",
+ childBounds1, windowToken.getMaxBounds());
+ }
+
+ private static class TestDisplayArea<T extends WindowContainer> extends DisplayArea<T> {
+ private TestDisplayArea(WindowManagerService wms, Rect bounds) {
+ super(wms, ANY, "half display area");
+ setBounds(bounds);
+ }
+
+ @Override
+ SurfaceControl.Builder makeChildSurface(WindowContainer child) {
+ return new MockSurfaceControlBuilder();
+ }
+ }
+
private WindowToken createWindowToken(int type) {
return new WindowToken(mWmsRule.getWindowManagerService(), new Binder(),
type, false /* persist */, null /* displayContent */,
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
index 96ea64667f6e..edf15361e445 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -1354,7 +1354,7 @@ public class DisplayContentTests extends WindowTestsBase {
assertFalse(displayRotation.updateRotationUnchecked(false));
// Rotation can be updated if the recents animation is finished.
- mDisplayContent.mFixedRotationTransitionListener.onFinishRecentsAnimation(false);
+ mDisplayContent.mFixedRotationTransitionListener.onFinishRecentsAnimation();
assertTrue(displayRotation.updateRotationUnchecked(false));
// Rotation can be updated if the recents animation is animating but it is not on top, e.g.
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
index 695a0e3881ea..8bc8c0b1169f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
@@ -362,13 +362,14 @@ public class RecentsAnimationControllerTest extends WindowTestsBase {
assertFalse(homeActivity.hasFixedRotationTransform());
}
- @Test
- public void testClearFixedRotationLaunchingAppAfterCleanupAnimation() {
- unblockDisplayRotation(mDefaultDisplay);
+ private ActivityRecord prepareFixedRotationLaunchingAppWithRecentsAnim() {
final ActivityRecord homeActivity = createHomeActivity();
homeActivity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
final ActivityRecord activity = createActivityRecord(mDefaultDisplay,
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
+ // Add a window so it can be animated by the recents.
+ final WindowState win = createWindow(null, TYPE_BASE_APPLICATION, activity, "win");
+ activity.addWindow(win);
// Assume an activity is launching to different rotation.
mDefaultDisplay.setFixedRotationLaunchingApp(activity,
(mDefaultDisplay.getRotation() + 1) % 4);
@@ -379,6 +380,14 @@ public class RecentsAnimationControllerTest extends WindowTestsBase {
// Before the transition is done, the recents animation is triggered.
initializeRecentsAnimationController(mController, homeActivity);
assertFalse(homeActivity.hasFixedRotationTransform());
+ assertTrue(mController.isAnimatingTask(activity.getTask()));
+
+ return activity;
+ }
+
+ @Test
+ public void testClearFixedRotationLaunchingAppAfterCleanupAnimation() {
+ final ActivityRecord activity = prepareFixedRotationLaunchingAppWithRecentsAnim();
// Simulate giving up the swipe up gesture to keep the original activity as top.
mController.cleanupAnimation(REORDER_MOVE_TO_ORIGINAL_POSITION);
@@ -388,6 +397,21 @@ public class RecentsAnimationControllerTest extends WindowTestsBase {
}
@Test
+ public void testKeepFixedRotationWhenMovingRecentsToTop() {
+ final ActivityRecord activity = prepareFixedRotationLaunchingAppWithRecentsAnim();
+ // Assume a transition animation has started running before recents animation. Then the
+ // activity will receive onAnimationFinished that notifies app transition finished when
+ // removing the recents animation of task.
+ activity.getTask().getAnimationSources().add(activity);
+
+ // Simulate swiping to home/recents before the transition is done.
+ mController.cleanupAnimation(REORDER_MOVE_TO_TOP);
+ // The rotation transform should be preserved. In real case, it will be cleared by the next
+ // move-to-top transition.
+ assertTrue(activity.hasFixedRotationTransform());
+ }
+
+ @Test
public void testWallpaperHasFixedRotationApplied() {
unblockDisplayRotation(mDefaultDisplay);
mWm.setRecentsAnimationController(mController);
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java
index e3cfe11df99f..e5d1e465d8ff 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java
@@ -33,6 +33,7 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
import static com.android.server.wm.RecentsAnimationController.REORDER_KEEP_IN_PLACE;
import static com.android.server.wm.Task.ActivityState.PAUSED;
+import static com.android.server.wm.WindowContainer.POSITION_TOP;
import static com.google.common.truth.Truth.assertThat;
@@ -118,7 +119,8 @@ public class RecentsAnimationTest extends ActivityTestsBase {
TaskDisplayArea defaultTaskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea();
final Task homeStack =
defaultTaskDisplayArea.getStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME);
- defaultTaskDisplayArea.positionStackAtTop(homeStack, false /* includingParents */);
+ defaultTaskDisplayArea.positionChildAt(POSITION_TOP, homeStack,
+ false /* includingParents */);
ActivityRecord topRunningHomeActivity = homeStack.topRunningActivity();
if (topRunningHomeActivity == null) {
topRunningHomeActivity = new ActivityBuilder(mService)
diff --git a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
index 3a5d33396c3a..74be2c979668 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
@@ -40,6 +40,7 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
import static com.android.server.wm.ActivityStackSupervisor.ON_TOP;
import static com.android.server.wm.RootWindowContainer.MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE;
import static com.android.server.wm.Task.ActivityState.STOPPED;
+import static com.android.server.wm.WindowContainer.POSITION_BOTTOM;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -459,7 +460,7 @@ public class RootActivityContainerTests extends ActivityTestsBase {
ACTIVITY_TYPE_STANDARD, false /* onTop */));
final Task task = new TaskBuilder(mSupervisor).setStack(targetStack).build();
final ActivityRecord activity = new ActivityBuilder(mService).setTask(task).build();
- taskDisplayArea.positionStackAtBottom(targetStack);
+ taskDisplayArea.positionChildAt(POSITION_BOTTOM, targetStack, false /*includingParents*/);
// Assume the stack is not at the topmost position (e.g. behind always-on-top stacks) but it
// is the current top focused stack.
@@ -560,7 +561,7 @@ public class RootActivityContainerTests extends ActivityTestsBase {
final Task task = new TaskBuilder(mSupervisor).setStack(targetStack).build();
final ActivityRecord activity = new ActivityBuilder(mService).setTask(task).build();
activity.setState(ActivityState.RESUMED, "test");
- taskDisplayArea.positionStackAtBottom(targetStack);
+ taskDisplayArea.positionChildAt(POSITION_BOTTOM, targetStack, false /*includingParents*/);
// Assume the stack is at the topmost position
assertFalse(targetStack.isTopStackInDisplayArea());
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
index bd52e9a294fc..800a5d42ce09 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
@@ -53,7 +53,6 @@ import static org.mockito.ArgumentMatchers.anyInt;
import android.app.ActivityManager;
import android.app.ActivityManager.RunningTaskInfo;
import android.app.ActivityManager.StackInfo;
-import android.app.IRequestFinishCallback;
import android.app.PictureInPictureParams;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
@@ -976,8 +975,7 @@ public class WindowOrganizerTests extends WindowTestsBase {
assertTrue(stack.isOrganized());
// Verify a back pressed does not call the organizer
- mWm.mAtmService.onBackPressedOnTaskRoot(activity.token,
- new IRequestFinishCallback.Default());
+ mWm.mAtmService.onBackPressedOnTaskRoot(activity.token);
verify(organizer, never()).onBackPressedOnTaskRoot(any());
// Enable intercepting back
@@ -985,8 +983,7 @@ public class WindowOrganizerTests extends WindowTestsBase {
true);
// Verify now that the back press does call the organizer
- mWm.mAtmService.onBackPressedOnTaskRoot(activity.token,
- new IRequestFinishCallback.Default());
+ mWm.mAtmService.onBackPressedOnTaskRoot(activity.token);
verify(organizer, times(1)).onBackPressedOnTaskRoot(any());
}
diff --git a/services/usb/java/com/android/server/usb/UsbAlsaManager.java b/services/usb/java/com/android/server/usb/UsbAlsaManager.java
index 5239d976e66f..22629dd52608 100644
--- a/services/usb/java/com/android/server/usb/UsbAlsaManager.java
+++ b/services/usb/java/com/android/server/usb/UsbAlsaManager.java
@@ -64,7 +64,7 @@ public final class UsbAlsaManager {
private UsbAlsaDevice mSelectedDevice;
//
- // Device Blacklist
+ // Device Denylist
//
// This exists due to problems with Sony game controllers which present as an audio device
// even if no headset is connected and have no way to set the volume on the unit.
@@ -73,31 +73,31 @@ public final class UsbAlsaManager {
private static final int USB_PRODUCTID_PS4CONTROLLER_ZCT1 = 0x05C4;
private static final int USB_PRODUCTID_PS4CONTROLLER_ZCT2 = 0x09CC;
- private static final int USB_BLACKLIST_OUTPUT = 0x0001;
- private static final int USB_BLACKLIST_INPUT = 0x0002;
+ private static final int USB_DENYLIST_OUTPUT = 0x0001;
+ private static final int USB_DENYLIST_INPUT = 0x0002;
- private static class BlackListEntry {
+ private static class DenyListEntry {
final int mVendorId;
final int mProductId;
final int mFlags;
- BlackListEntry(int vendorId, int productId, int flags) {
+ DenyListEntry(int vendorId, int productId, int flags) {
mVendorId = vendorId;
mProductId = productId;
mFlags = flags;
}
}
- static final List<BlackListEntry> sDeviceBlacklist = Arrays.asList(
- new BlackListEntry(USB_VENDORID_SONY,
+ static final List<DenyListEntry> sDeviceDenylist = Arrays.asList(
+ new DenyListEntry(USB_VENDORID_SONY,
USB_PRODUCTID_PS4CONTROLLER_ZCT1,
- USB_BLACKLIST_OUTPUT),
- new BlackListEntry(USB_VENDORID_SONY,
+ USB_DENYLIST_OUTPUT),
+ new DenyListEntry(USB_VENDORID_SONY,
USB_PRODUCTID_PS4CONTROLLER_ZCT2,
- USB_BLACKLIST_OUTPUT));
+ USB_DENYLIST_OUTPUT));
- private static boolean isDeviceBlacklisted(int vendorId, int productId, int flags) {
- for (BlackListEntry entry : sDeviceBlacklist) {
+ private static boolean isDeviceDenylisted(int vendorId, int productId, int flags) {
+ for (DenyListEntry entry : sDeviceDenylist) {
if (entry.mVendorId == vendorId && entry.mProductId == productId) {
// see if the type flag is set
return (entry.mFlags & flags) != 0;
@@ -226,11 +226,11 @@ public final class UsbAlsaManager {
// Add it to the devices list
boolean hasInput = parser.hasInput()
- && !isDeviceBlacklisted(usbDevice.getVendorId(), usbDevice.getProductId(),
- USB_BLACKLIST_INPUT);
+ && !isDeviceDenylisted(usbDevice.getVendorId(), usbDevice.getProductId(),
+ USB_DENYLIST_INPUT);
boolean hasOutput = parser.hasOutput()
- && !isDeviceBlacklisted(usbDevice.getVendorId(), usbDevice.getProductId(),
- USB_BLACKLIST_OUTPUT);
+ && !isDeviceDenylisted(usbDevice.getVendorId(), usbDevice.getProductId(),
+ USB_DENYLIST_OUTPUT);
if (DEBUG) {
Slog.d(TAG, "hasInput: " + hasInput + " hasOutput:" + hasOutput);
}
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index 6cf0eecc6352..2269e1d070b1 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -201,22 +201,22 @@ public class UsbDeviceManager implements ActivityTaskManagerInternal.ScreenObser
private String[] mAccessoryStrings;
private final UEventObserver mUEventObserver;
- private static Set<Integer> sBlackListedInterfaces;
+ private static Set<Integer> sDenyInterfaces;
private HashMap<Long, FileDescriptor> mControlFds;
static {
- sBlackListedInterfaces = new HashSet<>();
- sBlackListedInterfaces.add(UsbConstants.USB_CLASS_AUDIO);
- sBlackListedInterfaces.add(UsbConstants.USB_CLASS_COMM);
- sBlackListedInterfaces.add(UsbConstants.USB_CLASS_HID);
- sBlackListedInterfaces.add(UsbConstants.USB_CLASS_PRINTER);
- sBlackListedInterfaces.add(UsbConstants.USB_CLASS_MASS_STORAGE);
- sBlackListedInterfaces.add(UsbConstants.USB_CLASS_HUB);
- sBlackListedInterfaces.add(UsbConstants.USB_CLASS_CDC_DATA);
- sBlackListedInterfaces.add(UsbConstants.USB_CLASS_CSCID);
- sBlackListedInterfaces.add(UsbConstants.USB_CLASS_CONTENT_SEC);
- sBlackListedInterfaces.add(UsbConstants.USB_CLASS_VIDEO);
- sBlackListedInterfaces.add(UsbConstants.USB_CLASS_WIRELESS_CONTROLLER);
+ sDenyInterfaces = new HashSet<>();
+ sDenyInterfaces.add(UsbConstants.USB_CLASS_AUDIO);
+ sDenyInterfaces.add(UsbConstants.USB_CLASS_COMM);
+ sDenyInterfaces.add(UsbConstants.USB_CLASS_HID);
+ sDenyInterfaces.add(UsbConstants.USB_CLASS_PRINTER);
+ sDenyInterfaces.add(UsbConstants.USB_CLASS_MASS_STORAGE);
+ sDenyInterfaces.add(UsbConstants.USB_CLASS_HUB);
+ sDenyInterfaces.add(UsbConstants.USB_CLASS_CDC_DATA);
+ sDenyInterfaces.add(UsbConstants.USB_CLASS_CSCID);
+ sDenyInterfaces.add(UsbConstants.USB_CLASS_CONTENT_SEC);
+ sDenyInterfaces.add(UsbConstants.USB_CLASS_VIDEO);
+ sDenyInterfaces.add(UsbConstants.USB_CLASS_WIRELESS_CONTROLLER);
}
/*
@@ -960,7 +960,7 @@ public class UsbDeviceManager implements ActivityTaskManagerInternal.ScreenObser
while (interfaceCount >= 0) {
UsbInterface intrface = config.getInterface(interfaceCount);
interfaceCount--;
- if (sBlackListedInterfaces.contains(intrface.getInterfaceClass())) {
+ if (sDenyInterfaces.contains(intrface.getInterfaceClass())) {
mHideUsbNotification = true;
break;
}
diff --git a/services/usb/java/com/android/server/usb/UsbHostManager.java b/services/usb/java/com/android/server/usb/UsbHostManager.java
index 140a95d61100..f33001c9241e 100644
--- a/services/usb/java/com/android/server/usb/UsbHostManager.java
+++ b/services/usb/java/com/android/server/usb/UsbHostManager.java
@@ -62,7 +62,7 @@ public class UsbHostManager {
private final Context mContext;
// USB busses to exclude from USB host support
- private final String[] mHostBlacklist;
+ private final String[] mHostDenyList;
private final UsbAlsaManager mUsbAlsaManager;
private final UsbPermissionManager mPermissionManager;
@@ -235,8 +235,8 @@ public class UsbHostManager {
UsbPermissionManager permissionManager) {
mContext = context;
- mHostBlacklist = context.getResources().getStringArray(
- com.android.internal.R.array.config_usbHostBlacklist);
+ mHostDenyList = context.getResources().getStringArray(
+ com.android.internal.R.array.config_usbHostDenylist);
mUsbAlsaManager = alsaManager;
mPermissionManager = permissionManager;
String deviceConnectionHandler = context.getResources().getString(
@@ -271,10 +271,10 @@ public class UsbHostManager {
}
}
- private boolean isBlackListed(String deviceAddress) {
- int count = mHostBlacklist.length;
+ private boolean isDenyListed(String deviceAddress) {
+ int count = mHostDenyList.length;
for (int i = 0; i < count; i++) {
- if (deviceAddress.startsWith(mHostBlacklist[i])) {
+ if (deviceAddress.startsWith(mHostDenyList[i])) {
return true;
}
}
@@ -282,11 +282,11 @@ public class UsbHostManager {
}
/* returns true if the USB device should not be accessible by applications */
- private boolean isBlackListed(int clazz, int subClass) {
- // blacklist hubs
+ private boolean isDenyListed(int clazz, int subClass) {
+ // deny hubs
if (clazz == UsbConstants.USB_CLASS_HUB) return true;
- // blacklist HID boot devices (mouse and keyboard)
+ // deny HID boot devices (mouse and keyboard)
return clazz == UsbConstants.USB_CLASS_HID
&& subClass == UsbConstants.USB_INTERFACE_SUBCLASS_BOOT;
@@ -355,23 +355,23 @@ public class UsbHostManager {
Slog.d(TAG, "usbDeviceAdded(" + deviceAddress + ") - start");
}
- if (isBlackListed(deviceAddress)) {
+ if (isDenyListed(deviceAddress)) {
if (DEBUG) {
- Slog.d(TAG, "device address is black listed");
+ Slog.d(TAG, "device address is Deny listed");
}
return false;
}
- if (isBlackListed(deviceClass, deviceSubclass)) {
+ if (isDenyListed(deviceClass, deviceSubclass)) {
if (DEBUG) {
- Slog.d(TAG, "device class is black listed");
+ Slog.d(TAG, "device class is deny listed");
}
return false;
}
UsbDescriptorParser parser = new UsbDescriptorParser(deviceAddress, descriptors);
if (deviceClass == UsbConstants.USB_CLASS_PER_INTERFACE
- && !checkUsbInterfacesBlackListed(parser)) {
+ && !checkUsbInterfacesDenyListed(parser)) {
return false;
}
@@ -491,12 +491,12 @@ public class UsbHostManager {
public ParcelFileDescriptor openDevice(String deviceAddress,
UsbUserPermissionManager permissions, String packageName, int pid, int uid) {
synchronized (mLock) {
- if (isBlackListed(deviceAddress)) {
+ if (isDenyListed(deviceAddress)) {
throw new SecurityException("USB device is on a restricted bus");
}
UsbDevice device = mDevices.get(deviceAddress);
if (device == null) {
- // if it is not in mDevices, it either does not exist or is blacklisted
+ // if it is not in mDevices, it either does not exist or is denylisted
throw new IllegalArgumentException(
"device " + deviceAddress + " does not exist or is restricted");
}
@@ -554,23 +554,23 @@ public class UsbHostManager {
}
}
- private boolean checkUsbInterfacesBlackListed(UsbDescriptorParser parser) {
+ private boolean checkUsbInterfacesDenyListed(UsbDescriptorParser parser) {
// Device class needs to be obtained through the device interface. Ignore device only
- // if ALL interfaces are black-listed.
+ // if ALL interfaces are deny-listed.
boolean shouldIgnoreDevice = false;
for (UsbDescriptor descriptor: parser.getDescriptors()) {
if (!(descriptor instanceof UsbInterfaceDescriptor)) {
continue;
}
UsbInterfaceDescriptor iface = (UsbInterfaceDescriptor) descriptor;
- shouldIgnoreDevice = isBlackListed(iface.getUsbClass(), iface.getUsbSubclass());
+ shouldIgnoreDevice = isDenyListed(iface.getUsbClass(), iface.getUsbSubclass());
if (!shouldIgnoreDevice) {
break;
}
}
if (shouldIgnoreDevice) {
if (DEBUG) {
- Slog.d(TAG, "usb interface class is black listed");
+ Slog.d(TAG, "usb interface class is deny listed");
}
return false;
}
diff --git a/services/usb/java/com/android/server/usb/UsbPortManager.java b/services/usb/java/com/android/server/usb/UsbPortManager.java
index 1025bf5d67b0..ec7d4bd0d8c0 100644
--- a/services/usb/java/com/android/server/usb/UsbPortManager.java
+++ b/services/usb/java/com/android/server/usb/UsbPortManager.java
@@ -922,7 +922,7 @@ public class UsbPortManager {
contaminantDetectionStatus);
mPorts.put(portId, portInfo);
} else {
- // Sanity check that ports aren't changing definition out from under us.
+ // Validate that ports aren't changing definition out from under us.
if (supportedModes != portInfo.mUsbPort.getSupportedModes()) {
logAndPrint(Log.WARN, pw, "Ignoring inconsistent list of supported modes from "
+ "USB port driver (should be immutable): "
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
index 6c13cd799bc2..534fe036ba87 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
@@ -697,7 +697,7 @@ public class SoundTriggerService extends SystemService {
synchronized (mLock) {
ModuleProperties properties = mSoundTriggerHelper.getModuleProperties();
sEventLogger.log(new SoundTriggerLogger.StringEvent(
- "getModuleProperties(): " + properties.toString()));
+ "getModuleProperties(): " + properties));
return properties;
}
}
diff --git a/telecomm/TEST_MAPPING b/telecomm/TEST_MAPPING
index d58566673eec..c9903f9fa901 100644
--- a/telecomm/TEST_MAPPING
+++ b/telecomm/TEST_MAPPING
@@ -23,6 +23,14 @@
"exclude-annotation": "androidx.test.filters.FlakyTest"
}
]
+ },
+ {
+ "name": "CtsTelecomTestCases",
+ "options": [
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ }
+ ]
}
]
}
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index 3365ab740cde..0469fa56e648 100755
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -462,15 +462,15 @@ public final class Call {
/**
* Call supports adding participants to the call via
- * {@link #addConferenceParticipants(List)}.
- * @hide
+ * {@link #addConferenceParticipants(List)}. Once participants are added, the call becomes
+ * an adhoc conference call ({@link #PROPERTY_IS_ADHOC_CONFERENCE}).
*/
public static final int CAPABILITY_ADD_PARTICIPANT = 0x02000000;
/**
* When set for a call, indicates that this {@code Call} can be transferred to another
* number.
- * Call supports the blind and assured call transfer feature.
+ * Call supports the confirmed and unconfirmed call transfer feature.
*
* @hide
*/
@@ -599,8 +599,11 @@ public final class Call {
/**
* Indicates that the call is an adhoc conference call. This property can be set for both
- * incoming and outgoing calls.
- * @hide
+ * incoming and outgoing calls. An adhoc conference call is formed using
+ * {@link #addConferenceParticipants(List)},
+ * {@link TelecomManager#addNewIncomingConference(PhoneAccountHandle, Bundle)}, or
+ * {@link TelecomManager#startConference(List, Bundle)}, rather than by merging existing
+ * call using {@link #conference(Call)}.
*/
public static final int PROPERTY_IS_ADHOC_CONFERENCE = 0x00002000;
@@ -1593,8 +1596,8 @@ public final class Call {
* Instructs this {@code Call} to be transferred to another number.
*
* @param targetNumber The address to which the call will be transferred.
- * @param isConfirmationRequired if {@code true} it will initiate ASSURED transfer,
- * if {@code false}, it will initiate BLIND transfer.
+ * @param isConfirmationRequired if {@code true} it will initiate a confirmed transfer,
+ * if {@code false}, it will initiate an unconfirmed transfer.
*
* @hide
*/
@@ -1775,7 +1778,6 @@ public final class Call {
* See {@link Details#CAPABILITY_ADD_PARTICIPANT}.
*
* @param participants participants to be pulled to existing call.
- * @hide
*/
public void addConferenceParticipants(@NonNull List<Uri> participants) {
mInCallAdapter.addConferenceParticipants(mTelecomCallId, participants);
diff --git a/telecomm/java/android/telecom/Conference.java b/telecomm/java/android/telecom/Conference.java
index d9605522b3b0..39c3ff9e8839 100644
--- a/telecomm/java/android/telecom/Conference.java
+++ b/telecomm/java/android/telecom/Conference.java
@@ -181,8 +181,8 @@ public abstract class Conference extends Conferenceable {
/**
* Returns whether this conference is requesting that the system play a ringback tone
- * on its behalf.
- * @hide
+ * on its behalf. A ringback tone may be played when an outgoing conference is in the process of
+ * connecting to give the user an audible indication of that process.
*/
public final boolean isRingbackRequested() {
return mRingbackRequested;
@@ -329,7 +329,6 @@ public abstract class Conference extends Conferenceable {
/**
* Notifies the {@link Conference} of a request to add a new participants to the conference call
* @param participants that will be added to this conference call
- * @hide
*/
public void onAddConferenceParticipants(@NonNull List<Uri> participants) {}
@@ -340,7 +339,6 @@ public abstract class Conference extends Conferenceable {
* the default dialer's {@link InCallService}.
*
* @param videoState The video state in which to answer the connection.
- * @hide
*/
public void onAnswer(int videoState) {}
@@ -360,7 +358,6 @@ public abstract class Conference extends Conferenceable {
* a request to reject.
* For managed {@link ConnectionService}s, this will be called when the user rejects a call via
* the default dialer's {@link InCallService}.
- * @hide
*/
public void onReject() {}
@@ -380,7 +377,6 @@ public abstract class Conference extends Conferenceable {
/**
* Sets state to be ringing.
- * @hide
*/
public final void setRinging() {
setState(Connection.STATE_RINGING);
@@ -506,7 +502,6 @@ public abstract class Conference extends Conferenceable {
* that do not play a ringback tone themselves in the conference's audio stream.
*
* @param ringback Whether the ringback tone is to be played.
- * @hide
*/
public final void setRingbackRequested(boolean ringback) {
if (mRingbackRequested != ringback) {
@@ -773,7 +768,6 @@ public abstract class Conference extends Conferenceable {
*
* @param disconnectCause The disconnect cause, ({@see android.telecomm.DisconnectCause}).
* @return A {@code Conference} which indicates failure.
- * @hide
*/
public @NonNull static Conference createFailedConference(
@NonNull DisconnectCause disconnectCause, @NonNull PhoneAccountHandle phoneAccount) {
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index fa9909547fc4..00b711643fe6 100755
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -383,15 +383,17 @@ public abstract class Connection extends Conferenceable {
/**
* When set, indicates that this {@link Connection} supports initiation of a conference call
- * by directly adding participants using {@link #onAddConferenceParticipants(List)}.
- * @hide
+ * by directly adding participants using {@link #onAddConferenceParticipants(List)}. When
+ * participants are added to a {@link Connection}, it will be replaced by a {@link Conference}
+ * instance with {@link #PROPERTY_IS_ADHOC_CONFERENCE} set to indicate that it is an adhoc
+ * conference call.
*/
public static final int CAPABILITY_ADD_PARTICIPANT = 0x04000000;
/**
* Indicates that this {@code Connection} can be transferred to another
* number.
- * Connection supports the blind and assured call transfer feature.
+ * Connection supports the confirmed and unconfirmed call transfer feature.
* @hide
*/
public static final int CAPABILITY_TRANSFER = 0x08000000;
@@ -526,10 +528,9 @@ public abstract class Connection extends Conferenceable {
public static final int PROPERTY_REMOTELY_HOSTED = 1 << 11;
/**
- * Set by the framework to indicate that it is an adhoc conference call.
+ * Set by the framework to indicate that a call is an adhoc conference call.
* <p>
- * This is used for Outgoing and incoming conference calls.
- * @hide
+ * This is used for outgoing and incoming conference calls.
*/
public static final int PROPERTY_IS_ADHOC_CONFERENCE = 1 << 12;
@@ -3034,7 +3035,6 @@ public abstract class Connection extends Conferenceable {
* Supports initiation of a conference call by directly adding participants to an ongoing call.
*
* @param participants with which conference call will be formed.
- * @hide
*/
public void onAddConferenceParticipants(@NonNull List<Uri> participants) {}
diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java
index 56cba1d3f913..3646647e9734 100755
--- a/telecomm/java/android/telecom/ConnectionService.java
+++ b/telecomm/java/android/telecom/ConnectionService.java
@@ -1880,6 +1880,7 @@ public abstract class ConnectionService extends Service {
mConferenceById.put(callId, conference);
mIdByConference.put(conference, callId);
+
conference.addListener(mConferenceListener);
ParcelableConference parcelableConference = new ParcelableConference.Builder(
request.getAccountHandle(), conference.getState())
@@ -2678,15 +2679,15 @@ public abstract class ConnectionService extends Service {
return null;
}
/**
- * Create a {@code Connection} given an incoming request. This is used to attach to existing
- * incoming conference call.
+ * Create a {@code Conference} given an incoming request. This is used to attach to an incoming
+ * conference call initiated via
+ * {@link TelecomManager#addNewIncomingConference(PhoneAccountHandle, Bundle)}.
*
* @param connectionManagerPhoneAccount See description at
* {@link #onCreateOutgoingConnection(PhoneAccountHandle, ConnectionRequest)}.
- * @param request Details about the incoming call.
- * @return The {@code Connection} object to satisfy this call, or {@code null} to
+ * @param request Details about the incoming conference call.
+ * @return The {@code Conference} object to satisfy this call, or {@code null} to
* not handle the call.
- * @hide
*/
public @Nullable Conference onCreateIncomingConference(
@Nullable PhoneAccountHandle connectionManagerPhoneAccount,
@@ -2771,7 +2772,6 @@ public abstract class ConnectionService extends Service {
* @param connectionManagerPhoneAccount See description at
* {@link #onCreateOutgoingConnection(PhoneAccountHandle, ConnectionRequest)}.
* @param request The incoming connection request.
- * @hide
*/
public void onCreateIncomingConferenceFailed(
@Nullable PhoneAccountHandle connectionManagerPhoneAccount,
@@ -2792,7 +2792,6 @@ public abstract class ConnectionService extends Service {
* @param connectionManagerPhoneAccount See description at
* {@link #onCreateOutgoingConnection(PhoneAccountHandle, ConnectionRequest)}.
* @param request The outgoing connection request.
- * @hide
*/
public void onCreateOutgoingConferenceFailed(
@Nullable PhoneAccountHandle connectionManagerPhoneAccount,
@@ -2841,7 +2840,8 @@ public abstract class ConnectionService extends Service {
/**
* Create a {@code Conference} given an outgoing request. This is used to initiate new
- * outgoing conference call.
+ * outgoing conference call requested via
+ * {@link TelecomManager#startConference(List, Bundle)}.
*
* @param connectionManagerPhoneAccount The connection manager account to use for managing
* this call.
@@ -2861,7 +2861,6 @@ public abstract class ConnectionService extends Service {
* @param request Details about the outgoing call.
* @return The {@code Conference} object to satisfy this call, or the result of an invocation
* of {@link Connection#createFailedConnection(DisconnectCause)} to not handle the call.
- * @hide
*/
public @Nullable Conference onCreateOutgoingConference(
@Nullable PhoneAccountHandle connectionManagerPhoneAccount,
diff --git a/telecomm/java/android/telecom/InCallAdapter.java b/telecomm/java/android/telecom/InCallAdapter.java
index dd6c15311651..ab35affe9099 100755
--- a/telecomm/java/android/telecom/InCallAdapter.java
+++ b/telecomm/java/android/telecom/InCallAdapter.java
@@ -107,8 +107,8 @@ public final class InCallAdapter {
*
* @param callId The identifier of the call to transfer.
* @param targetNumber The address to transfer to.
- * @param isConfirmationRequired if {@code true} it will initiate ASSURED transfer,
- * if {@code false}, it will initiate BLIND transfer.
+ * @param isConfirmationRequired if {@code true} it will initiate a confirmed transfer,
+ * if {@code false}, it will initiate unconfirmed transfer.
*/
public void transferCall(@NonNull String callId, @NonNull Uri targetNumber,
boolean isConfirmationRequired) {
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index 8eebbeda9e83..bcb1736f416e 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -1867,11 +1867,13 @@ public class TelecomManager {
/**
* Registers a new incoming conference. A {@link ConnectionService} should invoke this method
- * when it has an incoming conference. For managed {@link ConnectionService}s, the specified
- * {@link PhoneAccountHandle} must have been registered with {@link #registerPhoneAccount} and
- * the user must have enabled the corresponding {@link PhoneAccount}. This can be checked using
- * {@link #getPhoneAccount}. Self-managed {@link ConnectionService}s must have
- * {@link android.Manifest.permission#MANAGE_OWN_CALLS} to add a new incoming call.
+ * when it has an incoming conference. An incoming {@link Conference} is an adhoc conference
+ * call initiated on another device which the user is being invited to join in. For managed
+ * {@link ConnectionService}s, the specified {@link PhoneAccountHandle} must have been
+ * registered with {@link #registerPhoneAccount} and the user must have enabled the
+ * corresponding {@link PhoneAccount}. This can be checked using
+ * {@link #getPhoneAccount(PhoneAccountHandle)}. Self-managed {@link ConnectionService}s must
+ * have {@link android.Manifest.permission#MANAGE_OWN_CALLS} to add a new incoming call.
* <p>
* The incoming conference you are adding is assumed to have a video state of
* {@link VideoProfile#STATE_AUDIO_ONLY}, unless the extra value
@@ -1879,8 +1881,9 @@ public class TelecomManager {
* <p>
* Once invoked, this method will cause the system to bind to the {@link ConnectionService}
* associated with the {@link PhoneAccountHandle} and request additional information about the
- * call (See {@link ConnectionService#onCreateIncomingConference}) before starting the incoming
- * call UI.
+ * call (See
+ * {@link ConnectionService#onCreateIncomingConference(PhoneAccountHandle, ConnectionRequest)})
+ * before starting the incoming call UI.
* <p>
* For a managed {@link ConnectionService}, a {@link SecurityException} will be thrown if either
* the {@link PhoneAccountHandle} does not correspond to a registered {@link PhoneAccount} or
@@ -1890,7 +1893,6 @@ public class TelecomManager {
* {@link #registerPhoneAccount}.
* @param extras A bundle that will be passed through to
* {@link ConnectionService#onCreateIncomingConference}.
- * @hide
*/
public void addNewIncomingConference(@NonNull PhoneAccountHandle phoneAccount,
@NonNull Bundle extras) {
@@ -2111,8 +2113,8 @@ public class TelecomManager {
/**
- * Place a new conference call with the provided participants using the system telecom service
- * This method doesn't support placing of emergency calls.
+ * Place a new adhoc conference call with the provided participants using the system telecom
+ * service. This method doesn't support placing of emergency calls.
*
* An adhoc conference call is established by providing a list of addresses to
* {@code TelecomManager#startConference(List<Uri>, int videoState)} where the
@@ -2130,7 +2132,6 @@ public class TelecomManager {
*
* @param participants List of participants to start conference with
* @param extras Bundle of extras to use with the call
- * @hide
*/
@RequiresPermission(android.Manifest.permission.CALL_PHONE)
public void startConference(@NonNull List<Uri> participants,
diff --git a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
index dee5a98e33e9..7c6f1df972f3 100644
--- a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
+++ b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
@@ -326,6 +326,8 @@ interface ITelecomService {
*/
void handleCallIntent(in Intent intent, in String callingPackageProxy);
+ void cleanupStuckCalls();
+
void setTestDefaultCallRedirectionApp(String packageName);
void setTestPhoneAcctSuggestionComponent(String flattenedComponentName);
diff --git a/telephony/common/android/telephony/LocationAccessPolicy.java b/telephony/common/android/telephony/LocationAccessPolicy.java
index 7d3fde61caa8..502bfa3749eb 100644
--- a/telephony/common/android/telephony/LocationAccessPolicy.java
+++ b/telephony/common/android/telephony/LocationAccessPolicy.java
@@ -47,7 +47,7 @@ public final class LocationAccessPolicy {
ALLOWED,
/**
* Indicates that the denial is due to a transient device state
- * (e.g. app-ops, location master switch)
+ * (e.g. app-ops, location main switch)
*/
DENIED_SOFT,
/**
@@ -306,16 +306,17 @@ public final class LocationAccessPolicy {
/** Check if location permissions have been granted */
public static LocationPermissionResult checkLocationPermission(
Context context, LocationPermissionQuery query) {
- // Always allow the phone process and system server to access location. This avoid
- // breaking legacy code that rely on public-facing APIs to access cell location, and
- // it doesn't create an info leak risk because the cell location is stored in the phone
+ // Always allow the phone process, system server, and network stack to access location.
+ // This avoid breaking legacy code that rely on public-facing APIs to access cell location,
+ // and it doesn't create an info leak risk because the cell location is stored in the phone
// process anyway, and the system server already has location access.
if (query.callingUid == Process.PHONE_UID || query.callingUid == Process.SYSTEM_UID
+ || query.callingUid == Process.NETWORK_STACK_UID
|| query.callingUid == Process.ROOT_UID) {
return LocationPermissionResult.ALLOWED;
}
- // Check the system-wide requirements. If the location master switch is off or
+ // Check the system-wide requirements. If the location main switch is off or
// the app's profile isn't in foreground, return a soft denial.
if (!checkSystemLocationAccess(context, query.callingUid, query.callingPid)) {
return LocationPermissionResult.DENIED_SOFT;
@@ -339,7 +340,7 @@ public final class LocationAccessPolicy {
}
// At this point, we're out of location checks to do. If the app bypassed all the previous
- // ones due to the SDK grandfathering schemes, allow it access.
+ // ones due to the SDK backwards compatibility schemes, allow it access.
return LocationPermissionResult.ALLOWED;
}
diff --git a/telephony/common/com/android/internal/telephony/TelephonyPermissions.java b/telephony/common/com/android/internal/telephony/TelephonyPermissions.java
index 71a1964210b0..0c463949b14a 100644
--- a/telephony/common/com/android/internal/telephony/TelephonyPermissions.java
+++ b/telephony/common/com/android/internal/telephony/TelephonyPermissions.java
@@ -74,7 +74,8 @@ public final class TelephonyPermissions {
* <li>return false: if the caller lacks all of these permissions and doesn't support runtime
* permissions. This implies that the user revoked the ability to read phone state
* manually (via AppOps). In this case we can't throw as it would break app compatibility,
- * so we return false to indicate that the calling function should return dummy data.
+ * so we return false to indicate that the calling function should return placeholder
+ * data.
* </ul>
*
* <p>Note: for simplicity, this method always returns false for callers using legacy
@@ -119,7 +120,8 @@ public final class TelephonyPermissions {
* <li>return false: if the caller lacks all of these permissions and doesn't support runtime
* permissions. This implies that the user revoked the ability to read phone state
* manually (via AppOps). In this case we can't throw as it would break app compatibility,
- * so we return false to indicate that the calling function should return dummy data.
+ * so we return false to indicate that the calling function should return placeholder
+ * data.
* </ul>
*
* <p>Note: for simplicity, this method always returns false for callers using legacy
@@ -225,7 +227,7 @@ public final class TelephonyPermissions {
* <li>return false: if the caller is targeting pre-Q and does have the READ_PHONE_STATE
* permission. In this case the caller would expect to have access to the device
* identifiers so false is returned instead of throwing a SecurityException to indicate
- * the calling function should return dummy data.
+ * the calling function should return placeholder data.
* </ul>
*/
public static boolean checkCallingOrSelfReadDeviceIdentifiers(Context context,
@@ -249,7 +251,7 @@ public final class TelephonyPermissions {
* <li>return false: if the caller is targeting pre-Q and does have the READ_PHONE_STATE
* permission or carrier privileges. In this case the caller would expect to have access
* to the device identifiers so false is returned instead of throwing a SecurityException
- * to indicate the calling function should return dummy data.
+ * to indicate the calling function should return placeholder data.
* </ul>
*/
public static boolean checkCallingOrSelfReadDeviceIdentifiers(Context context, int subId,
@@ -271,7 +273,7 @@ public final class TelephonyPermissions {
* <li>return false: if the caller is targeting pre-Q and does have the READ_PHONE_STATE
* permission. In this case the caller would expect to have access to the device
* identifiers so false is returned instead of throwing a SecurityException to indicate
- * the calling function should return dummy data.
+ * the calling function should return placeholder data.
* </ul>
*/
public static boolean checkCallingOrSelfReadSubscriberIdentifiers(Context context, int subId,
@@ -295,7 +297,7 @@ public final class TelephonyPermissions {
* <li>return false: if the caller is targeting pre-Q and does have the READ_PHONE_STATE
* permission. In this case the caller would expect to have access to the device
* identifiers so false is returned instead of throwing a SecurityException to indicate
- * the calling function should return dummy data.
+ * the calling function should return placeholder data.
* </ul>
*/
private static boolean checkPrivilegedReadPermissionOrCarrierPrivilegePermission(
diff --git a/telephony/common/com/google/android/mms/pdu/PduComposer.java b/telephony/common/com/google/android/mms/pdu/PduComposer.java
index 5e1f556f4c4a..7af0d1b09eed 100644
--- a/telephony/common/com/google/android/mms/pdu/PduComposer.java
+++ b/telephony/common/com/google/android/mms/pdu/PduComposer.java
@@ -1051,7 +1051,7 @@ public class PduComposer {
}
if (dataLength != (attachment.getLength() - headerLength)) {
- throw new RuntimeException("BUG: Length sanity check failed");
+ throw new RuntimeException("BUG: Length correctness check failed");
}
mStack.pop();
diff --git a/telephony/common/com/google/android/mms/pdu/PduPersister.java b/telephony/common/com/google/android/mms/pdu/PduPersister.java
index fcd5b8ff57a8..b61ad3680c6c 100755
--- a/telephony/common/com/google/android/mms/pdu/PduPersister.java
+++ b/telephony/common/com/google/android/mms/pdu/PduPersister.java
@@ -72,7 +72,7 @@ public class PduPersister {
private static final boolean DEBUG = false;
private static final boolean LOCAL_LOGV = false;
- private static final long DUMMY_THREAD_ID = Long.MAX_VALUE;
+ private static final long PLACEHOLDER_THREAD_ID = Long.MAX_VALUE;
/**
* The uri of temporary drm objects.
@@ -1340,7 +1340,7 @@ public class PduPersister {
// Save parts first to avoid inconsistent message is loaded
// while saving the parts.
- long dummyId = System.currentTimeMillis(); // Dummy ID of the msg.
+ long placeholderId = System.currentTimeMillis(); // Placeholder ID of the msg.
// Figure out if this PDU is a text-only message
boolean textOnly = true;
@@ -1364,7 +1364,7 @@ public class PduPersister {
for (int i = 0; i < partsNum; i++) {
PduPart part = body.getPart(i);
messageSize += part.getDataLength();
- persistPart(part, dummyId, preOpenedFiles);
+ persistPart(part, placeholderId, preOpenedFiles);
// If we've got anything besides text/plain or SMIL part, then we've got
// an mms message with some other type of attachment.
@@ -1395,14 +1395,14 @@ public class PduPersister {
throw new MmsException("persist() failed: return null.");
}
// Get the real ID of the PDU and update all parts which were
- // saved with the dummy ID.
+ // saved with the placeholder ID.
msgId = ContentUris.parseId(res);
}
values = new ContentValues(1);
values.put(Part.MSG_ID, msgId);
SqliteWrapper.update(mContext, mContentResolver,
- Uri.parse("content://mms/" + dummyId + "/part"),
+ Uri.parse("content://mms/" + placeholderId + "/part"),
values, null, null);
// We should return the longest URI of the persisted PDU, for
// example, if input URI is "content://mms/inbox" and the _ID of
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 5ea4c7b5dac9..fa229fb47423 100755
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -772,7 +772,7 @@ public class CarrierConfigManager {
* {@link #KEY_CARRIER_UT_PROVISIONING_REQUIRED_BOOL}). If false, this device will fallback to
* circuit switch for supplementary services and will disable this capability for IMS entirely.
*
- * The default value for this key is {@code true}.
+ * The default value for this key is {@code false}.
*/
public static final String KEY_CARRIER_SUPPORTS_SS_OVER_UT_BOOL =
"carrier_supports_ss_over_ut_bool";
@@ -1165,15 +1165,14 @@ public class CarrierConfigManager {
/**
* Determines whether adhoc conference calls are supported by a carrier. When {@code true},
* adhoc conference calling is supported, {@code false otherwise}.
- * @hide
*/
public static final String KEY_SUPPORT_ADHOC_CONFERENCE_CALLS_BOOL =
"support_adhoc_conference_calls_bool";
/**
- * Determines whether conference participants can be added to existing call. When {@code true},
+ * Determines whether conference participants can be added to existing call to form an adhoc
+ * conference call (in contrast to merging calls to form a conference). When {@code true},
* adding conference participants to existing call is supported, {@code false otherwise}.
- * @hide
*/
public static final String KEY_SUPPORT_ADD_CONFERENCE_PARTICIPANTS_BOOL =
"support_add_conference_participants_bool";
diff --git a/telephony/java/android/telephony/CellLocation.java b/telephony/java/android/telephony/CellLocation.java
index aa1230165e13..cdf735195d61 100644
--- a/telephony/java/android/telephony/CellLocation.java
+++ b/telephony/java/android/telephony/CellLocation.java
@@ -33,10 +33,12 @@ import com.android.internal.telephony.PhoneConstants;
public abstract class CellLocation {
/**
- * This method will not do anything.
+ * Request an updated CellLocation for callers targeting SDK 30 or older.
*
- * Whenever location changes, a callback will automatically be be sent to
- * all registrants of {@link PhoneStateListener#LISTEN_CELL_LOCATION}.
+ * Whenever Android is aware of location changes, a callback will automatically be sent to
+ * all registrants of {@link PhoneStateListener#LISTEN_CELL_LOCATION}. This API requests an
+ * additional location update for cases where power saving might cause location updates to be
+ * missed.
*
* <p>This method is a no-op for callers targeting SDK level 31 or greater.
* <p>This method is a no-op for callers that target SDK level 29 or 30 and lack
@@ -44,14 +46,7 @@ public abstract class CellLocation {
* <p>This method is a no-op for callers that target SDK level 28 or below and lack
* {@link android.Manifest.permission#ACCESS_COARSE_LOCATION}.
*
- * Callers wishing to request a single location update should use
- * {@link TelephonyManager#requestCellInfoUpdate}.
- *
- * @deprecated this method has undesirable side-effects, and it calls into the OS without
- * access to a {@link android.content.Context Context}, meaning that certain safety checks and
- * attribution are error-prone. Given that this method has numerous downsides, and given that
- * there are long-available superior alternatives, callers are strongly discouraged from using
- * this method.
+ * @deprecated use {@link TelephonyManager#requestCellInfoUpdate}.
*/
@Deprecated
public static void requestLocationUpdate() {
diff --git a/telephony/java/android/telephony/CellSignalStrengthNr.java b/telephony/java/android/telephony/CellSignalStrengthNr.java
index 8e50bba38e84..766019ec382a 100644
--- a/telephony/java/android/telephony/CellSignalStrengthNr.java
+++ b/telephony/java/android/telephony/CellSignalStrengthNr.java
@@ -149,7 +149,7 @@ public final class CellSignalStrengthNr extends CellSignalStrength implements Pa
mCsiRsrq = inRangeOrUnavailable(csiRsrq, -20, -3);
mCsiSinr = inRangeOrUnavailable(csiSinr, -23, 23);
mSsRsrp = inRangeOrUnavailable(ssRsrp, -140, -44);
- mSsRsrq = inRangeOrUnavailable(ssRsrq, -20, -3);
+ mSsRsrq = inRangeOrUnavailable(ssRsrq, -43, 20);
mSsSinr = inRangeOrUnavailable(ssSinr, -23, 40);
updateLevel(null, null);
}
diff --git a/telephony/java/android/telephony/MbmsDownloadSession.java b/telephony/java/android/telephony/MbmsDownloadSession.java
index 3f671ca2d809..18d6f467ba7b 100644
--- a/telephony/java/android/telephony/MbmsDownloadSession.java
+++ b/telephony/java/android/telephony/MbmsDownloadSession.java
@@ -509,7 +509,7 @@ public class MbmsDownloadSession implements AutoCloseable {
* provided directory is the same as what has been previously configured.
*
* The {@link File} supplied as a root temp file directory must already exist. If not, an
- * {@link IllegalArgumentException} will be thrown. In addition, as an additional sanity
+ * {@link IllegalArgumentException} will be thrown. In addition, as an additional correctness
* check, an {@link IllegalArgumentException} will be thrown if you attempt to set the temp
* file root directory to one of your data roots (the value of {@link Context#getDataDir()},
* {@link Context#getFilesDir()}, or {@link Context#getCacheDir()}).
diff --git a/telephony/java/android/telephony/PreciseDataConnectionState.java b/telephony/java/android/telephony/PreciseDataConnectionState.java
index 8660e3825e97..aee861768209 100644
--- a/telephony/java/android/telephony/PreciseDataConnectionState.java
+++ b/telephony/java/android/telephony/PreciseDataConnectionState.java
@@ -53,14 +53,11 @@ import java.util.Objects;
*
*/
public final class PreciseDataConnectionState implements Parcelable {
-
- private @DataState int mState = TelephonyManager.DATA_UNKNOWN;
- private @NetworkType int mNetworkType = TelephonyManager.NETWORK_TYPE_UNKNOWN;
- private @DataFailureCause int mFailCause = DataFailCause.NONE;
- private @ApnType int mApnTypes = ApnSetting.TYPE_NONE;
- private String mApn = "";
- private LinkProperties mLinkProperties = null;
- private ApnSetting mApnSetting = null;
+ private final @DataState int mState;
+ private final @NetworkType int mNetworkType;
+ private final @DataFailureCause int mFailCause;
+ private final LinkProperties mLinkProperties;
+ private final ApnSetting mApnSetting;
/**
* Constructor
@@ -77,48 +74,37 @@ public final class PreciseDataConnectionState implements Parcelable {
@ApnType int apnTypes, @NonNull String apn,
@Nullable LinkProperties linkProperties,
@DataFailureCause int failCause) {
- this(state, networkType, apnTypes, apn, linkProperties, failCause, null);
+ this(state, networkType, linkProperties, failCause, new ApnSetting.Builder()
+ .setApnTypeBitmask(apnTypes)
+ .setApnName(apn)
+ .build());
}
/**
* Constructor of PreciseDataConnectionState
*
- * @param state the state of the data connection
- * @param networkType the access network that is/would carry this data connection
- * @param apnTypes the APN types that this data connection carries
- * @param apn the APN of this data connection
- * @param linkProperties if the data connection is connected, the properties of the connection
- * @param failCause in case a procedure related to this data connection fails, a non-zero error
+ * @param state The state of the data connection
+ * @param networkType The access network that is/would carry this data connection
+ * @param linkProperties If the data connection is connected, the properties of the connection
+ * @param failCause In case a procedure related to this data connection fails, a non-zero error
* code indicating the cause of the failure.
- * @param apnSetting if there is a valid APN for this Data Connection, then the APN Settings;
+ * @param apnSetting If there is a valid APN for this Data Connection, then the APN Settings;
* if there is no valid APN setting for the specific type, then this will be null
- * @hide
*/
- public PreciseDataConnectionState(@DataState int state,
+ private PreciseDataConnectionState(@DataState int state,
@NetworkType int networkType,
- @ApnType int apnTypes, @NonNull String apn,
@Nullable LinkProperties linkProperties,
@DataFailureCause int failCause,
@Nullable ApnSetting apnSetting) {
mState = state;
mNetworkType = networkType;
- mApnTypes = apnTypes;
- mApn = apn;
mLinkProperties = linkProperties;
mFailCause = failCause;
mApnSetting = apnSetting;
}
/**
- * Empty Constructor
- *
- * @hide
- */
- public PreciseDataConnectionState() {
- }
-
- /**
* Construct a PreciseDataConnectionState object from the given parcel.
*
* @hide
@@ -126,11 +112,9 @@ public final class PreciseDataConnectionState implements Parcelable {
private PreciseDataConnectionState(Parcel in) {
mState = in.readInt();
mNetworkType = in.readInt();
- mApnTypes = in.readInt();
- mApn = in.readString();
- mLinkProperties = (LinkProperties) in.readParcelable(null);
+ mLinkProperties = in.readParcelable(LinkProperties.class.getClassLoader());
mFailCause = in.readInt();
- mApnSetting = (ApnSetting) in.readParcelable(null);
+ mApnSetting = in.readParcelable(ApnSetting.class.getClassLoader());
}
/**
@@ -167,9 +151,9 @@ public final class PreciseDataConnectionState implements Parcelable {
}
/**
- * Returns the network type associated with this data connection.
+ * Get the network type associated with this data connection.
*
- * Return the current/latest (radio) bearer technology that carries this data connection.
+ * @return The current/latest (radio) bearer technology that carries this data connection.
* For a variety of reasons, the network type can change during the life of the data
* connection, and this information is not reliable unless the physical link is currently
* active; (there is currently no mechanism to know whether the physical link is active at
@@ -189,7 +173,7 @@ public final class PreciseDataConnectionState implements Parcelable {
@Deprecated
@SystemApi
public @ApnType int getDataConnectionApnTypeBitMask() {
- return mApnTypes;
+ return (mApnSetting != null) ? mApnSetting.getApnTypeBitmask() : ApnSetting.TYPE_NONE;
}
/**
@@ -202,7 +186,7 @@ public final class PreciseDataConnectionState implements Parcelable {
@SystemApi
@Deprecated
public String getDataConnectionApn() {
- return mApn;
+ return (mApnSetting != null) ? mApnSetting.getApnName() : "";
}
/**
@@ -253,8 +237,6 @@ public final class PreciseDataConnectionState implements Parcelable {
public void writeToParcel(@NonNull Parcel out, int flags) {
out.writeInt(mState);
out.writeInt(mNetworkType);
- out.writeInt(mApnTypes);
- out.writeString(mApn);
out.writeParcelable(mLinkProperties, flags);
out.writeInt(mFailCause);
out.writeParcelable(mApnSetting, flags);
@@ -274,24 +256,20 @@ public final class PreciseDataConnectionState implements Parcelable {
@Override
public int hashCode() {
- return Objects.hash(mState, mNetworkType, mApnTypes, mApn, mLinkProperties,
- mFailCause, mApnSetting);
+ return Objects.hash(mState, mNetworkType, mFailCause, mLinkProperties, mApnSetting);
}
- @Override
- public boolean equals(@Nullable Object obj) {
-
- if (!(obj instanceof PreciseDataConnectionState)) {
- return false;
- }
- PreciseDataConnectionState other = (PreciseDataConnectionState) obj;
- return Objects.equals(mApn, other.mApn) && mApnTypes == other.mApnTypes
- && mFailCause == other.mFailCause
- && Objects.equals(mLinkProperties, other.mLinkProperties)
- && mNetworkType == other.mNetworkType
- && mState == other.mState
- && Objects.equals(mApnSetting, other.mApnSetting);
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ PreciseDataConnectionState that = (PreciseDataConnectionState) o;
+ return mState == that.mState
+ && mNetworkType == that.mNetworkType
+ && mFailCause == that.mFailCause
+ && Objects.equals(mLinkProperties, that.mLinkProperties)
+ && Objects.equals(mApnSetting, that.mApnSetting);
}
@NonNull
@@ -301,12 +279,104 @@ public final class PreciseDataConnectionState implements Parcelable {
sb.append("Data Connection state: " + mState);
sb.append(", Network type: " + mNetworkType);
- sb.append(", APN types: " + ApnSetting.getApnTypesStringFromBitmask(mApnTypes));
- sb.append(", APN: " + mApn);
+ sb.append(", APN types: " + ApnSetting.getApnTypesStringFromBitmask(
+ getDataConnectionApnTypeBitMask()));
+ sb.append(", APN: " + getDataConnectionApn());
sb.append(", Link properties: " + mLinkProperties);
sb.append(", Fail cause: " + DataFailCause.toString(mFailCause));
sb.append(", Apn Setting: " + mApnSetting);
return sb.toString();
}
+
+ /**
+ * {@link PreciseDataConnectionState} builder
+ *
+ * @hide
+ */
+ public static final class Builder {
+ /** The state of the data connection */
+ private @DataState int mState = TelephonyManager.DATA_UNKNOWN;
+
+ /** The network type associated with this data connection */
+ private @NetworkType int mNetworkType = TelephonyManager.NETWORK_TYPE_UNKNOWN;
+
+ /** If the data connection is connected, the properties of the connection */
+ private @Nullable LinkProperties mLinkProperties = null;
+
+ /**
+ * In case a procedure related to this data connection fails, a non-zero error code
+ * indicating the cause of the failure.
+ */
+ private @DataFailureCause int mFailCause = DataFailCause.NONE;
+
+ /** The APN Setting for this data connection */
+ private @Nullable ApnSetting mApnSetting = null;
+
+ /**
+ * Set the state of the data connection.
+ *
+ * @param state The state of the data connection
+ * @return The builder
+ */
+ public Builder setState(@DataState int state) {
+ mState = state;
+ return this;
+ }
+
+ /**
+ * Set the network type associated with this data connection.
+ *
+ * @param networkType The network type
+ * @return The builder
+ */
+ public Builder setNetworkType(@NetworkType int networkType) {
+ mNetworkType = networkType;
+ return this;
+ }
+
+ /**
+ * Set the link properties of the connection.
+ *
+ * @param linkProperties Link properties
+ * @return The builder
+ */
+ public Builder setLinkProperties(@NonNull LinkProperties linkProperties) {
+ mLinkProperties = linkProperties;
+ return this;
+ }
+
+ /**
+ * Set the fail cause of the data connection.
+ *
+ * @param failCause In case a procedure related to this data connection fails, a non-zero
+ * error code indicating the cause of the failure.
+ * @return The builder
+ */
+ public Builder setFailCause(@DataFailureCause int failCause) {
+ mFailCause = failCause;
+ return this;
+ }
+
+ /**
+ * Set the APN Setting for this data connection.
+ *
+ * @param apnSetting APN setting
+ * @return This builder
+ */
+ public Builder setApnSetting(@NonNull ApnSetting apnSetting) {
+ mApnSetting = apnSetting;
+ return this;
+ }
+
+ /**
+ * Build the {@link PreciseDataConnectionState} instance.
+ *
+ * @return The {@link PreciseDataConnectionState} instance
+ */
+ public PreciseDataConnectionState build() {
+ return new PreciseDataConnectionState(mState, mNetworkType, mLinkProperties, mFailCause,
+ mApnSetting);
+ }
+ }
}
diff --git a/telephony/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java
index 183fdcce1ca4..2b2608724e12 100644
--- a/telephony/java/android/telephony/SmsManager.java
+++ b/telephony/java/android/telephony/SmsManager.java
@@ -39,7 +39,9 @@ import android.os.RemoteException;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.Log;
+import android.util.Pair;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.telephony.IIntegerConsumer;
import com.android.internal.telephony.ISms;
import com.android.internal.telephony.ITelephony;
@@ -74,11 +76,16 @@ import java.util.concurrent.Executor;
public final class SmsManager {
private static final String TAG = "SmsManager";
- /** Singleton object constructed during class initialization. */
- private static final SmsManager sInstance = new SmsManager(
- SubscriptionManager.DEFAULT_SUBSCRIPTION_ID);
private static final Object sLockObject = new Object();
+ @GuardedBy("sLockObject")
+ private static final Map<Pair<Context, Integer>, SmsManager> sSubInstances =
+ new ArrayMap<>();
+
+ /** Singleton object constructed during class initialization. */
+ private static final SmsManager DEFAULT_INSTANCE = getSmsManagerForContextAndSubscriptionId(
+ null, SubscriptionManager.DEFAULT_SUBSCRIPTION_ID);
+
/** SMS record length from TS 51.011 10.5.3
* @hide
*/
@@ -89,13 +96,16 @@ public final class SmsManager {
*/
public static final int CDMA_SMS_RECORD_LENGTH = 255;
- private static final Map<Integer, SmsManager> sSubInstances =
- new ArrayMap<Integer, SmsManager>();
-
/** A concrete subscription id, or the pseudo DEFAULT_SUBSCRIPTION_ID */
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private int mSubId;
+ /**
+ * Context this SmsManager is for. Can be {@code null} in the case the manager was created via
+ * legacy APIs
+ */
+ private final @Nullable Context mContext;
+
/*
* Key for the various carrier-dependent configuration values.
* Some of the values are used by the system in processing SMS or MMS messages. Others
@@ -325,6 +335,34 @@ public final class SmsManager {
}
/**
+ * Get {@link Context#getOpPackageName()} if this manager has a context, otherwise a dummy
+ * value.
+ *
+ * @return The package name to be used for app-ops checks
+ */
+ private @Nullable String getOpPackageName() {
+ if (mContext == null) {
+ return null;
+ } else {
+ return mContext.getOpPackageName();
+ }
+ }
+
+ /**
+ * Get {@link Context#getAttributionTag()} ()} if this manager has a context, otherwise get the
+ * default attribution tag.
+ *
+ * @return The attribution tag to be used for app-ops checks
+ */
+ private @Nullable String getAttributionTag() {
+ if (mContext == null) {
+ return null;
+ } else {
+ return mContext.getAttributionTag();
+ }
+ }
+
+ /**
* Send a text based SMS.
*
* <p class="note"><strong>Note:</strong> Using this method requires that your app has the
@@ -424,7 +462,8 @@ public final class SmsManager {
String destinationAddress, String scAddress, String text,
PendingIntent sentIntent, PendingIntent deliveryIntent) {
sendTextMessageInternal(destinationAddress, scAddress, text, sentIntent, deliveryIntent,
- true /* persistMessage*/, null, null, 0L /* messageId */);
+ true /* persistMessage*/, getOpPackageName(), getAttributionTag(),
+ 0L /* messageId */);
}
@@ -443,7 +482,8 @@ public final class SmsManager {
@Nullable PendingIntent sentIntent, @Nullable PendingIntent deliveryIntent,
long messageId) {
sendTextMessageInternal(destinationAddress, scAddress, text, sentIntent, deliveryIntent,
- true /* persistMessage*/, null, null, messageId);
+ true /* persistMessage*/, getOpPackageName(), getAttributionTag(),
+ messageId);
}
/**
@@ -653,8 +693,8 @@ public final class SmsManager {
String destinationAddress, String scAddress, String text,
PendingIntent sentIntent, PendingIntent deliveryIntent) {
sendTextMessageInternal(destinationAddress, scAddress, text, sentIntent, deliveryIntent,
- false /* persistMessage */, null, null,
- 0L /* messageId */);
+ false /* persistMessage */, getOpPackageName(),
+ getAttributionTag(), 0L /* messageId */);
}
private void sendTextMessageInternal(
@@ -939,8 +979,8 @@ public final class SmsManager {
String destinationAddress, String scAddress, ArrayList<String> parts,
ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents) {
sendMultipartTextMessageInternal(destinationAddress, scAddress, parts, sentIntents,
- deliveryIntents, true /* persistMessage*/, null, null,
- 0L /* messageId */);
+ deliveryIntents, true /* persistMessage*/, getOpPackageName(),
+ getAttributionTag(), 0L /* messageId */);
}
/**
@@ -957,8 +997,8 @@ public final class SmsManager {
@NonNull List<String> parts, @Nullable List<PendingIntent> sentIntents,
@Nullable List<PendingIntent> deliveryIntents, long messageId) {
sendMultipartTextMessageInternal(destinationAddress, scAddress, parts, sentIntents,
- deliveryIntents, true /* persistMessage*/, null, null,
- messageId);
+ deliveryIntents, true /* persistMessage*/, getOpPackageName(),
+ getAttributionTag(), messageId);
}
/**
@@ -1088,8 +1128,8 @@ public final class SmsManager {
String destinationAddress, String scAddress, List<String> parts,
List<PendingIntent> sentIntents, List<PendingIntent> deliveryIntents) {
sendMultipartTextMessageInternal(destinationAddress, scAddress, parts, sentIntents,
- deliveryIntents, false /* persistMessage*/, null, null,
- 0L /* messageId */);
+ deliveryIntents, false /* persistMessage*/, getOpPackageName(),
+ getAttributionTag(), 0L /* messageId */);
}
/**
@@ -1451,9 +1491,37 @@ public final class SmsManager {
* @return the {@link SmsManager} associated with the default subscription id.
*
* @see SubscriptionManager#getDefaultSmsSubscriptionId()
+ *
+ * @deprecated Use {@link Context#getSystemService Context.getSystemService(SmsManager.class)}
+ * instead
*/
+ @Deprecated
public static SmsManager getDefault() {
- return sInstance;
+ return DEFAULT_INSTANCE;
+ }
+
+ /**
+ * Get the instance of the SmsManager associated with a particular context and subscription ID.
+ *
+ * @param context The context the manager belongs to
+ * @param subId an SMS subscription ID, typically accessed using {@link SubscriptionManager}
+ *
+ * @return the instance of the SmsManager associated with subscription
+ *
+ * @hide
+ */
+ public static @NonNull SmsManager getSmsManagerForContextAndSubscriptionId(
+ @Nullable Context context, int subId) {
+ synchronized(sLockObject) {
+ Pair<Context, Integer> key = new Pair<>(context, subId);
+
+ SmsManager smsManager = sSubInstances.get(key);
+ if (smsManager == null) {
+ smsManager = new SmsManager(context, subId);
+ sSubInstances.put(key, smsManager);
+ }
+ return smsManager;
+ }
}
/**
@@ -1468,19 +1536,33 @@ public final class SmsManager {
*
* @see SubscriptionManager#getActiveSubscriptionInfoList()
* @see SubscriptionManager#getDefaultSmsSubscriptionId()
+ * @deprecated Use {@link Context#getSystemService Context.getSystemService(SmsManager.class)}
+ * .{@link #createForSubscriptionId createForSubscriptionId(subId)} instead
*/
+ @Deprecated
public static SmsManager getSmsManagerForSubscriptionId(int subId) {
- synchronized(sLockObject) {
- SmsManager smsManager = sSubInstances.get(subId);
- if (smsManager == null) {
- smsManager = new SmsManager(subId);
- sSubInstances.put(subId, smsManager);
- }
- return smsManager;
- }
+ return getSmsManagerForContextAndSubscriptionId(null, subId);
+ }
+
+ /**
+ * Get the instance of the SmsManager associated with a particular subscription ID.
+ *
+ * <p class="note"><strong>Note:</strong> Constructing an {@link SmsManager} in this manner will
+ * never cause an SMS disambiguation dialog to appear, unlike {@link #getDefault()}.
+ * </p>
+ *
+ * @param subId an SMS subscription ID, typically accessed using {@link SubscriptionManager}
+ * @return the instance of the SmsManager associated with subscription
+ *
+ * @see SubscriptionManager#getActiveSubscriptionInfoList()
+ * @see SubscriptionManager#getDefaultSmsSubscriptionId()
+ */
+ public @NonNull SmsManager createForSubscriptionId(int subId) {
+ return getSmsManagerForContextAndSubscriptionId(mContext, subId);
}
- private SmsManager(int subId) {
+ private SmsManager(@Nullable Context context, int subId) {
+ mContext = context;
mSubId = subId;
}
@@ -1715,8 +1797,7 @@ public final class SmsManager {
* operation is performed on the correct subscription.
* </p>
*
- * @param messageIndex This is the same index used to access a message
- * from {@link #getMessagesFromIcc()}.
+ * @param messageIndex the message index of the message in the ICC (1-based index).
* @return true for success, false if the operation fails. Failure can be due to IPC failure,
* RIL/modem error which results in SMS failed to be deleted on SIM
*
@@ -1798,7 +1879,7 @@ public final class SmsManager {
* operation is performed on the correct subscription.
* </p>
*
- * @return <code>List</code> of <code>SmsMessage</code> objects
+ * @return <code>List</code> of <code>SmsMessage</code> objects for valid records only.
*
* {@hide}
*/
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 4ad52ae5e077..a71a965b1bdb 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -94,10 +94,9 @@ public class SubscriptionManager {
/** An invalid subscription identifier */
public static final int INVALID_SUBSCRIPTION_ID = -1;
- /** Base value for Dummy SUBSCRIPTION_ID's. */
- /** FIXME: Remove DummySubId's, but for now have them map just below INVALID_SUBSCRIPTION_ID
- /** @hide */
- public static final int DUMMY_SUBSCRIPTION_ID_BASE = INVALID_SUBSCRIPTION_ID - 1;
+ /** Base value for placeholder SUBSCRIPTION_ID's. */
+ /** @hide */
+ public static final int PLACEHOLDER_SUBSCRIPTION_ID_BASE = INVALID_SUBSCRIPTION_ID - 1;
/** An invalid phone identifier */
/** @hide */
diff --git a/telephony/java/android/telephony/TelephonyFrameworkInitializer.java b/telephony/java/android/telephony/TelephonyFrameworkInitializer.java
index c9540fb5f467..8308821b59ff 100644
--- a/telephony/java/android/telephony/TelephonyFrameworkInitializer.java
+++ b/telephony/java/android/telephony/TelephonyFrameworkInitializer.java
@@ -92,6 +92,12 @@ public class TelephonyFrameworkInitializer {
ImsManager.class,
context -> new ImsManager(context)
);
+ SystemServiceRegistry.registerContextAwareService(
+ Context.SMS_SERVICE,
+ SmsManager.class,
+ context -> SmsManager.getSmsManagerForContextAndSubscriptionId(context,
+ SubscriptionManager.DEFAULT_SUBSCRIPTION_ID)
+ );
}
/** @hide */
diff --git a/telephony/java/android/telephony/VisualVoicemailSmsFilterSettings.java b/telephony/java/android/telephony/VisualVoicemailSmsFilterSettings.java
index e8f3f1ebb6cf..eadb726bf63b 100644
--- a/telephony/java/android/telephony/VisualVoicemailSmsFilterSettings.java
+++ b/telephony/java/android/telephony/VisualVoicemailSmsFilterSettings.java
@@ -92,8 +92,8 @@ public final class VisualVoicemailSmsFilterSettings implements Parcelable {
}
/**
- * Sets the originating number whitelist for the visual voicemail SMS filter. If the list is
- * not null only the SMS messages from a number in the list can be considered as a visual
+ * Sets the originating number allow list for the visual voicemail SMS filter. If the list
+ * is not null only the SMS messages from a number in the list can be considered as a visual
* voicemail SMS. Otherwise, messages from any address will be considered.
*/
public Builder setOriginatingNumbers(List<String> originatingNumbers) {
@@ -133,7 +133,7 @@ public final class VisualVoicemailSmsFilterSettings implements Parcelable {
public final String clientPrefix;
/**
- * The originating number whitelist for the visual voicemail SMS filter of a phone account. If
+ * The originating number allow list for the visual voicemail SMS filter of a phone account. If
* the list is not null only the SMS messages from a number in the list can be considered as a
* visual voicemail SMS. Otherwise, messages from any address will be considered.
*/
diff --git a/telephony/java/android/telephony/data/ApnSetting.java b/telephony/java/android/telephony/data/ApnSetting.java
index bfb54b008cd8..e60ae896f9f8 100644
--- a/telephony/java/android/telephony/data/ApnSetting.java
+++ b/telephony/java/android/telephony/data/ApnSetting.java
@@ -1643,7 +1643,7 @@ public class ApnSetting implements Parcelable {
*
* <pre><code>
* // Create an MMS proxy address with a hostname. A network might not be
- * // available, so supply a dummy (0.0.0.0) IPv4 address to avoid DNS lookup.
+ * // available, so supply a placeholder (0.0.0.0) IPv4 address to avoid DNS lookup.
* String host = "mms.example.com";
* byte[] ipAddress = new byte[4];
* InetAddress mmsProxy;
@@ -1828,7 +1828,8 @@ public class ApnSetting implements Parcelable {
* {@link java.net.InetAddress#getAllByName getAllByName()} require DNS for hostname
* resolution. To avoid this requirement when setting a hostname, call
* {@link java.net.InetAddress#getByAddress(java.lang.String, byte[])} with both the
- * hostname and a dummy IP address. See {@link ApnSetting.Builder above} for an example.
+ * hostname and a placeholder IP address. See {@link ApnSetting.Builder above} for an
+ * example.
*
* @param proxy the proxy address to set for the APN
* @deprecated use {@link #setProxyAddress(String)} instead.
@@ -1882,7 +1883,8 @@ public class ApnSetting implements Parcelable {
* {@link java.net.InetAddress#getAllByName getAllByName()} require DNS for hostname
* resolution. To avoid this requirement when setting a hostname, call
* {@link java.net.InetAddress#getByAddress(java.lang.String, byte[])} with both the
- * hostname and a dummy IP address. See {@link ApnSetting.Builder above} for an example.
+ * hostname and a placeholder IP address. See {@link ApnSetting.Builder above} for an
+ * example.
*
* @param mmsProxy the MMS proxy address to set for the APN
* @deprecated use {@link #setMmsProxyAddress(String)} instead.
diff --git a/telephony/java/android/telephony/ims/ImsCallSession.java b/telephony/java/android/telephony/ims/ImsCallSession.java
index 80c38cbfc39a..8857b9b36d0c 100755
--- a/telephony/java/android/telephony/ims/ImsCallSession.java
+++ b/telephony/java/android/telephony/ims/ImsCallSession.java
@@ -815,7 +815,7 @@ public class ImsCallSession {
* Transfers an ongoing call.
*
* @param number number to be transferred to.
- * @param isConfirmationRequired indicates blind or assured transfer.
+ * @param isConfirmationRequired indicates whether confirmation of the transfer is required.
*/
public void transfer(@NonNull String number, boolean isConfirmationRequired) {
if (mClosed) {
diff --git a/telephony/java/android/telephony/ims/ImsReasonInfo.java b/telephony/java/android/telephony/ims/ImsReasonInfo.java
index 0d6b31d349e1..30389a290368 100644
--- a/telephony/java/android/telephony/ims/ImsReasonInfo.java
+++ b/telephony/java/android/telephony/ims/ImsReasonInfo.java
@@ -27,7 +27,8 @@ import android.os.Parcelable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
-
+import java.util.HashMap;
+import java.util.Map;
/**
* Provides details on why an IMS call failed. Applications can use the methods in this class to
* get local or network fault behind an IMS services failure. For example, if the code is
@@ -1095,6 +1096,196 @@ public final class ImsReasonInfo implements Parcelable {
@Retention(RetentionPolicy.SOURCE)
public @interface ImsCode {}
+
+ private static final Map<Integer, String> sImsCodeMap;
+ static {
+ sImsCodeMap = new HashMap<>();
+ sImsCodeMap.put(CODE_UNSPECIFIED, "CODE_UNSPECIFIED");
+ sImsCodeMap.put(CODE_LOCAL_ILLEGAL_ARGUMENT, "CODE_LOCAL_ILLEGAL_ARGUMENT");
+ sImsCodeMap.put(CODE_LOCAL_ILLEGAL_STATE, "CODE_LOCAL_ILLEGAL_STATE");
+ sImsCodeMap.put(CODE_LOCAL_INTERNAL_ERROR, "CODE_LOCAL_INTERNAL_ERROR");
+ sImsCodeMap.put(CODE_LOCAL_IMS_SERVICE_DOWN, "CODE_LOCAL_IMS_SERVICE_DOWN");
+ sImsCodeMap.put(CODE_LOCAL_NO_PENDING_CALL, "CODE_LOCAL_NO_PENDING_CALL");
+ sImsCodeMap.put(CODE_LOCAL_ENDED_BY_CONFERENCE_MERGE,
+ "CODE_LOCAL_ENDED_BY_CONFERENCE_MERGE");
+ sImsCodeMap.put(CODE_LOCAL_POWER_OFF, "CODE_LOCAL_POWER_OFF");
+ sImsCodeMap.put(CODE_LOCAL_LOW_BATTERY, "CODE_LOCAL_LOW_BATTERY");
+ sImsCodeMap.put(CODE_LOCAL_NETWORK_NO_SERVICE, "CODE_LOCAL_NETWORK_NO_SERVICE");
+ sImsCodeMap.put(CODE_LOCAL_NETWORK_NO_LTE_COVERAGE, "CODE_LOCAL_NETWORK_NO_LTE_COVERAGE");
+ sImsCodeMap.put(CODE_LOCAL_NETWORK_ROAMING, "CODE_LOCAL_NETWORK_ROAMING");
+ sImsCodeMap.put(CODE_LOCAL_NETWORK_IP_CHANGED, "CODE_LOCAL_NETWORK_IP_CHANGED");
+ sImsCodeMap.put(CODE_LOCAL_SERVICE_UNAVAILABLE, "CODE_LOCAL_SERVICE_UNAVAILABLE");
+ sImsCodeMap.put(CODE_LOCAL_NOT_REGISTERED, "CODE_LOCAL_NOT_REGISTERED");
+ sImsCodeMap.put(CODE_LOCAL_CALL_EXCEEDED, "CODE_LOCAL_CALL_EXCEEDED");
+ sImsCodeMap.put(CODE_LOCAL_CALL_BUSY, "CODE_LOCAL_CALL_BUSY");
+ sImsCodeMap.put(CODE_LOCAL_CALL_DECLINE, "CODE_LOCAL_CALL_DECLINE");
+ sImsCodeMap.put(CODE_LOCAL_CALL_VCC_ON_PROGRESSING, "CODE_LOCAL_CALL_VCC_ON_PROGRESSING");
+ sImsCodeMap.put(CODE_LOCAL_CALL_RESOURCE_RESERVATION_FAILED,
+ "CODE_LOCAL_CALL_RESOURCE_RESERVATION_FAILED");
+ sImsCodeMap.put(CODE_LOCAL_CALL_CS_RETRY_REQUIRED, "CODE_LOCAL_CALL_CS_RETRY_REQUIRED");
+ sImsCodeMap.put(CODE_LOCAL_CALL_VOLTE_RETRY_REQUIRED,
+ "CODE_LOCAL_CALL_VOLTE_RETRY_REQUIRED");
+ sImsCodeMap.put(CODE_LOCAL_CALL_TERMINATED, "CODE_LOCAL_CALL_TERMINATED");
+ sImsCodeMap.put(CODE_LOCAL_HO_NOT_FEASIBLE, "CODE_LOCAL_HO_NOT_FEASIBLE");
+ sImsCodeMap.put(CODE_TIMEOUT_1XX_WAITING, "CODE_TIMEOUT_1XX_WAITING");
+ sImsCodeMap.put(CODE_TIMEOUT_NO_ANSWER, "CODE_TIMEOUT_NO_ANSWER");
+ sImsCodeMap.put(CODE_TIMEOUT_NO_ANSWER_CALL_UPDATE, "CODE_TIMEOUT_NO_ANSWER_CALL_UPDATE");
+ sImsCodeMap.put(CODE_CALL_BARRED, "CODE_CALL_BARRED");
+ sImsCodeMap.put(CODE_FDN_BLOCKED, "CODE_FDN_BLOCKED");
+ sImsCodeMap.put(CODE_IMEI_NOT_ACCEPTED, "CODE_IMEI_NOT_ACCEPTED");
+ sImsCodeMap.put(CODE_DIAL_MODIFIED_TO_USSD, "CODE_DIAL_MODIFIED_TO_USSD");
+ sImsCodeMap.put(CODE_DIAL_MODIFIED_TO_SS, "CODE_DIAL_MODIFIED_TO_SS");
+ sImsCodeMap.put(CODE_DIAL_MODIFIED_TO_DIAL, "CODE_DIAL_MODIFIED_TO_DIAL");
+ sImsCodeMap.put(CODE_DIAL_MODIFIED_TO_DIAL_VIDEO, "CODE_DIAL_MODIFIED_TO_DIAL_VIDEO");
+ sImsCodeMap.put(CODE_DIAL_VIDEO_MODIFIED_TO_DIAL, "CODE_DIAL_VIDEO_MODIFIED_TO_DIAL");
+ sImsCodeMap.put(CODE_DIAL_VIDEO_MODIFIED_TO_DIAL_VIDEO,
+ "CODE_DIAL_VIDEO_MODIFIED_TO_DIAL_VIDEO");
+ sImsCodeMap.put(CODE_DIAL_VIDEO_MODIFIED_TO_SS, "CODE_DIAL_VIDEO_MODIFIED_TO_SS");
+ sImsCodeMap.put(CODE_DIAL_VIDEO_MODIFIED_TO_USSD, "CODE_DIAL_VIDEO_MODIFIED_TO_USSD");
+ sImsCodeMap.put(CODE_SIP_REDIRECTED, "CODE_SIP_REDIRECTED");
+ sImsCodeMap.put(CODE_SIP_BAD_REQUEST, "CODE_SIP_BAD_REQUEST");
+ sImsCodeMap.put(CODE_SIP_FORBIDDEN, "CODE_SIP_FORBIDDEN");
+ sImsCodeMap.put(CODE_SIP_NOT_FOUND, "CODE_SIP_NOT_FOUND");
+ sImsCodeMap.put(CODE_SIP_NOT_SUPPORTED, "CODE_SIP_NOT_SUPPORTED");
+ sImsCodeMap.put(CODE_SIP_REQUEST_TIMEOUT, "CODE_SIP_REQUEST_TIMEOUT");
+ sImsCodeMap.put(CODE_SIP_TEMPRARILY_UNAVAILABLE, "CODE_SIP_TEMPRARILY_UNAVAILABLE");
+ sImsCodeMap.put(CODE_SIP_BAD_ADDRESS, "CODE_SIP_BAD_ADDRESS");
+ sImsCodeMap.put(CODE_SIP_BUSY, "CODE_SIP_BUSY");
+ sImsCodeMap.put(CODE_SIP_REQUEST_CANCELLED, "CODE_SIP_REQUEST_CANCELLED");
+ sImsCodeMap.put(CODE_SIP_NOT_ACCEPTABLE, "CODE_SIP_NOT_ACCEPTABLE");
+ sImsCodeMap.put(CODE_SIP_NOT_REACHABLE, "CODE_SIP_NOT_REACHABLE");
+ sImsCodeMap.put(CODE_SIP_CLIENT_ERROR, "CODE_SIP_CLIENT_ERROR");
+ sImsCodeMap.put(CODE_SIP_TRANSACTION_DOES_NOT_EXIST, "CODE_SIP_TRANSACTION_DOES_NOT_EXIST");
+ sImsCodeMap.put(CODE_SIP_SERVER_INTERNAL_ERROR, "CODE_SIP_SERVER_INTERNAL_ERROR");
+ sImsCodeMap.put(CODE_SIP_SERVICE_UNAVAILABLE, "CODE_SIP_SERVICE_UNAVAILABLE");
+ sImsCodeMap.put(CODE_SIP_SERVER_TIMEOUT, "CODE_SIP_SERVER_TIMEOUT");
+ sImsCodeMap.put(CODE_SIP_SERVER_ERROR, "CODE_SIP_SERVER_ERROR");
+ sImsCodeMap.put(CODE_SIP_USER_REJECTED, "CODE_SIP_USER_REJECTED");
+ sImsCodeMap.put(CODE_SIP_GLOBAL_ERROR, "CODE_SIP_GLOBAL_ERROR");
+ sImsCodeMap.put(CODE_EMERGENCY_TEMP_FAILURE, "CODE_EMERGENCY_TEMP_FAILURE");
+ sImsCodeMap.put(CODE_EMERGENCY_PERM_FAILURE, "CODE_EMERGENCY_PERM_FAILURE");
+ sImsCodeMap.put(CODE_SIP_USER_MARKED_UNWANTED, "CODE_SIP_USER_MARKED_UNWANTED");
+ sImsCodeMap.put(CODE_SIP_METHOD_NOT_ALLOWED, "CODE_SIP_METHOD_NOT_ALLOWED");
+ sImsCodeMap.put(CODE_SIP_PROXY_AUTHENTICATION_REQUIRED,
+ "CODE_SIP_PROXY_AUTHENTICATION_REQUIRED");
+ sImsCodeMap.put(CODE_SIP_REQUEST_ENTITY_TOO_LARGE, "CODE_SIP_REQUEST_ENTITY_TOO_LARGE");
+ sImsCodeMap.put(CODE_SIP_REQUEST_URI_TOO_LARGE, "CODE_SIP_REQUEST_URI_TOO_LARGE");
+ sImsCodeMap.put(CODE_SIP_EXTENSION_REQUIRED, "CODE_SIP_EXTENSION_REQUIRED");
+ sImsCodeMap.put(CODE_SIP_INTERVAL_TOO_BRIEF, "CODE_SIP_INTERVAL_TOO_BRIEF");
+ sImsCodeMap.put(CODE_SIP_CALL_OR_TRANS_DOES_NOT_EXIST,
+ "CODE_SIP_CALL_OR_TRANS_DOES_NOT_EXIST");
+ sImsCodeMap.put(CODE_SIP_LOOP_DETECTED, "CODE_SIP_LOOP_DETECTED");
+ sImsCodeMap.put(CODE_SIP_TOO_MANY_HOPS, "CODE_SIP_TOO_MANY_HOPS");
+ sImsCodeMap.put(CODE_SIP_AMBIGUOUS, "CODE_SIP_AMBIGUOUS");
+ sImsCodeMap.put(CODE_SIP_REQUEST_PENDING, "CODE_SIP_REQUEST_PENDING");
+ sImsCodeMap.put(CODE_SIP_UNDECIPHERABLE, "CODE_SIP_UNDECIPHERABLE");
+ sImsCodeMap.put(CODE_MEDIA_INIT_FAILED, "CODE_MEDIA_INIT_FAILED");
+ sImsCodeMap.put(CODE_MEDIA_NO_DATA, "CODE_MEDIA_NO_DATA");
+ sImsCodeMap.put(CODE_MEDIA_NOT_ACCEPTABLE, "CODE_MEDIA_NOT_ACCEPTABLE");
+ sImsCodeMap.put(CODE_MEDIA_UNSPECIFIED, "CODE_MEDIA_UNSPECIFIED");
+ sImsCodeMap.put(CODE_USER_TERMINATED, "CODE_USER_TERMINATED");
+ sImsCodeMap.put(CODE_USER_NOANSWER, "CODE_USER_NOANSWER");
+ sImsCodeMap.put(CODE_USER_IGNORE, "CODE_USER_IGNORE");
+ sImsCodeMap.put(CODE_USER_DECLINE, "CODE_USER_DECLINE");
+ sImsCodeMap.put(CODE_LOW_BATTERY, "CODE_LOW_BATTERY");
+ sImsCodeMap.put(CODE_BLACKLISTED_CALL_ID, "CODE_BLACKLISTED_CALL_ID");
+ sImsCodeMap.put(CODE_USER_TERMINATED_BY_REMOTE, "CODE_USER_TERMINATED_BY_REMOTE");
+ sImsCodeMap.put(CODE_USER_REJECTED_SESSION_MODIFICATION,
+ "CODE_USER_REJECTED_SESSION_MODIFICATION");
+ sImsCodeMap.put(CODE_USER_CANCELLED_SESSION_MODIFICATION,
+ "CODE_USER_CANCELLED_SESSION_MODIFICATION");
+ sImsCodeMap.put(CODE_SESSION_MODIFICATION_FAILED, "CODE_SESSION_MODIFICATION_FAILED");
+ sImsCodeMap.put(CODE_UT_NOT_SUPPORTED, "CODE_UT_NOT_SUPPORTED");
+ sImsCodeMap.put(CODE_UT_SERVICE_UNAVAILABLE, "CODE_UT_SERVICE_UNAVAILABLE");
+ sImsCodeMap.put(CODE_UT_OPERATION_NOT_ALLOWED, "CODE_UT_OPERATION_NOT_ALLOWED");
+ sImsCodeMap.put(CODE_UT_NETWORK_ERROR, "CODE_UT_NETWORK_ERROR");
+ sImsCodeMap.put(CODE_UT_CB_PASSWORD_MISMATCH, "CODE_UT_CB_PASSWORD_MISMATCH");
+ sImsCodeMap.put(CODE_UT_SS_MODIFIED_TO_DIAL, "CODE_UT_SS_MODIFIED_TO_DIAL");
+ sImsCodeMap.put(CODE_UT_SS_MODIFIED_TO_USSD, "CODE_UT_SS_MODIFIED_TO_USSD");
+ sImsCodeMap.put(CODE_UT_SS_MODIFIED_TO_SS, "CODE_UT_SS_MODIFIED_TO_SS");
+ sImsCodeMap.put(CODE_UT_SS_MODIFIED_TO_DIAL_VIDEO, "CODE_UT_SS_MODIFIED_TO_DIAL_VIDEO");
+ sImsCodeMap.put(CODE_ECBM_NOT_SUPPORTED, "CODE_ECBM_NOT_SUPPORTED");
+ sImsCodeMap.put(CODE_MULTIENDPOINT_NOT_SUPPORTED, "CODE_MULTIENDPOINT_NOT_SUPPORTED");
+ sImsCodeMap.put(CODE_REGISTRATION_ERROR, "CODE_REGISTRATION_ERROR");
+ sImsCodeMap.put(CODE_ANSWERED_ELSEWHERE, "CODE_ANSWERED_ELSEWHERE");
+ sImsCodeMap.put(CODE_CALL_PULL_OUT_OF_SYNC, "CODE_CALL_PULL_OUT_OF_SYNC");
+ sImsCodeMap.put(CODE_CALL_END_CAUSE_CALL_PULL, "CODE_CALL_END_CAUSE_CALL_PULL");
+ sImsCodeMap.put(CODE_CALL_DROP_IWLAN_TO_LTE_UNAVAILABLE,
+ "CODE_CALL_DROP_IWLAN_TO_LTE_UNAVAILABLE");
+ sImsCodeMap.put(CODE_REJECTED_ELSEWHERE, "CODE_REJECTED_ELSEWHERE");
+ sImsCodeMap.put(CODE_SUPP_SVC_FAILED, "CODE_SUPP_SVC_FAILED");
+ sImsCodeMap.put(CODE_SUPP_SVC_CANCELLED, "CODE_SUPP_SVC_CANCELLED");
+ sImsCodeMap.put(CODE_SUPP_SVC_REINVITE_COLLISION, "CODE_SUPP_SVC_REINVITE_COLLISION");
+ sImsCodeMap.put(CODE_IWLAN_DPD_FAILURE, "CODE_IWLAN_DPD_FAILURE");
+ sImsCodeMap.put(CODE_EPDG_TUNNEL_ESTABLISH_FAILURE, "CODE_EPDG_TUNNEL_ESTABLISH_FAILURE");
+ sImsCodeMap.put(CODE_EPDG_TUNNEL_REKEY_FAILURE, "CODE_EPDG_TUNNEL_REKEY_FAILURE");
+ sImsCodeMap.put(CODE_EPDG_TUNNEL_LOST_CONNECTION, "CODE_EPDG_TUNNEL_LOST_CONNECTION");
+ sImsCodeMap.put(CODE_MAXIMUM_NUMBER_OF_CALLS_REACHED,
+ "CODE_MAXIMUM_NUMBER_OF_CALLS_REACHED");
+ sImsCodeMap.put(CODE_REMOTE_CALL_DECLINE, "CODE_REMOTE_CALL_DECLINE");
+ sImsCodeMap.put(CODE_DATA_LIMIT_REACHED, "CODE_DATA_LIMIT_REACHED");
+ sImsCodeMap.put(CODE_DATA_DISABLED, "CODE_DATA_DISABLED");
+ sImsCodeMap.put(CODE_WIFI_LOST, "CODE_WIFI_LOST");
+ sImsCodeMap.put(CODE_IKEV2_AUTH_FAILURE, "CODE_IKEV2_AUTH_FAILURE");
+ sImsCodeMap.put(CODE_RADIO_OFF, "CODE_RADIO_OFF");
+ sImsCodeMap.put(CODE_NO_VALID_SIM, "CODE_NO_VALID_SIM");
+ sImsCodeMap.put(CODE_RADIO_INTERNAL_ERROR, "CODE_RADIO_INTERNAL_ERROR");
+ sImsCodeMap.put(CODE_NETWORK_RESP_TIMEOUT, "CODE_NETWORK_RESP_TIMEOUT");
+ sImsCodeMap.put(CODE_NETWORK_REJECT, "CODE_NETWORK_REJECT");
+ sImsCodeMap.put(CODE_RADIO_ACCESS_FAILURE, "CODE_RADIO_ACCESS_FAILURE");
+ sImsCodeMap.put(CODE_RADIO_LINK_FAILURE, "CODE_RADIO_LINK_FAILURE");
+ sImsCodeMap.put(CODE_RADIO_LINK_LOST, "CODE_RADIO_LINK_LOST");
+ sImsCodeMap.put(CODE_RADIO_UPLINK_FAILURE, "CODE_RADIO_UPLINK_FAILURE");
+ sImsCodeMap.put(CODE_RADIO_SETUP_FAILURE, "CODE_RADIO_SETUP_FAILURE");
+ sImsCodeMap.put(CODE_RADIO_RELEASE_NORMAL, "CODE_RADIO_RELEASE_NORMAL");
+ sImsCodeMap.put(CODE_RADIO_RELEASE_ABNORMAL, "CODE_RADIO_RELEASE_ABNORMAL");
+ sImsCodeMap.put(CODE_ACCESS_CLASS_BLOCKED, "CODE_ACCESS_CLASS_BLOCKED");
+ sImsCodeMap.put(CODE_NETWORK_DETACH, "CODE_NETWORK_DETACH");
+ sImsCodeMap.put(CODE_SIP_ALTERNATE_EMERGENCY_CALL, "CODE_SIP_ALTERNATE_EMERGENCY_CALL");
+ sImsCodeMap.put(CODE_UNOBTAINABLE_NUMBER, "CODE_UNOBTAINABLE_NUMBER");
+ sImsCodeMap.put(CODE_NO_CSFB_IN_CS_ROAM, "CODE_NO_CSFB_IN_CS_ROAM");
+ sImsCodeMap.put(CODE_REJECT_UNKNOWN, "CODE_REJECT_UNKNOWN");
+ sImsCodeMap.put(CODE_REJECT_ONGOING_CALL_WAITING_DISABLED,
+ "CODE_REJECT_ONGOING_CALL_WAITING_DISABLED");
+ sImsCodeMap.put(CODE_REJECT_CALL_ON_OTHER_SUB, "CODE_REJECT_CALL_ON_OTHER_SUB");
+ sImsCodeMap.put(CODE_REJECT_1X_COLLISION, "CODE_REJECT_1X_COLLISION");
+ sImsCodeMap.put(CODE_REJECT_SERVICE_NOT_REGISTERED, "CODE_REJECT_SERVICE_NOT_REGISTERED");
+ sImsCodeMap.put(CODE_REJECT_CALL_TYPE_NOT_ALLOWED, "CODE_REJECT_CALL_TYPE_NOT_ALLOWED");
+ sImsCodeMap.put(CODE_REJECT_ONGOING_E911_CALL, "CODE_REJECT_ONGOING_E911_CALL");
+ sImsCodeMap.put(CODE_REJECT_ONGOING_CALL_SETUP, "CODE_REJECT_ONGOING_CALL_SETUP");
+ sImsCodeMap.put(CODE_REJECT_MAX_CALL_LIMIT_REACHED, "CODE_REJECT_MAX_CALL_LIMIT_REACHED");
+ sImsCodeMap.put(CODE_REJECT_UNSUPPORTED_SIP_HEADERS, "CODE_REJECT_UNSUPPORTED_SIP_HEADERS");
+ sImsCodeMap.put(CODE_REJECT_UNSUPPORTED_SDP_HEADERS, "CODE_REJECT_UNSUPPORTED_SDP_HEADERS");
+ sImsCodeMap.put(CODE_REJECT_ONGOING_CALL_TRANSFER, "CODE_REJECT_ONGOING_CALL_TRANSFER");
+ sImsCodeMap.put(CODE_REJECT_INTERNAL_ERROR, "CODE_REJECT_INTERNAL_ERROR");
+ sImsCodeMap.put(CODE_REJECT_QOS_FAILURE, "CODE_REJECT_QOS_FAILURE");
+ sImsCodeMap.put(CODE_REJECT_ONGOING_HANDOVER, "CODE_REJECT_ONGOING_HANDOVER");
+ sImsCodeMap.put(CODE_REJECT_VT_TTY_NOT_ALLOWED, "CODE_REJECT_VT_TTY_NOT_ALLOWED");
+ sImsCodeMap.put(CODE_REJECT_ONGOING_CALL_UPGRADE, "CODE_REJECT_ONGOING_CALL_UPGRADE");
+ sImsCodeMap.put(CODE_REJECT_CONFERENCE_TTY_NOT_ALLOWED,
+ "CODE_REJECT_CONFERENCE_TTY_NOT_ALLOWED");
+ sImsCodeMap.put(CODE_REJECT_ONGOING_CONFERENCE_CALL, "CODE_REJECT_ONGOING_CONFERENCE_CALL");
+ sImsCodeMap.put(CODE_REJECT_VT_AVPF_NOT_ALLOWED, "CODE_REJECT_VT_AVPF_NOT_ALLOWED");
+ sImsCodeMap.put(CODE_REJECT_ONGOING_ENCRYPTED_CALL, "CODE_REJECT_ONGOING_ENCRYPTED_CALL");
+ sImsCodeMap.put(CODE_REJECT_ONGOING_CS_CALL, "CODE_REJECT_ONGOING_CS_CALL");
+ sImsCodeMap.put(CODE_RETRY_ON_IMS_WITHOUT_RTT, "CODE_RETRY_ON_IMS_WITHOUT_RTT");
+ sImsCodeMap.put(CODE_OEM_CAUSE_1, "CODE_OEM_CAUSE_1");
+ sImsCodeMap.put(CODE_OEM_CAUSE_2, "CODE_OEM_CAUSE_2");
+ sImsCodeMap.put(CODE_OEM_CAUSE_3, "CODE_OEM_CAUSE_3");
+ sImsCodeMap.put(CODE_OEM_CAUSE_4, "CODE_OEM_CAUSE_4");
+ sImsCodeMap.put(CODE_OEM_CAUSE_5, "CODE_OEM_CAUSE_5");
+ sImsCodeMap.put(CODE_OEM_CAUSE_6, "CODE_OEM_CAUSE_6");
+ sImsCodeMap.put(CODE_OEM_CAUSE_7, "CODE_OEM_CAUSE_7");
+ sImsCodeMap.put(CODE_OEM_CAUSE_8, "CODE_OEM_CAUSE_8");
+ sImsCodeMap.put(CODE_OEM_CAUSE_9, "CODE_OEM_CAUSE_9");
+ sImsCodeMap.put(CODE_OEM_CAUSE_10, "CODE_OEM_CAUSE_10");
+ sImsCodeMap.put(CODE_OEM_CAUSE_11, "CODE_OEM_CAUSE_11");
+ sImsCodeMap.put(CODE_OEM_CAUSE_12, "CODE_OEM_CAUSE_12");
+ sImsCodeMap.put(CODE_OEM_CAUSE_13, "CODE_OEM_CAUSE_13");
+ sImsCodeMap.put(CODE_OEM_CAUSE_14, "CODE_OEM_CAUSE_14");
+ sImsCodeMap.put(CODE_OEM_CAUSE_15, "CODE_OEM_CAUSE_15");
+ }
+
/**
* Network string error messages.
* mExtraMessage may have these values.
@@ -1203,7 +1394,9 @@ public final class ImsReasonInfo implements Parcelable {
@NonNull
@Override
public String toString() {
- return "ImsReasonInfo :: {" + mCode + ", " + mExtraCode + ", " + mExtraMessage + "}";
+ String imsCode = (sImsCodeMap.containsKey(mCode)) ? sImsCodeMap.get(mCode) : "UNKNOWN_CODE";
+ return "ImsReasonInfo :: {" + mCode + " : " + imsCode + ", "
+ + mExtraCode + ", " + mExtraMessage + "}";
}
@Override
diff --git a/telephony/java/android/telephony/ims/compat/stub/ImsConfigImplBase.java b/telephony/java/android/telephony/ims/compat/stub/ImsConfigImplBase.java
index aae6f9214c70..0c7264697cd3 100644
--- a/telephony/java/android/telephony/ims/compat/stub/ImsConfigImplBase.java
+++ b/telephony/java/android/telephony/ims/compat/stub/ImsConfigImplBase.java
@@ -89,7 +89,7 @@ public class ImsConfigImplBase {
/**
* Sets the value for IMS service/capabilities parameters by the operator device
* management entity. It sets the config item value in the provisioned storage
- * from which the master value is derived. Synchronous blocking call.
+ * from which the main value is derived. Synchronous blocking call.
*
* @param item, as defined in com.android.ims.ImsConfig#ConfigConstants.
* @param value in Integer format.
@@ -102,7 +102,7 @@ public class ImsConfigImplBase {
/**
* Sets the value for IMS service/capabilities parameters by the operator device
* management entity. It sets the config item value in the provisioned storage
- * from which the master value is derived. Synchronous blocking call.
+ * from which the main value is derived. Synchronous blocking call.
*
* @param item as defined in com.android.ims.ImsConfig#ConfigConstants.
* @param value in String format.
@@ -114,7 +114,7 @@ public class ImsConfigImplBase {
/**
* Gets the value of the specified IMS feature item for specified network type.
- * This operation gets the feature config value from the master storage (i.e. final
+ * This operation gets the feature config value from the main storage (i.e. final
* value). Asynchronous non-blocking call.
*
* @param feature as defined in com.android.ims.ImsConfig#FeatureConstants.
@@ -127,7 +127,7 @@ public class ImsConfigImplBase {
/**
* Sets the value for IMS feature item for specified network type.
- * This operation stores the user setting in setting db from which master db
+ * This operation stores the user setting in setting db from which main db
* is derived.
*
* @param feature as defined in com.android.ims.ImsConfig#FeatureConstants.
@@ -268,7 +268,7 @@ public class ImsConfigImplBase {
/**
* Sets the value for IMS service/capabilities parameters by the operator device
* management entity. It sets the config item value in the provisioned storage
- * from which the master value is derived, and write it into local cache.
+ * from which the main value is derived, and write it into local cache.
* Synchronous blocking call.
*
* @param item, as defined in com.android.ims.ImsConfig#ConfigConstants.
@@ -292,7 +292,7 @@ public class ImsConfigImplBase {
/**
* Sets the value for IMS service/capabilities parameters by the operator device
* management entity. It sets the config item value in the provisioned storage
- * from which the master value is derived, and write it into local cache.
+ * from which the main value is derived, and write it into local cache.
* Synchronous blocking call.
*
* @param item as defined in com.android.ims.ImsConfig#ConfigConstants.
diff --git a/telephony/java/android/telephony/ims/stub/ImsCallSessionImplBase.java b/telephony/java/android/telephony/ims/stub/ImsCallSessionImplBase.java
index 73ba0e393e78..8f738d216cbe 100644
--- a/telephony/java/android/telephony/ims/stub/ImsCallSessionImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/ImsCallSessionImplBase.java
@@ -439,8 +439,8 @@ public class ImsCallSessionImplBase implements AutoCloseable {
* Transfer an established call to given number
*
* @param number number to transfer the call
- * @param isConfirmationRequired if {@code True}, indicates Assured transfer,
- * if {@code False} it indicates Blind transfer.
+ * @param isConfirmationRequired if {@code True}, indicates a confirmed transfer,
+ * if {@code False} it indicates an unconfirmed transfer.
* @hide
*/
public void transfer(@NonNull String number, boolean isConfirmationRequired) {
diff --git a/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java b/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java
index 6a2638bc7221..4ef44d3ec9ef 100644
--- a/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java
@@ -142,7 +142,7 @@ public class ImsConfigImplBase {
/**
* Sets the value for IMS service/capabilities parameters by the operator device
* management entity. It sets the config item value in the provisioned storage
- * from which the master value is derived, and write it into local cache.
+ * from which the main value is derived, and write it into local cache.
* Synchronous blocking call.
*
* @param item integer key
@@ -167,7 +167,7 @@ public class ImsConfigImplBase {
/**
* Sets the value for IMS service/capabilities parameters by the operator device
* management entity. It sets the config item value in the provisioned storage
- * from which the master value is derived, and write it into local cache.
+ * from which the main value is derived, and write it into local cache.
* Synchronous blocking call.
*
* @param item as defined in com.android.ims.ImsConfig#ConfigConstants.
diff --git a/telephony/java/android/telephony/mbms/MbmsTempFileProvider.java b/telephony/java/android/telephony/mbms/MbmsTempFileProvider.java
index 689becd7169a..17adede86c51 100644
--- a/telephony/java/android/telephony/mbms/MbmsTempFileProvider.java
+++ b/telephony/java/android/telephony/mbms/MbmsTempFileProvider.java
@@ -91,7 +91,7 @@ public class MbmsTempFileProvider extends ContentProvider {
public void attachInfo(Context context, ProviderInfo info) {
super.attachInfo(context, info);
- // Sanity check our security
+ // Correctness check our security
if (info.exported) {
throw new SecurityException("Provider must not be exported");
}
diff --git a/telephony/java/com/android/ims/internal/IImsCallSession.aidl b/telephony/java/com/android/ims/internal/IImsCallSession.aidl
index 0466efc2f6c6..ab14e82b7087 100644
--- a/telephony/java/com/android/ims/internal/IImsCallSession.aidl
+++ b/telephony/java/com/android/ims/internal/IImsCallSession.aidl
@@ -153,8 +153,8 @@ interface IImsCallSession {
* Transfer an established call to given number
*
* @param number number to transfer the call
- * @param isConfirmationRequired if {@code True}, indicates Assured transfer,
- * if {@code False} it indicates Blind transfer.
+ * @param isConfirmationRequired if {@code True}, indicates a confirmed transfer,
+ * if {@code False} it indicates an unconfirmed transfer.
*/
void transfer(String number, boolean isConfirmationRequired);
diff --git a/telephony/java/com/android/ims/internal/IImsConfig.aidl b/telephony/java/com/android/ims/internal/IImsConfig.aidl
index 7324814ae5a4..1a14e8780664 100644
--- a/telephony/java/com/android/ims/internal/IImsConfig.aidl
+++ b/telephony/java/com/android/ims/internal/IImsConfig.aidl
@@ -49,7 +49,7 @@ interface IImsConfig {
/**
* Sets the value for IMS service/capabilities parameters by the operator device
* management entity. It sets the config item value in the provisioned storage
- * from which the master value is derived. Synchronous blocking call.
+ * from which the main value is derived. Synchronous blocking call.
*
* @param item, as defined in com.android.ims.ImsConfig#ConfigConstants.
* @param value in Integer format.
@@ -60,7 +60,7 @@ interface IImsConfig {
/**
* Sets the value for IMS service/capabilities parameters by the operator device
* management entity. It sets the config item value in the provisioned storage
- * from which the master value is derived. Synchronous blocking call.
+ * from which the main value is derived. Synchronous blocking call.
*
* @param item, as defined in com.android.ims.ImsConfig#ConfigConstants.
* @param value in String format.
@@ -70,7 +70,7 @@ interface IImsConfig {
/**
* Gets the value of the specified IMS feature item for specified network type.
- * This operation gets the feature config value from the master storage (i.e. final
+ * This operation gets the feature config value from the main storage (i.e. final
* value). Asynchronous non-blocking call.
*
* @param feature. as defined in com.android.ims.ImsConfig#FeatureConstants.
@@ -82,7 +82,7 @@ interface IImsConfig {
/**
* Sets the value for IMS feature item for specified network type.
- * This operation stores the user setting in setting db from which master db
+ * This operation stores the user setting in setting db from which main db
* is dervied.
*
* @param feature. as defined in com.android.ims.ImsConfig#FeatureConstants.
diff --git a/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
index 542e08d743ab..a34e474e666e 100644
--- a/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
+++ b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
@@ -479,7 +479,7 @@ public class SmsMessage extends SmsMessageBase {
length = dis.readUnsignedByte();
addr.numberOfDigits = length;
- // sanity check on the length
+ // Correctness check on the length
if (length > pdu.length) {
throw new RuntimeException(
"createFromPdu: Invalid pdu, addr.numberOfDigits " + length
@@ -496,7 +496,7 @@ public class SmsMessage extends SmsMessageBase {
//encoded BearerData:
bearerDataLength = dis.readInt();
- // sanity check on the length
+ // Correctness check on the length
if (bearerDataLength > pdu.length) {
throw new RuntimeException(
"createFromPdu: Invalid pdu, bearerDataLength " + bearerDataLength
diff --git a/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java b/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java
index 7e31c4633050..e3df903b7f4f 100644
--- a/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java
+++ b/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java
@@ -353,7 +353,7 @@ public class SmsMessage extends SmsMessageBase {
statusReportRequested, ret);
// Skip encoding pdu if error occurs when create pdu head and the error will be handled
- // properly later on encodedMessage sanity check.
+ // properly later on encodedMessage correctness check.
if (bo == null) return ret;
// User Data (and length)
@@ -535,7 +535,7 @@ public class SmsMessage extends SmsMessageBase {
scAddress, destinationAddress, (byte) 0x41, /* TP-MTI=SMS-SUBMIT, TP-UDHI=true */
statusReportRequested, ret);
// Skip encoding pdu if error occurs when create pdu head and the error will be handled
- // properly later on encodedMessage sanity check.
+ // properly later on encodedMessage correctness check.
if (bo == null) return ret;
// TP-Data-Coding-Scheme
diff --git a/tests/BlobStoreTestUtils/src/com/android/utils/blob/DummyBlobData.java b/tests/BlobStoreTestUtils/src/com/android/utils/blob/FakeBlobData.java
index 2df0024bdea9..56db4f98e160 100644
--- a/tests/BlobStoreTestUtils/src/com/android/utils/blob/DummyBlobData.java
+++ b/tests/BlobStoreTestUtils/src/com/android/utils/blob/FakeBlobData.java
@@ -35,7 +35,7 @@ import java.security.MessageDigest;
import java.util.Random;
import java.util.concurrent.TimeUnit;
-public class DummyBlobData {
+public class FakeBlobData {
private static final long DEFAULT_SIZE_BYTES = 10 * 1024L * 1024L;
private final Random mRandom;
@@ -47,7 +47,7 @@ public class DummyBlobData {
byte[] mFileDigest;
long mExpiryTimeMs;
- private DummyBlobData(Builder builder) {
+ private FakeBlobData(Builder builder) {
mRandom = new Random(builder.getRandomSeed());
mFile = new File(builder.getContext().getFilesDir(), builder.getFileName());
mFileSize = builder.getFileSize();
@@ -116,8 +116,8 @@ public class DummyBlobData {
return mExpiryDurationMs;
}
- public DummyBlobData build() {
- return new DummyBlobData(this);
+ public FakeBlobData build() {
+ return new FakeBlobData(this);
}
}
diff --git a/tests/FlickerTests/Android.bp b/tests/FlickerTests/Android.bp
index 5161fba026db..952997efa0d4 100644
--- a/tests/FlickerTests/Android.bp
+++ b/tests/FlickerTests/Android.bp
@@ -24,6 +24,7 @@ android_test {
test_suites: ["device-tests"],
libs: ["android.test.runner"],
static_libs: [
+ "androidx.test.ext.junit",
"flickertestapplib",
"flickerlib",
"truth-prebuilt",
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt
new file mode 100644
index 000000000000..c1a3ed695096
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker
+
+import com.android.server.wm.flicker.dsl.EventLogAssertion
+import com.android.server.wm.flicker.dsl.LayersAssertion
+import com.android.server.wm.flicker.dsl.WmAssertion
+import com.android.server.wm.flicker.helpers.WindowUtils
+
+@JvmOverloads
+fun WmAssertion.statusBarWindowIsAlwaysVisible(
+ bugId: Int = 0,
+ enabled: Boolean = bugId == 0
+) {
+ all("statusBarWindowIsAlwaysVisible", enabled, bugId) {
+ this.showsAboveAppWindow(FlickerTestBase.STATUS_BAR_WINDOW_TITLE)
+ }
+}
+
+@JvmOverloads
+fun WmAssertion.navBarWindowIsAlwaysVisible(
+ bugId: Int = 0,
+ enabled: Boolean = bugId == 0
+) {
+ all("navBarWindowIsAlwaysVisible", enabled, bugId) {
+ this.showsAboveAppWindow(FlickerTestBase.NAVIGATION_BAR_WINDOW_TITLE)
+ }
+}
+
+@JvmOverloads
+fun LayersAssertion.noUncoveredRegions(
+ beginRotation: Int,
+ endRotation: Int = beginRotation,
+ allStates: Boolean = true,
+ bugId: Int = 0,
+ enabled: Boolean = bugId == 0
+) {
+ val startingBounds = WindowUtils.getDisplayBounds(beginRotation)
+ val endingBounds = WindowUtils.getDisplayBounds(endRotation)
+ if (allStates) {
+ all("noUncoveredRegions", enabled, bugId) {
+ if (startingBounds == endingBounds) {
+ this.coversAtLeastRegion(startingBounds)
+ } else {
+ this.coversAtLeastRegion(startingBounds)
+ .then()
+ .coversAtLeastRegion(endingBounds)
+ }
+ }
+ } else {
+ start("noUncoveredRegions_StartingPos") {
+ this.coversAtLeastRegion(startingBounds)
+ }
+ end("noUncoveredRegions_EndingPos") {
+ this.coversAtLeastRegion(endingBounds)
+ }
+ }
+}
+
+@JvmOverloads
+fun LayersAssertion.navBarLayerIsAlwaysVisible(
+ bugId: Int = 0,
+ enabled: Boolean = bugId == 0
+) {
+ all("navBarLayerIsAlwaysVisible", enabled, bugId) {
+ this.showsLayer(FlickerTestBase.NAVIGATION_BAR_WINDOW_TITLE)
+ }
+}
+
+@JvmOverloads
+fun LayersAssertion.statusBarLayerIsAlwaysVisible(
+ bugId: Int = 0,
+ enabled: Boolean = bugId == 0
+) {
+ all("statusBarLayerIsAlwaysVisible", enabled, bugId) {
+ this.showsLayer(FlickerTestBase.STATUS_BAR_WINDOW_TITLE)
+ }
+}
+
+@JvmOverloads
+fun LayersAssertion.navBarLayerRotatesAndScales(
+ beginRotation: Int,
+ endRotation: Int = beginRotation,
+ bugId: Int = 0,
+ enabled: Boolean = bugId == 0
+) {
+ val startingPos = WindowUtils.getNavigationBarPosition(beginRotation)
+ val endingPos = WindowUtils.getNavigationBarPosition(endRotation)
+
+ start("navBarLayerRotatesAndScales_StartingPos", enabled, bugId) {
+ this.hasVisibleRegion(FlickerTestBase.NAVIGATION_BAR_WINDOW_TITLE, startingPos)
+ }
+ end("navBarLayerRotatesAndScales_EndingPost", enabled, bugId) {
+ this.hasVisibleRegion(FlickerTestBase.NAVIGATION_BAR_WINDOW_TITLE, endingPos)
+ }
+
+ if (startingPos == endingPos) {
+ all("navBarLayerRotatesAndScales", enabled, bugId) {
+ this.hasVisibleRegion(FlickerTestBase.NAVIGATION_BAR_WINDOW_TITLE, startingPos)
+ }
+ }
+}
+
+@JvmOverloads
+fun LayersAssertion.statusBarLayerRotatesScales(
+ beginRotation: Int,
+ endRotation: Int = beginRotation,
+ bugId: Int = 0,
+ enabled: Boolean = bugId == 0
+) {
+ val startingPos = WindowUtils.getStatusBarPosition(beginRotation)
+ val endingPos = WindowUtils.getStatusBarPosition(endRotation)
+
+ start("statusBarLayerRotatesScales_StartingPos", enabled, bugId) {
+ this.hasVisibleRegion(FlickerTestBase.STATUS_BAR_WINDOW_TITLE, startingPos)
+ }
+ end("statusBarLayerRotatesScales_EndingPos", enabled, bugId) {
+ this.hasVisibleRegion(FlickerTestBase.STATUS_BAR_WINDOW_TITLE, endingPos)
+ }
+}
+
+fun EventLogAssertion.focusChanges(
+ vararg windows: String,
+ bugId: Int = 0,
+ enabled: Boolean = bugId == 0
+) {
+ all(enabled = enabled, bugId = bugId) {
+ this.focusChanges(windows)
+ }
+}
+
+fun EventLogAssertion.focusDoesNotChange(
+ bugId: Int = 0,
+ enabled: Boolean = bugId == 0
+) {
+ all(enabled = enabled, bugId = bugId) {
+ this.focusDoesNotChange()
+ }
+} \ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/CommonTransitions.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/CommonTransitions.kt
deleted file mode 100644
index b69e6a9736a3..000000000000
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/CommonTransitions.kt
+++ /dev/null
@@ -1,446 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm.flicker
-
-import android.app.Instrumentation
-import android.content.Context
-import android.content.Intent
-import android.os.RemoteException
-import android.os.SystemClock
-import android.platform.helpers.IAppHelper
-import android.util.Rational
-import android.view.Surface
-import androidx.test.uiautomator.By
-import androidx.test.uiautomator.UiDevice
-import androidx.test.uiautomator.Until
-import com.android.server.wm.flicker.helpers.AutomationUtils
-import com.android.server.wm.flicker.helpers.ImeAppHelper
-import com.android.server.wm.flicker.helpers.PipAppHelper
-
-/**
- * Collection of common transitions which can be used to test different apps or scenarios.
- */
-internal object CommonTransitions {
- private const val ITERATIONS = 1
- private const val APP_LAUNCH_TIMEOUT: Long = 10000
- private fun setRotation(device: UiDevice, rotation: Int) {
- try {
- when (rotation) {
- Surface.ROTATION_270 -> device.setOrientationLeft()
- Surface.ROTATION_90 -> device.setOrientationRight()
- Surface.ROTATION_0 -> device.setOrientationNatural()
- else -> device.setOrientationNatural()
- }
- // Wait for animation to complete
- SystemClock.sleep(1000)
- } catch (e: RemoteException) {
- throw RuntimeException(e)
- }
- }
-
- /**
- * Build a test tag for the test
- * @param testName Name of the transition(s) being tested
- * @param app App being launcher
- * @param rotation Initial screen rotation
- *
- * @return test tag with pattern <NAME>__<APP>__<ROTATION>
- </ROTATION></APP></NAME> */
- private fun buildTestTag(testName: String, app: IAppHelper, rotation: Int): String {
- return buildTestTag(
- testName, app, rotation, rotation, app2 = null, extraInfo = "")
- }
-
- /**
- * Build a test tag for the test
- * @param testName Name of the transition(s) being tested
- * @param app App being launcher
- * @param beginRotation Initial screen rotation
- * @param endRotation End screen rotation (if any, otherwise use same as initial)
- *
- * @return test tag with pattern <NAME>__<APP>__<BEGIN_ROTATION>-<END_ROTATION>
- </END_ROTATION></BEGIN_ROTATION></APP></NAME> */
- private fun buildTestTag(
- testName: String,
- app: IAppHelper,
- beginRotation: Int,
- endRotation: Int
- ): String {
- return buildTestTag(
- testName, app, beginRotation, endRotation, app2 = null, extraInfo = "")
- }
-
- /**
- * Build a test tag for the test
- * @param testName Name of the transition(s) being tested
- * @param app App being launcher
- * @param app2 Second app being launched (if any)
- * @param beginRotation Initial screen rotation
- * @param endRotation End screen rotation (if any, otherwise use same as initial)
- * @param extraInfo Additional information to append to the tag
- *
- * @return test tag with pattern <NAME>__<APP></APP>(S)>__<ROTATION></ROTATION>(S)>[__<EXTRA>]
- </EXTRA></NAME> */
- private fun buildTestTag(
- testName: String,
- app: IAppHelper,
- beginRotation: Int,
- endRotation: Int,
- app2: IAppHelper?,
- extraInfo: String
- ): String {
- val testTag = StringBuilder()
- testTag.append(testName)
- .append("__")
- .append(app.launcherName)
- if (app2 != null) {
- testTag.append("-")
- .append(app2.launcherName)
- }
- testTag.append("__")
- .append(Surface.rotationToString(beginRotation))
- if (endRotation != beginRotation) {
- testTag.append("-")
- .append(Surface.rotationToString(endRotation))
- }
- if (extraInfo.isNotEmpty()) {
- testTag.append("__")
- .append(extraInfo)
- }
- return testTag.toString()
- }
-
- fun openAppWarm(
- testApp: IAppHelper,
- instrumentation: Instrumentation,
- device: UiDevice,
- beginRotation: Int
- ): TransitionRunner.TransitionBuilder {
- return TransitionRunner.TransitionBuilder(instrumentation)
- .withTag(buildTestTag("openAppWarm", testApp, beginRotation))
- .recordAllRuns()
- .runBeforeAll { AutomationUtils.wakeUpAndGoToHomeScreen() }
- .runBeforeAll { setRotation(device, beginRotation) }
- .runBeforeAll { testApp.open() }
- .runBefore { device.pressHome() }
- .runBefore { device.waitForIdle() }
- .runBefore { setRotation(device, beginRotation) }
- .run { testApp.open() }
- .runAfterAll { testApp.exit() }
- .runAfterAll { AutomationUtils.setDefaultWait() }
- .repeat(ITERATIONS)
- }
-
- fun closeAppWithBackKey(
- testApp: IAppHelper,
- instrumentation: Instrumentation,
- device: UiDevice,
- beginRotation: Int
- ): TransitionRunner.TransitionBuilder {
- return TransitionRunner.TransitionBuilder(instrumentation)
- .withTag(buildTestTag("closeAppWithBackKey", testApp, beginRotation))
- .recordAllRuns()
- .runBeforeAll { AutomationUtils.wakeUpAndGoToHomeScreen() }
- .runBefore { testApp.open() }
- .runBefore { device.waitForIdle() }
- .run { device.pressBack() }
- .run { device.waitForIdle() }
- .runAfterAll { testApp.exit() }
- .runAfterAll { AutomationUtils.setDefaultWait() }
- .repeat(ITERATIONS)
- }
-
- fun closeAppWithHomeKey(
- testApp: IAppHelper,
- instrumentation: Instrumentation,
- device: UiDevice,
- beginRotation: Int
- ): TransitionRunner.TransitionBuilder {
- return TransitionRunner.TransitionBuilder(instrumentation)
- .withTag(buildTestTag("closeAppWithHomeKey", testApp, beginRotation))
- .recordAllRuns()
- .runBeforeAll { AutomationUtils.wakeUpAndGoToHomeScreen() }
- .runBefore { testApp.open() }
- .runBefore { device.waitForIdle() }
- .run { device.pressHome() }
- .run { device.waitForIdle() }
- .runAfterAll { testApp.exit() }
- .runAfterAll { AutomationUtils.setDefaultWait() }
- .repeat(ITERATIONS)
- }
-
- fun openAppCold(
- testApp: IAppHelper,
- instrumentation: Instrumentation,
- device: UiDevice,
- beginRotation: Int
- ): TransitionRunner.TransitionBuilder {
- return TransitionRunner.TransitionBuilder(instrumentation)
- .withTag(buildTestTag("openAppCold", testApp, beginRotation))
- .recordAllRuns()
- .runBeforeAll { AutomationUtils.wakeUpAndGoToHomeScreen() }
- .runBefore { device.pressHome() }
- .runBeforeAll { setRotation(device, beginRotation) }
- .runBefore { testApp.exit() }
- .runBefore { device.waitForIdle() }
- .run { testApp.open() }
- .runAfterAll { testApp.exit() }
- .runAfterAll { setRotation(device, Surface.ROTATION_0) }
- .repeat(ITERATIONS)
- }
-
- fun changeAppRotation(
- testApp: IAppHelper,
- instrumentation: Instrumentation,
- device: UiDevice,
- beginRotation: Int,
- endRotation: Int
- ): TransitionRunner.TransitionBuilder {
- return TransitionRunner.TransitionBuilder(instrumentation)
- .withTag(buildTestTag("changeAppRotation", testApp, beginRotation, endRotation))
- .recordAllRuns()
- .runBeforeAll { AutomationUtils.wakeUpAndGoToHomeScreen() }
- .runBeforeAll { testApp.open() }
- .runBefore { setRotation(device, beginRotation) }
- .run { setRotation(device, endRotation) }
- .runAfterAll { testApp.exit() }
- .runAfterAll { setRotation(device, Surface.ROTATION_0) }
- .repeat(ITERATIONS)
- }
-
- fun changeAppRotation(
- intent: Intent,
- intentId: String,
- context: Context,
- instrumentation: Instrumentation,
- device: UiDevice,
- beginRotation: Int,
- endRotation: Int
- ): TransitionRunner.TransitionBuilder {
- val testTag = "changeAppRotation_" + intentId + "_" +
- Surface.rotationToString(beginRotation) + "_" +
- Surface.rotationToString(endRotation)
- return TransitionRunner.TransitionBuilder(instrumentation)
- .withTag(testTag)
- .recordAllRuns()
- .runBeforeAll { AutomationUtils.wakeUpAndGoToHomeScreen() }
- .runBeforeAll {
- context.startActivity(intent)
- device.wait(Until.hasObject(By.pkg(intent.component?.packageName)
- .depth(0)), APP_LAUNCH_TIMEOUT)
- }
- .runBefore { setRotation(device, beginRotation) }
- .run { setRotation(device, endRotation) }
- .runAfterAll { AutomationUtils.stopPackage(context, intent.component?.packageName) }
- .runAfterAll { setRotation(device, Surface.ROTATION_0) }
- .repeat(ITERATIONS)
- }
-
- fun appToSplitScreen(
- testApp: IAppHelper,
- instrumentation: Instrumentation,
- device: UiDevice,
- beginRotation: Int
- ): TransitionRunner.TransitionBuilder {
- return TransitionRunner.TransitionBuilder(instrumentation)
- .withTag(buildTestTag("appToSplitScreen", testApp, beginRotation))
- .recordAllRuns()
- .runBeforeAll { AutomationUtils.wakeUpAndGoToHomeScreen() }
- .runBeforeAll { setRotation(device, beginRotation) }
- .runBefore { testApp.open() }
- .runBefore { device.waitForIdle() }
- .runBefore { SystemClock.sleep(500) }
- .run { AutomationUtils.launchSplitScreen(device) }
- .runAfter { AutomationUtils.exitSplitScreen(device) }
- .runAfterAll { testApp.exit() }
- .repeat(ITERATIONS)
- }
-
- fun splitScreenToLauncher(
- testApp: IAppHelper,
- instrumentation: Instrumentation,
- device: UiDevice,
- beginRotation: Int
- ): TransitionRunner.TransitionBuilder {
- return TransitionRunner.TransitionBuilder(instrumentation)
- .withTag(buildTestTag("splitScreenToLauncher", testApp, beginRotation))
- .recordAllRuns()
- .runBeforeAll { AutomationUtils.wakeUpAndGoToHomeScreen() }
- .runBefore { testApp.open() }
- .runBefore { device.waitForIdle() }
- .runBefore { AutomationUtils.launchSplitScreen(device) }
- .run { AutomationUtils.exitSplitScreen(device) }
- .runAfterAll { testApp.exit() }
- .repeat(ITERATIONS)
- }
-
- fun editTextSetFocus(
- testApp: ImeAppHelper,
- instrumentation: Instrumentation,
- device: UiDevice,
- beginRotation: Int
- ): TransitionRunner.TransitionBuilder {
- return TransitionRunner.TransitionBuilder(instrumentation)
- .withTag(buildTestTag("editTextSetFocus", testApp, beginRotation))
- .recordAllRuns()
- .runBeforeAll { AutomationUtils.wakeUpAndGoToHomeScreen() }
- .runBefore { device.pressHome() }
- .runBefore { setRotation(device, beginRotation) }
- .runBefore { testApp.open() }
- .run { testApp.openIME(device) }
- .runAfterAll { testApp.exit() }
- .repeat(ITERATIONS)
- }
-
- fun resizeSplitScreen(
- testAppTop: IAppHelper,
- testAppBottom: ImeAppHelper,
- instrumentation: Instrumentation,
- device: UiDevice,
- beginRotation: Int,
- startRatio: Rational,
- stopRatio: Rational
- ): TransitionRunner.TransitionBuilder {
- val description = (startRatio.toString().replace("/", "-") + "_to_" +
- stopRatio.toString().replace("/", "-"))
- val testTag = buildTestTag("resizeSplitScreen", testAppTop, beginRotation,
- beginRotation, testAppBottom, description)
- return TransitionRunner.TransitionBuilder(instrumentation)
- .withTag(testTag)
- .recordAllRuns()
- .runBeforeAll { AutomationUtils.wakeUpAndGoToHomeScreen() }
- .runBeforeAll { setRotation(device, beginRotation) }
- .runBeforeAll { AutomationUtils.clearRecents(instrumentation) }
- .runBefore { testAppBottom.open() }
- .runBefore { device.pressHome() }
- .runBefore { testAppTop.open() }
- .runBefore { device.waitForIdle() }
- .runBefore { AutomationUtils.launchSplitScreen(device) }
- .runBefore {
- val snapshot = device.findObject(
- By.res(device.launcherPackageName, "snapshot"))
- snapshot.click()
- }
- .runBefore { testAppBottom.openIME(device) }
- .runBefore { device.pressBack() }
- .runBefore { AutomationUtils.resizeSplitScreen(device, startRatio) }
- .run { AutomationUtils.resizeSplitScreen(device, stopRatio) }
- .runAfter { AutomationUtils.exitSplitScreen(device) }
- .runAfter { device.pressHome() }
- .runAfterAll { testAppTop.exit() }
- .runAfterAll { testAppBottom.exit() }
- .repeat(ITERATIONS)
- }
-
- fun editTextLoseFocusToHome(
- testApp: ImeAppHelper,
- instrumentation: Instrumentation,
- device: UiDevice,
- beginRotation: Int
- ): TransitionRunner.TransitionBuilder {
- return TransitionRunner.TransitionBuilder(instrumentation)
- .withTag(buildTestTag("editTextLoseFocusToHome", testApp, beginRotation))
- .recordAllRuns()
- .runBeforeAll { AutomationUtils.wakeUpAndGoToHomeScreen() }
- .runBefore { device.pressHome() }
- .runBefore { setRotation(device, beginRotation) }
- .runBefore { testApp.open() }
- .runBefore { testApp.openIME(device) }
- .run { device.pressHome() }
- .run { device.waitForIdle() }
- .runAfterAll { testApp.exit() }
- .repeat(ITERATIONS)
- }
-
- fun editTextLoseFocusToApp(
- testApp: ImeAppHelper,
- instrumentation: Instrumentation,
- device: UiDevice,
- beginRotation: Int
- ): TransitionRunner.TransitionBuilder {
- return TransitionRunner.TransitionBuilder(instrumentation)
- .withTag(buildTestTag("editTextLoseFocusToApp", testApp, beginRotation))
- .recordAllRuns()
- .runBeforeAll { AutomationUtils.wakeUpAndGoToHomeScreen() }
- .runBefore { device.pressHome() }
- .runBefore { setRotation(device, beginRotation) }
- .runBefore { testApp.open() }
- .runBefore { testApp.openIME(device) }
- .run { device.pressBack() }
- .run { device.waitForIdle() }
- .runAfterAll { testApp.exit() }
- .repeat(ITERATIONS)
- }
-
- fun enterPipMode(
- testApp: PipAppHelper,
- instrumentation: Instrumentation,
- device: UiDevice,
- beginRotation: Int
- ): TransitionRunner.TransitionBuilder {
- return TransitionRunner.TransitionBuilder(instrumentation)
- .withTag(buildTestTag("enterPipMode", testApp, beginRotation))
- .runBeforeAll { AutomationUtils.wakeUpAndGoToHomeScreen() }
- .runBefore { device.pressHome() }
- .runBefore { setRotation(device, beginRotation) }
- .runBefore { testApp.open() }
- .run { testApp.clickEnterPipButton(device) }
- .runAfter { testApp.closePipWindow(device) }
- .runAfterAll { testApp.exit() }
- .repeat(ITERATIONS)
- }
-
- fun exitPipModeToHome(
- testApp: PipAppHelper,
- instrumentation: Instrumentation,
- device: UiDevice,
- beginRotation: Int
- ): TransitionRunner.TransitionBuilder {
- return TransitionRunner.TransitionBuilder(instrumentation)
- .withTag(buildTestTag("exitPipModeToHome", testApp, beginRotation))
- .recordAllRuns()
- .runBeforeAll { AutomationUtils.wakeUpAndGoToHomeScreen() }
- .runBefore { device.pressHome() }
- .runBefore { setRotation(device, beginRotation) }
- .runBefore { testApp.open() }
- .run { testApp.clickEnterPipButton(device) }
- .run { testApp.closePipWindow(device) }
- .run { device.waitForIdle() }
- .run { testApp.exit() }
- .repeat(ITERATIONS)
- }
-
- fun exitPipModeToApp(
- testApp: PipAppHelper,
- instrumentation: Instrumentation,
- device: UiDevice,
- beginRotation: Int
- ): TransitionRunner.TransitionBuilder {
- return TransitionRunner.TransitionBuilder(instrumentation)
- .withTag(buildTestTag("exitPipModeToApp", testApp, beginRotation))
- .recordAllRuns()
- .runBeforeAll { AutomationUtils.wakeUpAndGoToHomeScreen() }
- .run { device.pressHome() }
- .run { setRotation(device, beginRotation) }
- .run { testApp.open() }
- .run { testApp.clickEnterPipButton(device) }
- .run { AutomationUtils.expandPipWindow(device) }
- .run { device.waitForIdle() }
- .run { testApp.exit() }
- .repeat(ITERATIONS)
- }
-} \ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/DebugTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/DebugTest.kt
deleted file mode 100644
index 43cfdffb6efb..000000000000
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/DebugTest.kt
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm.flicker
-
-import android.platform.helpers.IAppHelper
-import android.util.Rational
-import android.view.Surface
-import androidx.test.InstrumentationRegistry
-import androidx.test.filters.FlakyTest
-import androidx.test.filters.LargeTest
-import androidx.test.runner.AndroidJUnit4
-import androidx.test.uiautomator.UiDevice
-import com.android.server.wm.flicker.helpers.ImeAppHelper
-import com.android.server.wm.flicker.helpers.PipAppHelper
-import org.junit.FixMethodOrder
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-
-/**
- * Tests to help debug individual transitions, capture video recordings and create test cases.
- *
- * Not actual tests
- */
-@LargeTest
-@FlakyTest
-@RunWith(AndroidJUnit4::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class DebugTest {
- private val instrumentation = InstrumentationRegistry.getInstrumentation()
- private val testApp: IAppHelper = StandardAppHelper(instrumentation,
- "com.android.server.wm.flicker.testapp", "SimpleApp")
- private val uiDevice = UiDevice.getInstance(instrumentation)
-
- /**
- * atest FlickerTests:DebugTest#openAppCold
- */
- @Test
- fun openAppCold() {
- CommonTransitions.openAppCold(testApp, instrumentation, uiDevice, Surface.ROTATION_0)
- .recordAllRuns().build().run()
- }
-
- /**
- * atest FlickerTests:DebugTest#openAppWarm
- */
- @Test
- fun openAppWarm() {
- CommonTransitions.openAppWarm(testApp, instrumentation, uiDevice, Surface.ROTATION_0)
- .recordAllRuns().build().run()
- }
-
- /**
- * atest FlickerTests:DebugTest#changeOrientationFromNaturalToLeft
- */
- @Test
- fun changeOrientationFromNaturalToLeft() {
- CommonTransitions.changeAppRotation(testApp, instrumentation, uiDevice, Surface.ROTATION_0,
- Surface.ROTATION_270).recordAllRuns().build().run()
- }
-
- /**
- * atest FlickerTests:DebugTest#closeAppWithBackKey
- */
- @Test
- fun closeAppWithBackKey() {
- CommonTransitions.closeAppWithBackKey(testApp, instrumentation, uiDevice,
- Surface.ROTATION_0).recordAllRuns().build().run()
- }
-
- /**
- * atest FlickerTests:DebugTest#closeAppWithHomeKey
- */
- @Test
- fun closeAppWithHomeKey() {
- CommonTransitions.closeAppWithHomeKey(testApp, instrumentation, uiDevice,
- Surface.ROTATION_0).recordAllRuns().build().run()
- }
-
- /**
- * atest FlickerTests:DebugTest#openAppToSplitScreen
- */
- @Test
- fun openAppToSplitScreen() {
- CommonTransitions.appToSplitScreen(testApp, instrumentation, uiDevice,
- Surface.ROTATION_0).includeJankyRuns().recordAllRuns()
- .build().run()
- }
-
- /**
- * atest FlickerTests:DebugTest#splitScreenToLauncher
- */
- @Test
- fun splitScreenToLauncher() {
- CommonTransitions.splitScreenToLauncher(testApp, instrumentation, uiDevice,
- Surface.ROTATION_0).includeJankyRuns().recordAllRuns().build().run()
- }
-
- /**
- * atest FlickerTests:DebugTest#resizeSplitScreen
- */
- @Test
- fun resizeSplitScreen() {
- val bottomApp = ImeAppHelper(instrumentation)
- CommonTransitions.resizeSplitScreen(
- testApp,
- bottomApp,
- instrumentation,
- uiDevice,
- Surface.ROTATION_0,
- Rational(1, 3), Rational(2, 3)
- ).includeJankyRuns().build().run()
- }
- // IME tests
- /**
- * atest FlickerTests:DebugTest#editTextSetFocus
- */
- @Test
- fun editTextSetFocus() {
- val testApp = ImeAppHelper(instrumentation)
- CommonTransitions.editTextSetFocus(testApp, instrumentation, uiDevice, Surface.ROTATION_0)
- .includeJankyRuns()
- .build().run()
- }
-
- /**
- * atest FlickerTests:DebugTest#editTextLoseFocusToHome
- */
- @Test
- fun editTextLoseFocusToHome() {
- val testApp = ImeAppHelper(instrumentation)
- CommonTransitions.editTextLoseFocusToHome(testApp, instrumentation, uiDevice,
- Surface.ROTATION_0).includeJankyRuns().build().run()
- }
-
- /**
- * atest FlickerTests:DebugTest#editTextLoseFocusToApp
- */
- @Test
- fun editTextLoseFocusToApp() {
- val testApp = ImeAppHelper(instrumentation)
- CommonTransitions.editTextLoseFocusToHome(testApp, instrumentation, uiDevice,
- Surface.ROTATION_0).includeJankyRuns().build().run()
- }
- // PIP tests
- /**
- * atest FlickerTests:DebugTest#enterPipMode
- */
- @Test
- fun enterPipMode() {
- val testApp = PipAppHelper(instrumentation)
- CommonTransitions.enterPipMode(testApp, instrumentation, uiDevice, Surface.ROTATION_0)
- .includeJankyRuns().build().run()
- }
-
- /**
- * atest FlickerTests:DebugTest#exitPipModeToHome
- */
- @Test
- fun exitPipModeToHome() {
- val testApp = PipAppHelper(instrumentation)
- CommonTransitions.exitPipModeToHome(testApp, instrumentation, uiDevice, Surface.ROTATION_0)
- .includeJankyRuns()
- .build().run()
- }
-
- /**
- * atest FlickerTests:DebugTest#exitPipModeToApp
- */
- @Test
- fun exitPipModeToApp() {
- val testApp = PipAppHelper(instrumentation)
- CommonTransitions.exitPipModeToApp(testApp, instrumentation, uiDevice, Surface.ROTATION_0)
- .includeJankyRuns().build().run()
- }
-}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/FlickerTestBase.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/FlickerTestBase.kt
index d7586d0db915..eaf4d8799208 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/FlickerTestBase.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/FlickerTestBase.kt
@@ -16,15 +16,12 @@
package com.android.server.wm.flicker
+import android.os.RemoteException
+import android.os.SystemClock
import android.platform.helpers.IAppHelper
-import android.util.Log
-import androidx.test.InstrumentationRegistry
+import android.view.Surface
+import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.uiautomator.UiDevice
-import com.android.server.wm.flicker.helpers.AutomationUtils
-import com.google.common.truth.Truth
-import org.junit.After
-import org.junit.AfterClass
-import org.junit.Before
/**
* Base class of all Flicker test that performs common functions for all flicker tests:
@@ -37,101 +34,96 @@ import org.junit.Before
* - Fails tests if results are not available for any test due to jank.
*/
abstract class FlickerTestBase {
- lateinit var testApp: IAppHelper
- open val instrumentation by lazy {
+ val instrumentation by lazy {
InstrumentationRegistry.getInstrumentation()
}
val uiDevice by lazy {
UiDevice.getInstance(instrumentation)
}
- lateinit var tesults: List<TransitionResult>
- private var lastResult: TransitionResult? = null
/**
- * Runs a transition, returns a cached result if the transition has run before.
- */
- fun run(transition: TransitionRunner) {
- if (transitionResults.containsKey(transition.testTag)) {
- tesults = transitionResults[transition.testTag]
- ?: throw IllegalStateException("Results do not contain test tag " +
- transition.testTag)
- return
- }
- tesults = transition.run().results
- /* Fail if we don't have any results due to jank */
- Truth.assertWithMessage("No results to test because all transition runs were invalid " +
- "because of Jank").that(tesults).isNotEmpty()
- transitionResults[transition.testTag] = tesults
+ * Build a test tag for the test
+ * @param testName Name of the transition(s) being tested
+ * @param app App being launcher
+ * @param rotation Initial screen rotation
+ *
+ * @return test tag with pattern <NAME>__<APP>__<ROTATION>
+ </ROTATION></APP></NAME> */
+ protected fun buildTestTag(testName: String, app: IAppHelper, rotation: Int): String {
+ return buildTestTag(
+ testName, app, rotation, rotation, app2 = null, extraInfo = "")
}
/**
- * Runs a transition, returns a cached result if the transition has run before.
- */
- @Before
- fun runTransition() {
- run(transitionToRun)
+ * Build a test tag for the test
+ * @param testName Name of the transition(s) being tested
+ * @param app App being launcher
+ * @param beginRotation Initial screen rotation
+ * @param endRotation End screen rotation (if any, otherwise use same as initial)
+ *
+ * @return test tag with pattern <NAME>__<APP>__<BEGIN_ROTATION>-<END_ROTATION>
+ </END_ROTATION></BEGIN_ROTATION></APP></NAME> */
+ protected fun buildTestTag(
+ testName: String,
+ app: IAppHelper,
+ beginRotation: Int,
+ endRotation: Int
+ ): String {
+ return buildTestTag(
+ testName, app, beginRotation, endRotation, app2 = null, extraInfo = "")
}
/**
- * Gets the transition that will be executed
- */
- abstract val transitionToRun: TransitionRunner
-
- /**
- * Goes through a list of transition results and checks assertions on each result.
- */
- fun checkResults(assertion: (TransitionResult) -> Unit) {
- for (result in tesults) {
- lastResult = result
- assertion(result)
+ * Build a test tag for the test
+ * @param testName Name of the transition(s) being tested
+ * @param app App being launcher
+ * @param app2 Second app being launched (if any)
+ * @param beginRotation Initial screen rotation
+ * @param endRotation End screen rotation (if any, otherwise use same as initial)
+ * @param extraInfo Additional information to append to the tag
+ *
+ * @return test tag with pattern <NAME>__<APP></APP>(S)>__<ROTATION></ROTATION>(S)>[__<EXTRA>]
+ </EXTRA></NAME> */
+ protected fun buildTestTag(
+ testName: String,
+ app: IAppHelper,
+ beginRotation: Int,
+ endRotation: Int,
+ app2: IAppHelper?,
+ extraInfo: String
+ ): String {
+ var testTag = "${testName}__$${app.launcherName}"
+ if (app2 != null) {
+ testTag += "-${app2.launcherName}"
+ }
+ testTag += "__${Surface.rotationToString(beginRotation)}"
+ if (endRotation != beginRotation) {
+ testTag += "-${Surface.rotationToString(endRotation)}"
+ }
+ if (extraInfo.isNotEmpty()) {
+ testTag += "__$extraInfo"
}
- lastResult = null
+ return testTag
}
- /**
- * Kludge to mark a file for saving. If `checkResults` fails, the last result is not
- * cleared. This indicates the assertion failed for the result, so mark it for saving.
- */
- @After
- fun markArtifactsForSaving() {
- lastResult?.flagForSaving()
+ protected fun Flicker.setRotation(rotation: Int) {
+ try {
+ when (rotation) {
+ Surface.ROTATION_270 -> device.setOrientationLeft()
+ Surface.ROTATION_90 -> device.setOrientationRight()
+ Surface.ROTATION_0 -> device.setOrientationNatural()
+ else -> device.setOrientationNatural()
+ }
+ // Wait for animation to complete
+ SystemClock.sleep(1000)
+ } catch (e: RemoteException) {
+ throw RuntimeException(e)
+ }
}
companion object {
- const val TAG = "FLICKER"
const val NAVIGATION_BAR_WINDOW_TITLE = "NavigationBar"
const val STATUS_BAR_WINDOW_TITLE = "StatusBar"
const val DOCKED_STACK_DIVIDER = "DockedStackDivider"
- private val transitionResults = mutableMapOf<String, List<TransitionResult>>()
-
- /**
- * Teardown any system settings and clean up test artifacts from the file system.
- *
- * Note: test artifacts for failed tests will remain on the device.
- */
- @AfterClass
- @JvmStatic
- fun teardown() {
- AutomationUtils.setDefaultWait()
- transitionResults.values
- .flatten()
- .forEach {
- if (it.canDelete()) {
- it.delete()
- } else {
- if (it.layersTraceExists()) {
- Log.e(TAG, "Layers trace saved to ${it.layersTracePath}")
- }
- if (it.windowManagerTraceExists()) {
- Log.e(TAG,
- "WindowManager trace saved to ${it.windowManagerTracePath}")
- }
- if (it.screenCaptureVideoExists()) {
- Log.e(TAG,
- "Screen capture video saved to ${it.screenCaptureVideoPath()}")
- }
- }
- }
- }
}
-}
+} \ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/NonRotationTestBase.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/NonRotationTestBase.kt
index 1f8150c0977b..e7d1f8e94dba 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/NonRotationTestBase.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/NonRotationTestBase.kt
@@ -17,52 +17,20 @@
package com.android.server.wm.flicker
import android.view.Surface
-import androidx.test.filters.FlakyTest
-import org.junit.Test
import org.junit.runners.Parameterized
abstract class NonRotationTestBase(
- beginRotationName: String,
- protected val beginRotation: Int
+ protected val rotationName: String,
+ protected val rotation: Int
) : FlickerTestBase() {
- @FlakyTest(bugId = 141361128)
- @Test
- fun checkCoveredRegion_noUncoveredRegions() {
- val displayBounds = WindowUtils.getDisplayBounds(beginRotation)
- checkResults {
- LayersTraceSubject.assertThat(it).coversRegion(
- displayBounds).forAllEntries()
- }
- }
-
- @FlakyTest(bugId = 141361128)
- @Test
- fun checkVisibility_navBarLayerIsAlwaysVisible() {
- checkResults {
- LayersTraceSubject.assertThat(it)
- .showsLayer(NAVIGATION_BAR_WINDOW_TITLE).forAllEntries()
- }
- }
-
- @FlakyTest(bugId = 141361128)
- @Test
- fun checkVisibility_statusBarLayerIsAlwaysVisible() {
- checkResults {
- LayersTraceSubject.assertThat(it)
- .showsLayer(STATUS_BAR_WINDOW_TITLE).forAllEntries()
- }
- }
-
companion object {
+ const val SCREENSHOT_LAYER = "RotationLayer"
+
@Parameterized.Parameters(name = "{0}")
@JvmStatic
fun getParams(): Collection<Array<Any>> {
val supportedRotations = intArrayOf(Surface.ROTATION_0, Surface.ROTATION_90)
- val params: MutableCollection<Array<Any>> = ArrayList()
- for (begin in supportedRotations) {
- params.add(arrayOf(Surface.rotationToString(begin), begin))
- }
- return params
+ return supportedRotations.map { arrayOf(Surface.rotationToString(it), it) }
}
}
-}
+} \ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/RotationTestBase.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/RotationTestBase.kt
index dfc3c07d5417..3b6772779029 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/RotationTestBase.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/RotationTestBase.kt
@@ -17,8 +17,6 @@
package com.android.server.wm.flicker
import android.view.Surface
-import androidx.test.filters.FlakyTest
-import org.junit.Test
import org.junit.runners.Parameterized
abstract class RotationTestBase(
@@ -27,82 +25,7 @@ abstract class RotationTestBase(
protected val beginRotation: Int,
protected val endRotation: Int
) : FlickerTestBase() {
- @FlakyTest(bugId = 140855415)
- @Test
- fun checkVisibility_navBarWindowIsAlwaysVisible() {
- checkResults {
- WmTraceSubject.assertThat(it)
- .showsAboveAppWindow(NAVIGATION_BAR_WINDOW_TITLE).forAllEntries()
- }
- }
-
- @FlakyTest(bugId = 140855415)
- @Test
- fun checkVisibility_statusBarWindowIsAlwaysVisible() {
- checkResults {
- WmTraceSubject.assertThat(it)
- .showsAboveAppWindow(STATUS_BAR_WINDOW_TITLE).forAllEntries()
- }
- }
-
- @Test
- fun checkPosition_navBarLayerRotatesAndScales() {
- val startingPos = WindowUtils.getNavigationBarPosition(beginRotation)
- val endingPos = WindowUtils.getNavigationBarPosition(endRotation)
- if (startingPos == endingPos) {
- checkResults {
- LayersTraceSubject.assertThat(it)
- .hasVisibleRegion(NAVIGATION_BAR_WINDOW_TITLE, startingPos)
- .forAllEntries()
- }
- } else {
- checkResults {
- LayersTraceSubject.assertThat(it)
- .hasVisibleRegion(NAVIGATION_BAR_WINDOW_TITLE, startingPos)
- .inTheBeginning()
- }
- checkResults {
- LayersTraceSubject.assertThat(it)
- .hasVisibleRegion(NAVIGATION_BAR_WINDOW_TITLE, endingPos)
- .atTheEnd()
- }
- }
- }
-
- @Test
- fun checkPosition_statusBarLayerRotatesScales() {
- val startingPos = WindowUtils.getStatusBarPosition(beginRotation)
- val endingPos = WindowUtils.getStatusBarPosition(endRotation)
- checkResults {
- LayersTraceSubject.assertThat(it)
- .hasVisibleRegion(STATUS_BAR_WINDOW_TITLE, startingPos)
- .inTheBeginning()
- LayersTraceSubject.assertThat(it)
- .hasVisibleRegion(STATUS_BAR_WINDOW_TITLE, endingPos).atTheEnd()
- }
- }
-
- @FlakyTest(bugId = 140855415)
- @Test
- fun checkVisibility_navBarLayerIsAlwaysVisible() {
- checkResults {
- LayersTraceSubject.assertThat(it)
- .showsLayer(NAVIGATION_BAR_WINDOW_TITLE).forAllEntries()
- }
- }
-
- @FlakyTest(bugId = 140855415)
- @Test
- fun checkVisibility_statusBarLayerIsAlwaysVisible() {
- checkResults {
- LayersTraceSubject.assertThat(it)
- .showsLayer(STATUS_BAR_WINDOW_TITLE).forAllEntries()
- }
- }
-
companion object {
- const val SCREENSHOT_LAYER = "RotationLayer"
-
@Parameterized.Parameters(name = "{0}-{1}")
@JvmStatic
fun getParams(): Collection<Array<Any>> {
@@ -123,4 +46,4 @@ abstract class RotationTestBase(
return params
}
}
-}
+} \ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/FlickerAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/FlickerAppHelper.kt
index e579533d2bb7..71475774343a 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/FlickerAppHelper.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/FlickerAppHelper.kt
@@ -17,14 +17,15 @@
package com.android.server.wm.flicker.helpers
import android.app.Instrumentation
+import android.support.test.launcherhelper.ILauncherStrategy
import com.android.server.wm.flicker.StandardAppHelper
abstract class FlickerAppHelper(
instr: Instrumentation,
- launcherName: String
-) : StandardAppHelper(instr, sFlickerPackage, launcherName) {
+ launcherName: String,
+ launcherStrategy: ILauncherStrategy
+) : StandardAppHelper(instr, sFlickerPackage, launcherName, launcherStrategy) {
companion object {
- var sFindTimeout = 10000
var sFlickerPackage = "com.android.server.wm.flicker.testapp"
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppHelper.kt
index 979cbeaca539..c1b765790ce5 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppHelper.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppHelper.kt
@@ -17,6 +17,8 @@
package com.android.server.wm.flicker.helpers
import android.app.Instrumentation
+import android.support.test.launcherhelper.ILauncherStrategy
+import android.support.test.launcherhelper.LauncherStrategyFactory
import androidx.test.uiautomator.By
import androidx.test.uiautomator.UiDevice
import androidx.test.uiautomator.Until
@@ -24,17 +26,26 @@ import org.junit.Assert
open class ImeAppHelper(
instr: Instrumentation,
- launcherName: String = "ImeApp"
-) : FlickerAppHelper(instr, launcherName) {
+ launcherName: String = "ImeApp",
+ launcherStrategy: ILauncherStrategy = LauncherStrategyFactory
+ .getInstance(instr)
+ .launcherStrategy
+) : FlickerAppHelper(instr, launcherName, launcherStrategy) {
open fun openIME(device: UiDevice) {
val editText = device.wait(
Until.findObject(By.res(getPackage(), "plain_text_input")),
- AutomationUtils.FIND_TIMEOUT)
+ FIND_TIMEOUT)
Assert.assertNotNull("Text field not found, this usually happens when the device " +
"was left in an unknown state (e.g. in split screen)", editText)
editText.click()
- if (!AutomationUtils.waitForIME(device)) {
+ if (!device.waitForIME()) {
Assert.fail("IME did not appear")
}
}
+
+ open fun closeIME(device: UiDevice) {
+ device.pressBack()
+ // Using only the AccessibilityInfo it is not possible to identify if the IME is active
+ device.waitForIdle(1000)
+ }
} \ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt
index daee810b6899..d10bb1ef3ee7 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt
@@ -17,20 +17,27 @@
package com.android.server.wm.flicker.helpers
import android.app.Instrumentation
+import android.support.test.launcherhelper.ILauncherStrategy
+import android.support.test.launcherhelper.LauncherStrategyFactory
import androidx.test.uiautomator.By
import androidx.test.uiautomator.UiDevice
import org.junit.Assert
-class PipAppHelper(instr: Instrumentation) : FlickerAppHelper(instr, "PipApp") {
+class PipAppHelper(
+ instr: Instrumentation,
+ launcherStrategy: ILauncherStrategy = LauncherStrategyFactory
+ .getInstance(instr)
+ .launcherStrategy
+) : FlickerAppHelper(instr, "PipApp", launcherStrategy) {
fun clickEnterPipButton(device: UiDevice) {
val enterPipButton = device.findObject(By.res(getPackage(), "enter_pip"))
Assert.assertNotNull("Pip button not found, this usually happens when the device " +
"was left in an unknown state (e.g. in split screen)", enterPipButton)
enterPipButton.click()
- AutomationUtils.hasPipWindow(device)
+ device.hasPipWindow()
}
fun closePipWindow(device: UiDevice) {
- AutomationUtils.closePipWindow(device)
+ device.closePipWindow()
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt
index 814cdcf5e114..80d039475fab 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt
@@ -16,11 +16,19 @@
package com.android.server.wm.flicker.ime
-import androidx.test.filters.FlakyTest
+import android.view.Surface
import androidx.test.filters.LargeTest
-import com.android.server.wm.flicker.CommonTransitions
-import com.android.server.wm.flicker.TransitionRunner
+import com.android.server.wm.flicker.dsl.flicker
import com.android.server.wm.flicker.helpers.ImeAppAutoFocusHelper
+import com.android.server.wm.flicker.helpers.ImeAppHelper
+import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
+import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.navBarLayerRotatesAndScales
+import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.noUncoveredRegions
+import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarLayerRotatesScales
+import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -35,33 +43,52 @@ import org.junit.runners.Parameterized
@RunWith(Parameterized::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
class CloseImeAutoOpenWindowToAppTest(
- beginRotationName: String,
- beginRotation: Int
-) : CloseImeWindowToAppTest(beginRotationName, beginRotation) {
- init {
- testApp = ImeAppAutoFocusHelper(instrumentation)
- }
-
- override val transitionToRun: TransitionRunner
- get() = CommonTransitions.editTextLoseFocusToApp(testApp as ImeAppAutoFocusHelper,
- instrumentation, uiDevice, beginRotation)
- .includeJankyRuns().build()
+ rotationName: String,
+ rotation: Int
+) : CloseImeWindowToAppTest(rotationName, rotation) {
+ override val testApp: ImeAppHelper
+ get() = ImeAppAutoFocusHelper(instrumentation)
- @FlakyTest(bugId = 141458352)
@Test
- override fun checkVisibility_imeLayerBecomesInvisible() {
- super.checkVisibility_imeLayerBecomesInvisible()
- }
+ override fun test() {
+ flicker(instrumentation) {
+ withTag { buildTestTag("imeToAppAutoOpen", testApp, rotation) }
+ repeat { 1 }
+ setup {
+ eachRun {
+ device.wakeUpAndGoToHomeScreen()
+ this.setRotation(rotation)
+ testApp.open()
+ testApp.openIME(device)
+ }
+ }
+ teardown {
+ eachRun {
+ testApp.exit()
+ this.setRotation(Surface.ROTATION_0)
+ }
+ }
+ transitions {
+ device.pressBack()
+ device.waitForIdle()
+ }
+ assertions {
+ windowManagerTrace {
+ navBarWindowIsAlwaysVisible()
+ statusBarWindowIsAlwaysVisible()
+ imeAppWindowIsAlwaysVisible(testApp, bugId = 141458352)
+ }
- @FlakyTest(bugId = 141458352)
- @Test
- override fun checkVisibility_imeAppLayerIsAlwaysVisible() {
- super.checkVisibility_imeAppLayerIsAlwaysVisible()
- }
-
- @FlakyTest(bugId = 141458352)
- @Test
- override fun checkVisibility_imeAppWindowIsAlwaysVisible() {
- super.checkVisibility_imeAppWindowIsAlwaysVisible()
+ layersTrace {
+ navBarLayerIsAlwaysVisible()
+ statusBarLayerIsAlwaysVisible()
+ noUncoveredRegions(rotation)
+ navBarLayerRotatesAndScales(rotation)
+ statusBarLayerRotatesScales(rotation)
+ imeLayerBecomesInvisible(bugId = 141458352)
+ imeAppLayerIsAlwaysVisible(testApp, bugId = 141458352)
+ }
+ }
+ }
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt
index c2025b6da204..31d1fd313374 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt
@@ -16,11 +16,19 @@
package com.android.server.wm.flicker.ime
-import androidx.test.filters.FlakyTest
+import android.view.Surface
import androidx.test.filters.LargeTest
-import com.android.server.wm.flicker.CommonTransitions
-import com.android.server.wm.flicker.TransitionRunner
+import com.android.server.wm.flicker.dsl.flicker
import com.android.server.wm.flicker.helpers.ImeAppAutoFocusHelper
+import com.android.server.wm.flicker.helpers.ImeAppHelper
+import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
+import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.navBarLayerRotatesAndScales
+import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.noUncoveredRegions
+import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarLayerRotatesScales
+import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -35,33 +43,53 @@ import org.junit.runners.Parameterized
@RunWith(Parameterized::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
class CloseImeAutoOpenWindowToHomeTest(
- beginRotationName: String,
- beginRotation: Int
-) : CloseImeWindowToHomeTest(beginRotationName, beginRotation) {
- init {
- testApp = ImeAppAutoFocusHelper(instrumentation)
- }
-
- override val transitionToRun: TransitionRunner
- get() = CommonTransitions.editTextLoseFocusToHome(testApp as ImeAppAutoFocusHelper,
- instrumentation, uiDevice, beginRotation)
- .includeJankyRuns().build()
+ rotationName: String,
+ rotation: Int
+) : CloseImeWindowToHomeTest(rotationName, rotation) {
+ override val testApp: ImeAppHelper
+ get() = ImeAppAutoFocusHelper(instrumentation)
- @FlakyTest(bugId = 141458352)
@Test
- override fun checkVisibility_imeWindowBecomesInvisible() {
- super.checkVisibility_imeWindowBecomesInvisible()
- }
+ override fun test() {
+ flicker(instrumentation) {
+ withTag { buildTestTag("imeToHomeAutoOpen", testApp, rotation) }
+ repeat { 1 }
+ setup {
+ eachRun {
+ device.wakeUpAndGoToHomeScreen()
+ this.setRotation(rotation)
+ testApp.open()
+ testApp.openIME(device)
+ }
+ }
+ teardown {
+ eachRun {
+ testApp.exit()
+ this.setRotation(Surface.ROTATION_0)
+ }
+ }
+ transitions {
+ device.pressHome()
+ device.waitForIdle()
+ }
+ assertions {
+ windowManagerTrace {
+ navBarWindowIsAlwaysVisible()
+ statusBarWindowIsAlwaysVisible()
+ imeWindowBecomesInvisible(bugId = 141458352)
+ imeAppWindowBecomesInvisible(testApp, bugId = 157449248)
+ }
- @FlakyTest(bugId = 141458352)
- @Test
- override fun checkVisibility_imeLayerBecomesInvisible() {
- super.checkVisibility_imeLayerBecomesInvisible()
- }
-
- @FlakyTest(bugId = 157449248)
- @Test
- override fun checkVisibility_imeAppWindowBecomesInvisible() {
- super.checkVisibility_imeAppWindowBecomesInvisible()
+ layersTrace {
+ navBarLayerIsAlwaysVisible()
+ statusBarLayerIsAlwaysVisible()
+ noUncoveredRegions(rotation)
+ navBarLayerRotatesAndScales(rotation)
+ statusBarLayerRotatesScales(rotation)
+ imeLayerBecomesInvisible(bugId = 141458352)
+ imeAppLayerBecomesInvisible(testApp, bugId = 153739621)
+ }
+ }
+ }
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt
index b38262e9f298..67c46d3f4722 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt
@@ -16,14 +16,19 @@
package com.android.server.wm.flicker.ime
-import androidx.test.filters.FlakyTest
+import android.view.Surface
import androidx.test.filters.LargeTest
-import com.android.server.wm.flicker.CommonTransitions
-import com.android.server.wm.flicker.LayersTraceSubject
import com.android.server.wm.flicker.NonRotationTestBase
-import com.android.server.wm.flicker.TransitionRunner
-import com.android.server.wm.flicker.WmTraceSubject
+import com.android.server.wm.flicker.dsl.flicker
import com.android.server.wm.flicker.helpers.ImeAppHelper
+import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
+import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.navBarLayerRotatesAndScales
+import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.noUncoveredRegions
+import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarLayerRotatesScales
+import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -38,49 +43,51 @@ import org.junit.runners.Parameterized
@RunWith(Parameterized::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
open class CloseImeWindowToAppTest(
- beginRotationName: String,
- beginRotation: Int
-) : NonRotationTestBase(beginRotationName, beginRotation) {
- init {
- testApp = ImeAppHelper(instrumentation)
- }
-
- override val transitionToRun: TransitionRunner
- get() = CommonTransitions.editTextLoseFocusToApp(testApp as ImeAppHelper,
- instrumentation, uiDevice, beginRotation)
- .includeJankyRuns().build()
+ rotationName: String,
+ rotation: Int
+) : NonRotationTestBase(rotationName, rotation) {
+ open val testApp = ImeAppHelper(instrumentation)
- @FlakyTest
@Test
- open fun checkVisibility_imeLayerBecomesInvisible() {
- checkResults {
- LayersTraceSubject.assertThat(it)
- .showsLayer(IME_WINDOW_TITLE)
- .then()
- .hidesLayer(IME_WINDOW_TITLE)
- .forAllEntries()
- }
- }
+ open fun test() {
+ flicker(instrumentation) {
+ withTag { buildTestTag("imeToApp", testApp, rotation) }
+ repeat { 1 }
+ setup {
+ eachRun {
+ device.wakeUpAndGoToHomeScreen()
+ this.setRotation(rotation)
+ testApp.open()
+ testApp.openIME(device)
+ }
+ }
+ teardown {
+ eachRun {
+ testApp.exit()
+ this.setRotation(Surface.ROTATION_0)
+ }
+ }
+ transitions {
+ device.pressBack()
+ device.waitForIdle()
+ }
+ assertions {
+ windowManagerTrace {
+ navBarWindowIsAlwaysVisible()
+ statusBarWindowIsAlwaysVisible()
+ imeAppWindowIsAlwaysVisible(testApp)
+ }
- @Test
- open fun checkVisibility_imeAppLayerIsAlwaysVisible() {
- checkResults {
- LayersTraceSubject.assertThat(it)
- .showsLayer(testApp.getPackage())
- .forAllEntries()
+ layersTrace {
+ navBarLayerIsAlwaysVisible()
+ statusBarLayerIsAlwaysVisible()
+ noUncoveredRegions(rotation)
+ navBarLayerRotatesAndScales(rotation)
+ statusBarLayerRotatesScales(rotation)
+ imeLayerBecomesInvisible(enabled = false)
+ imeAppLayerIsAlwaysVisible(testApp)
+ }
+ }
}
}
-
- @Test
- open fun checkVisibility_imeAppWindowIsAlwaysVisible() {
- checkResults {
- WmTraceSubject.assertThat(it)
- .showsAppWindowOnTop(testApp.getPackage())
- .forAllEntries()
- }
- }
-
- companion object {
- const val IME_WINDOW_TITLE = "InputMethod"
- }
-}
+} \ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt
index ca04babfa0f1..b643ec2ba332 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt
@@ -16,20 +16,26 @@
package com.android.server.wm.flicker.ime
-import androidx.test.filters.FlakyTest
+import android.view.Surface
import androidx.test.filters.LargeTest
-import com.android.server.wm.flicker.CommonTransitions
-import com.android.server.wm.flicker.LayersTraceSubject
import com.android.server.wm.flicker.NonRotationTestBase
-import com.android.server.wm.flicker.TransitionRunner
-import com.android.server.wm.flicker.WmTraceSubject
+import com.android.server.wm.flicker.dsl.flicker
import com.android.server.wm.flicker.helpers.ImeAppHelper
+import com.android.server.wm.flicker.helpers.openQuickstep
+import com.android.server.wm.flicker.helpers.reopenAppFromOverview
+import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
+import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.navBarLayerRotatesAndScales
+import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.noUncoveredRegions
+import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarLayerRotatesScales
+import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
-
/**
* Test IME window closing to home transitions.
* To run this test: `atest FlickerTests:CloseImeWindowToHomeTest`
@@ -38,67 +44,60 @@ import org.junit.runners.Parameterized
@RunWith(Parameterized::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
open class CloseImeWindowToHomeTest(
- beginRotationName: String,
- beginRotation: Int
-) : NonRotationTestBase(beginRotationName, beginRotation) {
- init {
- testApp = ImeAppHelper(instrumentation)
- }
-
- override val transitionToRun: TransitionRunner
- get() = CommonTransitions.editTextLoseFocusToHome(testApp as ImeAppHelper,
- instrumentation, uiDevice, beginRotation)
- .includeJankyRuns().build()
-
- @Test
- open fun checkVisibility_imeWindowBecomesInvisible() {
- checkResults {
- WmTraceSubject.assertThat(it)
- .showsNonAppWindow(IME_WINDOW_TITLE)
- .then()
- .hidesNonAppWindow(IME_WINDOW_TITLE)
- .forAllEntries()
- }
- }
-
- @FlakyTest(bugId = 153739621)
- @Test
- open fun checkVisibility_imeLayerBecomesInvisible() {
- checkResults {
- LayersTraceSubject.assertThat(it)
- .skipUntilFirstAssertion()
- .showsLayer(IME_WINDOW_TITLE)
- .then()
- .hidesLayer(IME_WINDOW_TITLE)
- .forAllEntries()
- }
- }
+ rotationName: String,
+ rotation: Int
+) : NonRotationTestBase(rotationName, rotation) {
+ open val testApp = ImeAppHelper(instrumentation)
- @FlakyTest(bugId = 153739621)
@Test
- fun checkVisibility_imeAppLayerBecomesInvisible() {
- checkResults {
- LayersTraceSubject.assertThat(it)
- .skipUntilFirstAssertion()
- .showsLayer(testApp.getPackage())
- .then()
- .hidesLayer(testApp.getPackage())
- .forAllEntries()
- }
- }
+ open fun test() {
+ flicker(instrumentation) {
+ withTag { buildTestTag("imeToHome", testApp, rotation) }
+ repeat { 1 }
+ setup {
+ test {
+ device.wakeUpAndGoToHomeScreen()
+ this.setRotation(rotation)
+ testApp.open()
+ }
+ eachRun {
+ device.openQuickstep()
+ device.reopenAppFromOverview()
+ this.setRotation(rotation)
+ testApp.openIME(device)
+ }
+ }
+ transitions {
+ device.pressHome()
+ device.waitForIdle()
+ }
+ teardown {
+ eachRun {
+ device.pressHome()
+ }
+ test {
+ testApp.exit()
+ this.setRotation(Surface.ROTATION_0)
+ }
+ }
+ assertions {
+ windowManagerTrace {
+ navBarWindowIsAlwaysVisible()
+ statusBarWindowIsAlwaysVisible()
+ imeWindowBecomesInvisible()
+ imeAppWindowBecomesInvisible(testApp)
+ }
- @Test
- open fun checkVisibility_imeAppWindowBecomesInvisible() {
- checkResults {
- WmTraceSubject.assertThat(it)
- .showsAppWindowOnTop(testApp.getPackage())
- .then()
- .appWindowNotOnTop(testApp.getPackage())
- .forAllEntries()
+ layersTrace {
+ navBarLayerIsAlwaysVisible()
+ statusBarLayerIsAlwaysVisible()
+ noUncoveredRegions(rotation)
+ navBarLayerRotatesAndScales(rotation, Surface.ROTATION_0)
+ statusBarLayerRotatesScales(rotation, Surface.ROTATION_0)
+ imeLayerBecomesInvisible(bugId = 153739621)
+ imeAppLayerBecomesInvisible(testApp, bugId = 153739621)
+ }
+ }
}
}
-
- companion object {
- const val IME_WINDOW_TITLE: String = "InputMethod"
- }
-}
+} \ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ImeAssertions.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ImeAssertions.kt
new file mode 100644
index 000000000000..b2be54fe068a
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ImeAssertions.kt
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.ime
+
+import android.platform.helpers.IAppHelper
+import com.android.server.wm.flicker.dsl.LayersAssertion
+import com.android.server.wm.flicker.dsl.WmAssertion
+
+const val IME_WINDOW_TITLE = "InputMethod"
+
+@JvmOverloads
+fun LayersAssertion.imeLayerBecomesVisible(
+ bugId: Int = 0,
+ enabled: Boolean = bugId == 0
+) {
+ all("imeLayerBecomesVisible", enabled, bugId) {
+ this.hidesLayer(IME_WINDOW_TITLE)
+ .then()
+ .showsLayer(IME_WINDOW_TITLE)
+ }
+}
+
+fun LayersAssertion.imeLayerBecomesInvisible(
+ bugId: Int = 0,
+ enabled: Boolean = bugId == 0
+) {
+ all("imeLayerBecomesInvisible", enabled, bugId) {
+ this.showsLayer(IME_WINDOW_TITLE)
+ .then()
+ .hidesLayer(IME_WINDOW_TITLE)
+ }
+}
+
+fun LayersAssertion.imeAppLayerIsAlwaysVisible(
+ testApp: IAppHelper,
+ bugId: Int = 0,
+ enabled: Boolean = bugId == 0
+) {
+ all("imeAppLayerIsAlwaysVisible", enabled, bugId) {
+ this.showsLayer(testApp.getPackage())
+ }
+}
+
+fun WmAssertion.imeAppWindowIsAlwaysVisible(
+ testApp: IAppHelper,
+ bugId: Int = 0,
+ enabled: Boolean = bugId == 0
+) {
+ all("imeAppWindowIsAlwaysVisible", enabled, bugId) {
+ this.showsAppWindowOnTop(testApp.getPackage())
+ }
+}
+
+fun WmAssertion.imeWindowBecomesInvisible(
+ bugId: Int = 0,
+ enabled: Boolean = bugId == 0
+) {
+ all("imeWindowBecomesInvisible", enabled, bugId) {
+ this.showsNonAppWindow(IME_WINDOW_TITLE)
+ .then()
+ .hidesNonAppWindow(IME_WINDOW_TITLE)
+ }
+}
+
+fun WmAssertion.imeAppWindowBecomesInvisible(
+ testApp: IAppHelper,
+ bugId: Int = 0,
+ enabled: Boolean = bugId == 0
+) {
+ all("imeAppWindowBecomesInvisible", enabled, bugId) {
+ this.showsAppWindowOnTop(testApp.getPackage())
+ .then()
+ .appWindowNotOnTop(testApp.getPackage())
+ }
+}
+
+fun LayersAssertion.imeAppLayerBecomesInvisible(
+ testApp: IAppHelper,
+ bugId: Int = 0,
+ enabled: Boolean = bugId == 0
+) {
+ all("imeAppLayerBecomesInvisible", enabled, bugId) {
+ this.skipUntilFirstAssertion()
+ .showsLayer(testApp.getPackage())
+ .then()
+ .hidesLayer(testApp.getPackage())
+ }
+} \ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt
index c7731f330aeb..5874a0736d85 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt
@@ -16,13 +16,19 @@
package com.android.server.wm.flicker.ime
+import android.view.Surface
import androidx.test.filters.LargeTest
-import com.android.server.wm.flicker.CommonTransitions
-import com.android.server.wm.flicker.LayersTraceSubject
import com.android.server.wm.flicker.NonRotationTestBase
-import com.android.server.wm.flicker.TransitionRunner
-import com.android.server.wm.flicker.WmTraceSubject
+import com.android.server.wm.flicker.dsl.flicker
import com.android.server.wm.flicker.helpers.ImeAppHelper
+import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
+import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.navBarLayerRotatesAndScales
+import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.noUncoveredRegions
+import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarLayerRotatesScales
+import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -37,38 +43,58 @@ import org.junit.runners.Parameterized
@RunWith(Parameterized::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
class OpenImeWindowTest(
- beginRotationName: String,
- beginRotation: Int
-) : NonRotationTestBase(beginRotationName, beginRotation) {
- init {
- testApp = ImeAppHelper(instrumentation)
- }
+ rotationName: String,
+ rotation: Int
+) : NonRotationTestBase(rotationName, rotation) {
+ @Test
+ fun test() {
+ val testApp = ImeAppHelper(instrumentation)
- override val transitionToRun: TransitionRunner
- get() = CommonTransitions.editTextSetFocus(testApp as ImeAppHelper,
- instrumentation, uiDevice, beginRotation)
- .includeJankyRuns().build()
+ flicker(instrumentation) {
+ withTag { buildTestTag("openIme", testApp, rotation) }
+ repeat { 1 }
+ setup {
+ test {
+ device.wakeUpAndGoToHomeScreen()
+ this.setRotation(rotation)
+ testApp.open()
+ }
+ }
+ transitions {
+ testApp.openIME(device)
+ }
+ teardown {
+ eachRun {
+ testApp.closeIME(device)
+ }
+ test {
+ testApp.exit()
+ this.setRotation(Surface.ROTATION_0)
+ }
+ }
+ assertions {
+ windowManagerTrace {
+ navBarWindowIsAlwaysVisible()
+ statusBarWindowIsAlwaysVisible()
- @Test
- fun checkVisibility_imeWindowBecomesVisible() {
- checkResults {
- WmTraceSubject.assertThat(it)
- .skipUntilFirstAssertion()
- .hidesNonAppWindow(IME_WINDOW_TITLE)
- .then()
- .showsNonAppWindow(IME_WINDOW_TITLE)
- .forAllEntries()
- }
- }
+ all("imeWindowBecomesVisible") {
+ this.skipUntilFirstAssertion()
+ .hidesNonAppWindow(IME_WINDOW_TITLE)
+ .then()
+ .showsNonAppWindow(IME_WINDOW_TITLE)
+ }
+ }
- @Test
- fun checkVisibility_imeLayerBecomesVisible() {
- checkResults {
- LayersTraceSubject.assertThat(it)
- .hidesLayer(IME_WINDOW_TITLE)
- .then()
- .showsLayer(IME_WINDOW_TITLE)
- .forAllEntries()
+ layersTrace {
+ navBarLayerIsAlwaysVisible()
+ statusBarLayerIsAlwaysVisible()
+ noUncoveredRegions(rotation)
+ navBarLayerRotatesAndScales(rotation)
+ statusBarLayerRotatesScales(rotation)
+
+ imeLayerBecomesVisible()
+ }
+ }
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt
index 88b885407935..af751dc71f6c 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt
@@ -16,14 +16,18 @@
package com.android.server.wm.flicker.launch
-import androidx.test.filters.FlakyTest
+import android.view.Surface
import androidx.test.filters.LargeTest
-import com.android.server.wm.flicker.CommonTransitions
-import com.android.server.wm.flicker.LayersTraceSubject
-import com.android.server.wm.flicker.NonRotationTestBase
-import com.android.server.wm.flicker.StandardAppHelper
-import com.android.server.wm.flicker.TransitionRunner
-import com.android.server.wm.flicker.WmTraceSubject
+import com.android.server.wm.flicker.dsl.flicker
+import com.android.server.wm.flicker.focusChanges
+import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
+import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.navBarLayerRotatesAndScales
+import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.noUncoveredRegions
+import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarLayerRotatesScales
+import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -38,50 +42,53 @@ import org.junit.runners.Parameterized
@RunWith(Parameterized::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
class OpenAppColdTest(
- beginRotationName: String,
- beginRotation: Int
-) : NonRotationTestBase(beginRotationName, beginRotation) {
- init {
- testApp = StandardAppHelper(instrumentation,
- "com.android.server.wm.flicker.testapp", "SimpleApp")
- }
-
- override val transitionToRun: TransitionRunner
- get() = CommonTransitions.openAppCold(testApp, instrumentation, uiDevice, beginRotation)
- .includeJankyRuns().build()
-
+ rotationName: String,
+ rotation: Int
+) : OpenAppTestBase(rotationName, rotation) {
@Test
- fun checkVisibility_wallpaperWindowBecomesInvisible() {
- checkResults {
- WmTraceSubject.assertThat(it)
- .showsBelowAppWindow("Wallpaper")
- .then()
- .hidesBelowAppWindow("Wallpaper")
- .forAllEntries()
- }
- }
+ fun test() {
+ flicker(instrumentation) {
+ withTag { buildTestTag("openAppCold", testApp, rotation) }
+ repeat { 1 }
+ setup {
+ test {
+ device.wakeUpAndGoToHomeScreen()
+ }
+ eachRun {
+ this.setRotation(rotation)
+ }
+ }
+ transitions {
+ testApp.open()
+ }
+ teardown {
+ eachRun {
+ testApp.exit()
+ this.setRotation(Surface.ROTATION_0)
+ }
+ }
+ assertions {
+ windowManagerTrace {
+ navBarWindowIsAlwaysVisible()
+ statusBarWindowIsAlwaysVisible()
+ appWindowReplacesLauncherAsTopWindow(bugId = 141361128)
+ wallpaperWindowBecomesInvisible()
+ }
- @FlakyTest(bugId = 140855415)
- @Test
- fun checkZOrder_appWindowReplacesLauncherAsTopWindow() {
- checkResults {
- WmTraceSubject.assertThat(it)
- .showsAppWindowOnTop(
- "com.android.launcher3/.Launcher")
- .then()
- .showsAppWindowOnTop(testApp.getPackage())
- .forAllEntries()
- }
- }
+ layersTrace {
+ noUncoveredRegions(rotation, bugId = 141361128)
+ // During testing the launcher is always in portrait mode
+ navBarLayerRotatesAndScales(Surface.ROTATION_0, rotation)
+ statusBarLayerRotatesScales(Surface.ROTATION_0, rotation)
+ navBarLayerIsAlwaysVisible(bugId = 141361128)
+ statusBarLayerIsAlwaysVisible(bugId = 141361128)
+ wallpaperLayerBecomesInvisible(bugId = 141361128)
+ }
- @Test
- fun checkVisibility_wallpaperLayerBecomesInvisible() {
- checkResults {
- LayersTraceSubject.assertThat(it)
- .showsLayer("Wallpaper")
- .then()
- .replaceVisibleLayer("Wallpaper", testApp.getPackage())
- .forAllEntries()
+ eventLog {
+ focusChanges("NexusLauncherActivity", testApp.`package`)
+ }
+ }
}
}
} \ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTestBase.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTestBase.kt
new file mode 100644
index 000000000000..3cec077f0184
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTestBase.kt
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.launch
+
+import com.android.server.wm.flicker.NonRotationTestBase
+import com.android.server.wm.flicker.StandardAppHelper
+import com.android.server.wm.flicker.dsl.LayersAssertion
+import com.android.server.wm.flicker.dsl.WmAssertion
+
+abstract class OpenAppTestBase(
+ rotationName: String,
+ rotation: Int
+) : NonRotationTestBase(rotationName, rotation) {
+ protected val testApp = StandardAppHelper(instrumentation,
+ "com.android.server.wm.flicker.testapp", "SimpleApp")
+
+ protected fun WmAssertion.wallpaperWindowBecomesInvisible(
+ bugId: Int = 0,
+ enabled: Boolean = bugId == 0
+ ) {
+ all("wallpaperWindowBecomesInvisible", enabled, bugId) {
+ this.showsBelowAppWindow("Wallpaper")
+ .then()
+ .hidesBelowAppWindow("Wallpaper")
+ }
+ }
+
+ protected fun WmAssertion.appWindowReplacesLauncherAsTopWindow(
+ bugId: Int = 0,
+ enabled: Boolean = bugId == 0
+ ) {
+ all("appWindowReplacesLauncherAsTopWindow", enabled, bugId) {
+ this.showsAppWindowOnTop(
+ "Launcher")
+ .then()
+ .showsAppWindowOnTop(testApp.getPackage())
+ }
+ }
+
+ protected fun LayersAssertion.wallpaperLayerBecomesInvisible(
+ bugId: Int = 0,
+ enabled: Boolean = bugId == 0
+ ) {
+ all("appWindowReplacesLauncherAsTopWindow", enabled, bugId) {
+ this.showsLayer("Wallpaper")
+ .then()
+ .replaceVisibleLayer("Wallpaper", testApp.getPackage())
+ }
+ }
+} \ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
index f0bc3f00338a..d3595747d3ee 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
@@ -16,14 +16,19 @@
package com.android.server.wm.flicker.launch
-import androidx.test.filters.FlakyTest
+import android.view.Surface
import androidx.test.filters.LargeTest
-import com.android.server.wm.flicker.CommonTransitions
-import com.android.server.wm.flicker.LayersTraceSubject
-import com.android.server.wm.flicker.NonRotationTestBase
import com.android.server.wm.flicker.StandardAppHelper
-import com.android.server.wm.flicker.TransitionRunner
-import com.android.server.wm.flicker.WmTraceSubject
+import com.android.server.wm.flicker.dsl.flicker
+import com.android.server.wm.flicker.focusChanges
+import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
+import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.navBarLayerRotatesAndScales
+import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.noUncoveredRegions
+import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarLayerRotatesScales
+import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -38,50 +43,60 @@ import org.junit.runners.Parameterized
@RunWith(Parameterized::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
class OpenAppWarmTest(
- beginRotationName: String,
- beginRotation: Int
-) : NonRotationTestBase(beginRotationName, beginRotation) {
- init {
- testApp = StandardAppHelper(instrumentation,
+ rotationName: String,
+ rotation: Int
+) : OpenAppTestBase(rotationName, rotation) {
+ @Test
+ fun test() {
+ val testApp = StandardAppHelper(instrumentation,
"com.android.server.wm.flicker.testapp", "SimpleApp")
- }
-
- override val transitionToRun: TransitionRunner
- get() = CommonTransitions.openAppWarm(testApp, instrumentation, uiDevice, beginRotation)
- .includeJankyRuns().build()
- @Test
- fun checkVisibility_wallpaperBecomesInvisible() {
- checkResults {
- WmTraceSubject.assertThat(it)
- .showsBelowAppWindow("Wallpaper")
- .then()
- .hidesBelowAppWindow("Wallpaper")
- .forAllEntries()
- }
- }
+ flicker(instrumentation) {
+ withTag { buildTestTag("openAppWarm", testApp, rotation) }
+ repeat { 1 }
+ setup {
+ test {
+ device.wakeUpAndGoToHomeScreen()
+ testApp.open()
+ }
+ eachRun {
+ device.pressHome()
+ this.setRotation(rotation)
+ }
+ }
+ transitions {
+ testApp.open()
+ }
+ teardown {
+ eachRun {
+ this.setRotation(Surface.ROTATION_0)
+ }
+ test {
+ testApp.exit()
+ }
+ }
+ assertions {
+ windowManagerTrace {
+ navBarWindowIsAlwaysVisible()
+ statusBarWindowIsAlwaysVisible()
+ appWindowReplacesLauncherAsTopWindow(bugId = 141361128)
+ wallpaperWindowBecomesInvisible(enabled = false)
+ }
- @FlakyTest(bugId = 140855415)
- @Test
- fun checkZOrder_appWindowReplacesLauncherAsTopWindow() {
- checkResults {
- WmTraceSubject.assertThat(it)
- .showsAppWindowOnTop(
- "com.android.launcher3/.Launcher")
- .then()
- .showsAppWindowOnTop(testApp.getPackage())
- .forAllEntries()
- }
- }
+ layersTrace {
+ noUncoveredRegions(rotation, bugId = 141361128)
+ // During testing the launcher is always in portrait mode
+ navBarLayerRotatesAndScales(Surface.ROTATION_0, rotation)
+ statusBarLayerRotatesScales(Surface.ROTATION_0, rotation)
+ navBarLayerIsAlwaysVisible(bugId = 141361128)
+ statusBarLayerIsAlwaysVisible(bugId = 141361128)
+ wallpaperLayerBecomesInvisible(bugId = 141361128)
+ }
- @Test
- fun checkVisibility_wallpaperLayerBecomesInvisible() {
- checkResults {
- LayersTraceSubject.assertThat(it)
- .showsLayer("Wallpaper")
- .then()
- .replaceVisibleLayer("Wallpaper", testApp.getPackage())
- .forAllEntries()
+ eventLog {
+ focusChanges("NexusLauncherActivity", testApp.`package`)
+ }
+ }
}
}
-}
+} \ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/pip/PipTestBase.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/pip/PipTestBase.kt
index 79321f9488ad..4afabd4cdfb1 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/pip/PipTestBase.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/pip/PipTestBase.kt
@@ -16,66 +16,36 @@
package com.android.server.wm.flicker.pip
-import androidx.test.InstrumentationRegistry
-import androidx.test.filters.LargeTest
-import androidx.test.uiautomator.UiDevice
-import com.android.server.wm.flicker.LayersTraceSubject
+import com.android.server.wm.flicker.dsl.LayersAssertion
import com.android.server.wm.flicker.NonRotationTestBase
-import com.android.server.wm.flicker.WmTraceSubject
-import com.android.server.wm.flicker.helpers.AutomationUtils
+import com.android.server.wm.flicker.dsl.WmAssertion
import com.android.server.wm.flicker.helpers.PipAppHelper
-import org.junit.AfterClass
-import org.junit.FixMethodOrder
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-@LargeTest
-@RunWith(Parameterized::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
abstract class PipTestBase(
- beginRotationName: String,
- beginRotation: Int
-) : NonRotationTestBase(beginRotationName, beginRotation) {
- init {
- testApp = PipAppHelper(instrumentation)
- }
+ rotationName: String,
+ rotation: Int
+) : NonRotationTestBase(rotationName, rotation) {
+ protected val testApp = PipAppHelper(instrumentation)
- @Test
- fun checkVisibility_pipWindowBecomesVisible() {
- checkResults {
- WmTraceSubject.assertThat(it)
- .skipUntilFirstAssertion()
+ protected fun WmAssertion.pipWindowBecomesVisible() {
+ all("pipWindowBecomesVisible") {
+ this.skipUntilFirstAssertion()
.showsAppWindowOnTop(sPipWindowTitle)
.then()
.hidesAppWindow(sPipWindowTitle)
- .forAllEntries()
}
}
- @Test
- fun checkVisibility_pipLayerBecomesVisible() {
- checkResults {
- LayersTraceSubject.assertThat(it)
- .skipUntilFirstAssertion()
+ protected fun LayersAssertion.pipLayerBecomesVisible() {
+ all("pipLayerBecomesVisible") {
+ this.skipUntilFirstAssertion()
.showsLayer(sPipWindowTitle)
.then()
.hidesLayer(sPipWindowTitle)
- .forAllEntries()
}
}
companion object {
const val sPipWindowTitle = "PipMenuActivity"
-
- @AfterClass
- @JvmStatic
- fun teardown() {
- val device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
- if (AutomationUtils.hasPipWindow(device)) {
- AutomationUtils.closePipWindow(device)
- }
- }
}
-}
+} \ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/pip/PipToAppTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/pip/PipToAppTest.kt
index 89ffb7a57b73..c8a0e7dc9557 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/pip/PipToAppTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/pip/PipToAppTest.kt
@@ -16,12 +16,22 @@
package com.android.server.wm.flicker.pip
+import android.view.Surface
import androidx.test.filters.FlakyTest
import androidx.test.filters.LargeTest
-import com.android.server.wm.flicker.CommonTransitions
-import com.android.server.wm.flicker.TransitionRunner
-import com.android.server.wm.flicker.WmTraceSubject
-import com.android.server.wm.flicker.helpers.PipAppHelper
+import com.android.server.wm.flicker.dsl.flicker
+import com.android.server.wm.flicker.focusChanges
+import com.android.server.wm.flicker.helpers.closePipWindow
+import com.android.server.wm.flicker.helpers.expandPipWindow
+import com.android.server.wm.flicker.helpers.hasPipWindow
+import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
+import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.navBarLayerRotatesAndScales
+import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.noUncoveredRegions
+import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarLayerRotatesScales
+import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -37,27 +47,61 @@ import org.junit.runners.Parameterized
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@FlakyTest(bugId = 152738416)
class PipToAppTest(
- beginRotationName: String,
- beginRotation: Int
-) : PipTestBase(beginRotationName, beginRotation) {
- override val transitionToRun: TransitionRunner
- get() = CommonTransitions.exitPipModeToApp(testApp as PipAppHelper, instrumentation,
- uiDevice, beginRotation)
- .includeJankyRuns().build()
-
+ rotationName: String,
+ rotation: Int
+) : PipTestBase(rotationName, rotation) {
@Test
- fun checkVisibility_backgroundWindowVisibleBehindPipLayer() {
- checkResults {
- WmTraceSubject.assertThat(it)
- .skipUntilFirstAssertion()
- .showsAppWindowOnTop(sPipWindowTitle)
- .then()
- .showsBelowAppWindow("Wallpaper")
- .then()
- .showsAppWindowOnTop(testApp.getPackage())
- .then()
- .appWindowNotOnTop(testApp.getPackage())
- .forAllEntries()
+ fun test() {
+ flicker(instrumentation) {
+ withTag { buildTestTag("exitPipModeToApp", testApp, rotation) }
+ repeat { 1 }
+ setup {
+ eachRun {
+ device.wakeUpAndGoToHomeScreen()
+ }
+ }
+ teardown {
+ eachRun {
+ testApp.exit()
+ this.setRotation(Surface.ROTATION_0)
+ }
+ test {
+ if (device.hasPipWindow()) {
+ device.closePipWindow()
+ }
+ }
+ }
+ transitions {
+ device.pressHome()
+ this.setRotation(rotation)
+ testApp.open()
+ testApp.clickEnterPipButton(device)
+ device.expandPipWindow()
+ device.waitForIdle()
+ testApp.exit()
+ }
+ assertions {
+ windowManagerTrace {
+ navBarWindowIsAlwaysVisible()
+ statusBarWindowIsAlwaysVisible()
+ pipWindowBecomesVisible()
+ }
+
+ layersTrace {
+ navBarLayerIsAlwaysVisible()
+ statusBarLayerIsAlwaysVisible()
+ noUncoveredRegions(rotation)
+ navBarLayerRotatesAndScales(rotation)
+ statusBarLayerRotatesScales(rotation)
+ pipLayerBecomesVisible()
+ }
+
+ eventLog {
+ focusChanges(
+ "NexusLauncherActivity", testApp.launcherName, "NexusLauncherActivity",
+ bugId = 151179149)
+ }
+ }
}
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/pip/PipToHomeTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/pip/PipToHomeTest.kt
index 8591360cff60..7e9880c6caa8 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/pip/PipToHomeTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/pip/PipToHomeTest.kt
@@ -16,12 +16,21 @@
package com.android.server.wm.flicker.pip
+import android.view.Surface
import androidx.test.filters.FlakyTest
import androidx.test.filters.LargeTest
-import com.android.server.wm.flicker.CommonTransitions
-import com.android.server.wm.flicker.TransitionRunner
-import com.android.server.wm.flicker.WmTraceSubject
-import com.android.server.wm.flicker.helpers.PipAppHelper
+import com.android.server.wm.flicker.dsl.flicker
+import com.android.server.wm.flicker.focusChanges
+import com.android.server.wm.flicker.helpers.closePipWindow
+import com.android.server.wm.flicker.helpers.hasPipWindow
+import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
+import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.navBarLayerRotatesAndScales
+import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.noUncoveredRegions
+import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarLayerRotatesScales
+import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -37,24 +46,67 @@ import org.junit.runners.Parameterized
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@FlakyTest(bugId = 152738416)
class PipToHomeTest(
- beginRotationName: String,
- beginRotation: Int
-) : PipTestBase(beginRotationName, beginRotation) {
- override val transitionToRun: TransitionRunner
- get() = CommonTransitions.exitPipModeToHome(testApp as PipAppHelper, instrumentation,
- uiDevice, beginRotation)
- .includeJankyRuns().build()
-
+ rotationName: String,
+ rotation: Int
+) : PipTestBase(rotationName, rotation) {
@Test
- fun checkVisibility_backgroundWindowVisibleBehindPipLayer() {
- checkResults {
- WmTraceSubject.assertThat(it)
- .showsAppWindowOnTop(sPipWindowTitle)
- .then()
- .showsBelowAppWindow("Wallpaper")
- .then()
- .showsAppWindowOnTop("Wallpaper")
- .forAllEntries()
+ fun test() {
+ flicker(instrumentation) {
+ withTag { buildTestTag("exitPipModeToApp", testApp, rotation) }
+ repeat { 1 }
+ setup {
+ eachRun {
+ device.wakeUpAndGoToHomeScreen()
+ device.pressHome()
+ this.setRotation(rotation)
+ testApp.open()
+ }
+ }
+ teardown {
+ eachRun {
+ testApp.exit()
+ this.setRotation(Surface.ROTATION_0)
+ }
+ test {
+ if (device.hasPipWindow()) {
+ device.closePipWindow()
+ }
+ }
+ }
+ transitions {
+ testApp.clickEnterPipButton(device)
+ testApp.closePipWindow(device)
+ device.waitForIdle()
+ testApp.exit()
+ }
+ assertions {
+ windowManagerTrace {
+ navBarWindowIsAlwaysVisible()
+ statusBarWindowIsAlwaysVisible()
+ pipWindowBecomesVisible()
+
+ all {
+ this.showsAppWindowOnTop(sPipWindowTitle)
+ .and()
+ .showsBelowAppWindow("Wallpaper")
+ .then()
+ .showsAboveAppWindow("Wallpaper")
+ }
+ }
+
+ layersTrace {
+ navBarLayerIsAlwaysVisible()
+ statusBarLayerIsAlwaysVisible()
+ noUncoveredRegions(rotation)
+ navBarLayerRotatesAndScales(rotation)
+ statusBarLayerRotatesScales(rotation)
+ pipLayerBecomesVisible()
+ }
+
+ eventLog {
+ focusChanges(testApp.launcherName, "NexusLauncherActivity", bugId = 151179149)
+ }
+ }
}
}
-}
+} \ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
index fb1cb399e8bc..a7aae8c51d8f 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
@@ -16,15 +16,22 @@
package com.android.server.wm.flicker.rotation
-import android.util.Log
-import androidx.test.filters.FlakyTest
+import android.view.Surface
import androidx.test.filters.LargeTest
-import com.android.server.wm.flicker.CommonTransitions
-import com.android.server.wm.flicker.LayersTraceSubject
+import com.android.server.wm.flicker.NonRotationTestBase.Companion.SCREENSHOT_LAYER
import com.android.server.wm.flicker.RotationTestBase
import com.android.server.wm.flicker.StandardAppHelper
-import com.android.server.wm.flicker.TransitionRunner
-import com.android.server.wm.flicker.WindowUtils
+import com.android.server.wm.flicker.dsl.flicker
+import com.android.server.wm.flicker.focusDoesNotChange
+import com.android.server.wm.flicker.helpers.WindowUtils
+import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
+import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.navBarLayerRotatesAndScales
+import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.noUncoveredRegions
+import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarLayerRotatesScales
+import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -44,42 +51,80 @@ class ChangeAppRotationTest(
beginRotation: Int,
endRotation: Int
) : RotationTestBase(beginRotationName, endRotationName, beginRotation, endRotation) {
- init {
- testApp = StandardAppHelper(instrumentation,
+ @Test
+ fun test() {
+ val testApp = StandardAppHelper(instrumentation,
"com.android.server.wm.flicker.testapp", "SimpleApp")
- }
- override val transitionToRun: TransitionRunner
- get() = CommonTransitions.changeAppRotation(testApp, instrumentation, uiDevice,
- beginRotation, endRotation)
- .includeJankyRuns().build()
+ flicker(instrumentation) {
+ withTag {
+ buildTestTag("changeAppRotation", testApp, beginRotation, endRotation)
+ }
+ repeat { 1 }
+ setup {
+ eachRun {
+ device.wakeUpAndGoToHomeScreen()
+ testApp.open()
+ this.setRotation(beginRotation)
+ }
+ }
+ teardown {
+ eachRun {
+ testApp.exit()
+ this.setRotation(Surface.ROTATION_0)
+ }
+ }
+ transitions {
+ this.setRotation(endRotation)
+ }
+ assertions {
+ windowManagerTrace {
+ navBarWindowIsAlwaysVisible(bugId = 140855415)
+ statusBarWindowIsAlwaysVisible(bugId = 140855415)
+ }
- @Test
- fun checkPosition_appLayerRotates() {
- val startingPos = WindowUtils.getAppPosition(beginRotation)
- val endingPos = WindowUtils.getAppPosition(endRotation)
- Log.e(TAG, "startingPos=$startingPos endingPos=$endingPos")
- checkResults {
- LayersTraceSubject.assertThat(it)
- .hasVisibleRegion(testApp.getPackage(), startingPos).inTheBeginning()
- LayersTraceSubject.assertThat(it)
- .hasVisibleRegion(testApp.getPackage(), endingPos).atTheEnd()
- }
- }
+ layersTrace {
+ navBarLayerIsAlwaysVisible(bugId = 140855415)
+ statusBarLayerIsAlwaysVisible(bugId = 140855415)
+ noUncoveredRegions(beginRotation, endRotation, allStates = false)
+ navBarLayerRotatesAndScales(beginRotation, endRotation)
+ statusBarLayerRotatesScales(beginRotation, endRotation)
+ }
- @FlakyTest
- @Test
- fun checkVisibility_screenshotLayerBecomesInvisible() {
- checkResults {
- LayersTraceSubject.assertThat(it)
- .showsLayer(testApp.getPackage())
- .then()
- .replaceVisibleLayer(testApp.getPackage(), SCREENSHOT_LAYER)
- .then()
- .showsLayer(testApp.getPackage()).and().showsLayer(SCREENSHOT_LAYER)
- .then()
- .replaceVisibleLayer(SCREENSHOT_LAYER, testApp.getPackage())
- .forAllEntries()
+ layersTrace {
+ val startingPos = WindowUtils.getDisplayBounds(beginRotation)
+ val endingPos = WindowUtils.getDisplayBounds(endRotation)
+
+ start("appLayerRotates_StartingPos") {
+ this.hasVisibleRegion(testApp.getPackage(), startingPos)
+ }
+
+ end("appLayerRotates_EndingPos") {
+ this.hasVisibleRegion(testApp.getPackage(), endingPos)
+ }
+
+ all("screenshotLayerBecomesInvisible", enabled = false) {
+ this.showsLayer(testApp.getPackage())
+ .then()
+ .replaceVisibleLayer(
+ testApp.getPackage(),
+ SCREENSHOT_LAYER)
+ .then()
+ .showsLayer(testApp.getPackage())
+ .and()
+ .showsLayer(SCREENSHOT_LAYER)
+ .then()
+ .replaceVisibleLayer(
+ SCREENSHOT_LAYER,
+ testApp.getPackage()
+ )
+ }
+ }
+
+ eventLog {
+ focusDoesNotChange(bugId = 151179149)
+ }
+ }
}
}
-}
+} \ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
index 1cd19983f3b1..de87b412fc90 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
@@ -17,15 +17,26 @@
package com.android.server.wm.flicker.rotation
import android.content.Intent
+import android.content.Intent.FLAG_ACTIVITY_NEW_TASK
import android.view.Surface
-import androidx.test.InstrumentationRegistry
import androidx.test.filters.FlakyTest
import androidx.test.filters.LargeTest
-import com.android.server.wm.flicker.CommonTransitions
-import com.android.server.wm.flicker.LayersTraceSubject
+import androidx.test.uiautomator.By
+import androidx.test.uiautomator.Until
import com.android.server.wm.flicker.RotationTestBase
-import com.android.server.wm.flicker.TransitionRunner
-import com.android.server.wm.flicker.WindowUtils
+import com.android.server.wm.flicker.dsl.flicker
+import com.android.server.wm.flicker.focusDoesNotChange
+import com.android.server.wm.flicker.helpers.WindowUtils
+import com.android.server.wm.flicker.dsl.flicker
+import com.android.server.wm.flicker.helpers.stopPackage
+import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
+import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.navBarLayerRotatesAndScales
+import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.noUncoveredRegions
+import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarLayerRotatesScales
+import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
import com.android.server.wm.flicker.testapp.ActivityOptions
import org.junit.FixMethodOrder
import org.junit.Test
@@ -42,67 +53,101 @@ import org.junit.runners.Parameterized
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@FlakyTest(bugId = 147659548)
class SeamlessAppRotationTest(
+ testId: String,
private val intent: Intent,
beginRotationName: String,
endRotationName: String,
beginRotation: Int,
endRotation: Int
) : RotationTestBase(beginRotationName, endRotationName, beginRotation, endRotation) {
- override val transitionToRun: TransitionRunner
- get() {
- var intentId = ""
- if (intent.extras?.getBoolean(ActivityOptions.EXTRA_STARVE_UI_THREAD) == true) {
- intentId = "BUSY_UI_THREAD"
- }
- return CommonTransitions.changeAppRotation(intent, intentId,
- InstrumentationRegistry.getContext(), instrumentation, uiDevice,
- beginRotation, endRotation).build()
+ @Test
+ fun test() {
+ var intentId = ""
+ if (intent.extras?.getBoolean(ActivityOptions.EXTRA_STARVE_UI_THREAD) == true) {
+ intentId = "BUSY_UI_THREAD"
}
- @Test
- fun checkPosition_appLayerRotates() {
- val startingPos = WindowUtils.getAppPosition(beginRotation)
- val endingPos = WindowUtils.getAppPosition(endRotation)
- if (startingPos == endingPos) {
- checkResults {
- LayersTraceSubject.assertThat(it)
- .hasVisibleRegion(intent.component?.packageName ?: "", startingPos)
- .forAllEntries()
+ flicker(instrumentation) {
+ withTag {
+ "changeAppRotation_" + intentId + "_" +
+ Surface.rotationToString(beginRotation) + "_" +
+ Surface.rotationToString(endRotation)
}
- } else {
- checkResults {
- LayersTraceSubject.assertThat(it)
- .hasVisibleRegion(intent.component?.packageName ?: "", startingPos)
- .then()
- .hasVisibleRegion(intent.component?.packageName ?: "", endingPos)
- .forAllEntries()
+ repeat { 1 }
+ setup {
+ eachRun {
+ device.wakeUpAndGoToHomeScreen()
+ instrumentation.targetContext.startActivity(intent)
+ device.wait(Until.hasObject(By.pkg(intent.component?.packageName)
+ .depth(0)), APP_LAUNCH_TIMEOUT)
+ this.setRotation(beginRotation)
+ }
}
- }
- }
-
- @Test
- fun checkCoveredRegion_noUncoveredRegions() {
- val startingBounds = WindowUtils.getDisplayBounds(beginRotation)
- val endingBounds = WindowUtils.getDisplayBounds(endRotation)
- if (startingBounds == endingBounds) {
- checkResults {
- LayersTraceSubject.assertThat(it)
- .coversRegion(startingBounds)
- .forAllEntries()
+ teardown {
+ eachRun {
+ stopPackage(
+ instrumentation.targetContext,
+ intent.component?.packageName
+ ?: error("Unable to determine package name for intent"))
+ this.setRotation(Surface.ROTATION_0)
+ }
}
- } else {
- checkResults {
- LayersTraceSubject.assertThat(it)
- .coversRegion(startingBounds)
- .then()
- .coversRegion(endingBounds)
- .forAllEntries()
+ transitions {
+ this.setRotation(endRotation)
+ }
+ assertions {
+ windowManagerTrace {
+ navBarWindowIsAlwaysVisible(bugId = 140855415)
+ statusBarWindowIsAlwaysVisible(bugId = 140855415)
+ }
+
+ layersTrace {
+ navBarLayerIsAlwaysVisible(bugId = 140855415)
+ statusBarLayerIsAlwaysVisible(bugId = 140855415)
+ noUncoveredRegions(beginRotation, endRotation, allStates = true)
+ navBarLayerRotatesAndScales(beginRotation, endRotation)
+ statusBarLayerRotatesScales(beginRotation, endRotation, enabled = false)
+ }
+
+ layersTrace {
+ all("appLayerRotates"/*, bugId = 147659548*/) {
+ val startingPos = WindowUtils.getDisplayBounds(beginRotation)
+ val endingPos = WindowUtils.getDisplayBounds(endRotation)
+
+ if (startingPos == endingPos) {
+ this.hasVisibleRegion(
+ intent.component?.packageName ?: "",
+ startingPos)
+ } else {
+ this.hasVisibleRegion(intent.component?.packageName ?: "", startingPos)
+ .then()
+ .hasVisibleRegion(intent.component?.packageName
+ ?: "", endingPos)
+ }
+ }
+
+ all("noUncoveredRegions"/*, bugId = 147659548*/) {
+ val startingBounds = WindowUtils.getDisplayBounds(beginRotation)
+ val endingBounds = WindowUtils.getDisplayBounds(endRotation)
+ if (startingBounds == endingBounds) {
+ this.coversAtLeastRegion(startingBounds)
+ } else {
+ this.coversAtLeastRegion(startingBounds)
+ .then()
+ .coversAtLeastRegion(endingBounds)
+ }
+ }
+ }
+
+ eventLog {
+ focusDoesNotChange(bugId = 151179149)
+ }
}
}
}
companion object {
- // launch test activity that supports seamless rotation
+ private const val APP_LAUNCH_TIMEOUT: Long = 10000
// launch test activity that supports seamless rotation with a busy UI thread to miss frames
// when the app is asked to redraw
@@ -110,18 +155,20 @@ class SeamlessAppRotationTest(
@JvmStatic
fun getParams(): Collection<Array<Any>> {
val supportedRotations = intArrayOf(Surface.ROTATION_0, Surface.ROTATION_90)
- val params: MutableCollection<Array<Any>> = ArrayList()
- val testIntents = ArrayList<Intent>()
+ val params = mutableListOf<Array<Any>>()
+ val testIntents = mutableListOf<Intent>()
// launch test activity that supports seamless rotation
var intent = Intent(Intent.ACTION_MAIN)
intent.component = ActivityOptions.SEAMLESS_ACTIVITY_COMPONENT_NAME
+ intent.flags = FLAG_ACTIVITY_NEW_TASK
testIntents.add(intent)
// launch test activity that supports seamless rotation with a busy UI thread to miss frames
// when the app is asked to redraw
intent = Intent(intent)
intent.putExtra(ActivityOptions.EXTRA_STARVE_UI_THREAD, true)
+ intent.flags = FLAG_ACTIVITY_NEW_TASK
testIntents.add(intent)
for (testIntent in testIntents) {
for (begin in supportedRotations) {
@@ -133,7 +180,13 @@ class SeamlessAppRotationTest(
ActivityOptions.EXTRA_STARVE_UI_THREAD) == true) {
testId += "_" + "BUSY_UI_THREAD"
}
- params.add(arrayOf(testId, testIntent, begin, end))
+ params.add(arrayOf(
+ testId,
+ testIntent,
+ Surface.rotationToString(begin),
+ Surface.rotationToString(end),
+ begin,
+ end))
}
}
}
@@ -141,4 +194,4 @@ class SeamlessAppRotationTest(
return params
}
}
-}
+} \ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/OpenAppToSplitScreenTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/OpenAppToSplitScreenTest.kt
index b5611a45a2e7..a4ec3b17e63e 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/OpenAppToSplitScreenTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/OpenAppToSplitScreenTest.kt
@@ -16,13 +16,23 @@
package com.android.server.wm.flicker.splitscreen
+import android.os.SystemClock
+import android.view.Surface
import androidx.test.filters.LargeTest
-import com.android.server.wm.flicker.CommonTransitions
-import com.android.server.wm.flicker.LayersTraceSubject
import com.android.server.wm.flicker.NonRotationTestBase
import com.android.server.wm.flicker.StandardAppHelper
-import com.android.server.wm.flicker.TransitionRunner
-import com.android.server.wm.flicker.WmTraceSubject
+import com.android.server.wm.flicker.dsl.flicker
+import com.android.server.wm.flicker.focusChanges
+import com.android.server.wm.flicker.helpers.exitSplitScreen
+import com.android.server.wm.flicker.helpers.launchSplitScreen
+import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
+import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.navBarLayerRotatesAndScales
+import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.noUncoveredRegions
+import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarLayerRotatesScales
+import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -37,42 +47,68 @@ import org.junit.runners.Parameterized
@RunWith(Parameterized::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
class OpenAppToSplitScreenTest(
- beginRotationName: String,
- beginRotation: Int
-) : NonRotationTestBase(beginRotationName, beginRotation) {
- init {
- testApp = StandardAppHelper(instrumentation,
- "com.android.server.wm.flicker.testapp", "SimpleApp")
- }
+ rotationName: String,
+ rotation: Int
+) : NonRotationTestBase(rotationName, rotation) {
+ @Test
+ fun test() {
+ val testApp = StandardAppHelper(instrumentation,
+ "com.android.server.wm.flicker.testapp", "SimpleApp")
- override val transitionToRun: TransitionRunner
- get() = CommonTransitions.appToSplitScreen(testApp, instrumentation, uiDevice,
- beginRotation).includeJankyRuns().build()
+ flicker(instrumentation) {
+ withTag { buildTestTag("appToSplitScreen", testApp, rotation) }
+ repeat { 1 }
+ setup {
+ eachRun {
+ device.wakeUpAndGoToHomeScreen()
+ this.setRotation(rotation)
+ testApp.open()
+ SystemClock.sleep(500)
+ }
+ }
+ teardown {
+ eachRun {
+ device.exitSplitScreen()
+ testApp.exit()
+ }
+ }
+ transitions {
+ device.launchSplitScreen()
+ }
+ assertions {
+ windowManagerTrace {
+ navBarWindowIsAlwaysVisible()
+ statusBarWindowIsAlwaysVisible()
+ }
- @Test
- fun checkVisibility_navBarWindowIsAlwaysVisible() {
- checkResults {
- WmTraceSubject.assertThat(it)
- .showsAboveAppWindow(NAVIGATION_BAR_WINDOW_TITLE).forAllEntries()
- }
- }
+ layersTrace {
+ navBarLayerIsAlwaysVisible()
+ statusBarLayerIsAlwaysVisible()
+ noUncoveredRegions(rotation)
+ navBarLayerRotatesAndScales(rotation)
+ statusBarLayerRotatesScales(rotation)
- @Test
- fun checkVisibility_statusBarWindowIsAlwaysVisible() {
- checkResults {
- WmTraceSubject.assertThat(it)
- .showsAboveAppWindow(STATUS_BAR_WINDOW_TITLE).forAllEntries()
+ all("dividerLayerBecomesVisible") {
+ this.hidesLayer(DOCKED_STACK_DIVIDER)
+ .then()
+ .showsLayer(DOCKED_STACK_DIVIDER)
+ }
+ }
+
+ eventLog {
+ focusChanges(testApp.`package`,
+ "recents_animation_input_consumer", "NexusLauncherActivity")
+ }
+ }
}
}
- @Test
- fun checkVisibility_dividerLayerBecomesVisible() {
- checkResults {
- LayersTraceSubject.assertThat(it)
- .hidesLayer(DOCKED_STACK_DIVIDER)
- .then()
- .showsLayer(DOCKED_STACK_DIVIDER)
- .forAllEntries()
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): Collection<Array<Any>> {
+ val supportedRotations = intArrayOf(Surface.ROTATION_0)
+ return supportedRotations.map { arrayOf(Surface.rotationToString(it), it) }
}
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/ResizeSplitScreenTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/ResizeSplitScreenTest.kt
index 6b597e5807ea..a08b2bfdf1fe 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/ResizeSplitScreenTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/ResizeSplitScreenTest.kt
@@ -19,24 +19,28 @@ package com.android.server.wm.flicker.splitscreen
import android.graphics.Region
import android.util.Rational
import android.view.Surface
-import androidx.test.InstrumentationRegistry
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.FlakyTest
import androidx.test.filters.LargeTest
-import androidx.test.runner.AndroidJUnit4
-import androidx.test.uiautomator.UiDevice
-import com.android.server.wm.flicker.CommonTransitions
+import androidx.test.uiautomator.By
import com.android.server.wm.flicker.FlickerTestBase
-import com.android.server.wm.flicker.LayersTrace
-import com.android.server.wm.flicker.LayersTraceSubject
import com.android.server.wm.flicker.StandardAppHelper
-import com.android.server.wm.flicker.TransitionRunner
-import com.android.server.wm.flicker.TransitionResult
-import com.android.server.wm.flicker.WindowUtils
-import com.android.server.wm.flicker.WmTraceSubject
-import com.android.server.wm.flicker.helpers.AutomationUtils
+import com.android.server.wm.flicker.dsl.flicker
+import com.android.server.wm.flicker.focusDoesNotChange
import com.android.server.wm.flicker.helpers.ImeAppHelper
-import com.google.common.truth.Truth
-import org.junit.AfterClass
+import com.android.server.wm.flicker.helpers.WindowUtils
+import com.android.server.wm.flicker.helpers.exitSplitScreen
+import com.android.server.wm.flicker.helpers.isInSplitScreen
+import com.android.server.wm.flicker.helpers.launchSplitScreen
+import com.android.server.wm.flicker.helpers.resizeSplitScreen
+import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
+import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.navBarLayerRotatesAndScales
+import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.noUncoveredRegions
+import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarLayerRotatesScales
+import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -53,146 +57,134 @@ import org.junit.runners.MethodSorters
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@FlakyTest(bugId = 159096424)
class ResizeSplitScreenTest : FlickerTestBase() {
- init {
- testApp = StandardAppHelper(instrumentation,
+ @Test
+ fun test() {
+ val testAppTop = StandardAppHelper(instrumentation,
"com.android.server.wm.flicker.testapp", "SimpleApp")
- }
+ val testAppBottom = ImeAppHelper(instrumentation)
- override val transitionToRun: TransitionRunner
- get() {
- val bottomApp = ImeAppHelper(instrumentation)
- return CommonTransitions.resizeSplitScreen(testApp, bottomApp, instrumentation,
- uiDevice, Surface.ROTATION_0,
- Rational(1, 3), Rational(2, 3))
- .includeJankyRuns().build()
- }
+ flicker(instrumentation) {
+ withTag {
+ val description = (startRatio.toString().replace("/", "-") + "_to_" +
+ stopRatio.toString().replace("/", "-"))
+ buildTestTag("resizeSplitScreen", testAppTop, rotation,
+ rotation, testAppBottom, description)
+ }
+ repeat { 1 }
+ setup {
+ eachRun {
+ device.wakeUpAndGoToHomeScreen()
+ this.setRotation(rotation)
+ this.launcherStrategy.clearRecentAppsFromOverview()
+ testAppBottom.open()
+ device.pressHome()
+ testAppTop.open()
+ device.waitForIdle()
+ device.launchSplitScreen()
+ val snapshot = device.findObject(By.res(device.launcherPackageName, "snapshot"))
+ snapshot.click()
+ testAppBottom.openIME(device)
+ device.pressBack()
+ device.resizeSplitScreen(startRatio)
+ }
+ }
+ teardown {
+ eachRun {
+ device.exitSplitScreen()
+ device.pressHome()
+ testAppTop.exit()
+ testAppBottom.exit()
+ }
+ test {
+ if (device.isInSplitScreen()) {
+ device.exitSplitScreen()
+ }
+ }
+ }
+ transitions {
+ device.resizeSplitScreen(stopRatio)
+ }
+ assertions {
+ windowManagerTrace {
+ navBarWindowIsAlwaysVisible()
+ statusBarWindowIsAlwaysVisible()
- @Test
- fun checkVisibility_topAppLayerIsAlwaysVisible() {
- checkResults {
- LayersTraceSubject.assertThat(it)
- .showsLayer(sSimpleActivity)
- .forAllEntries()
- }
- }
+ all("topAppWindowIsAlwaysVisible", bugId = 156223549) {
+ this.showsAppWindow(sSimpleActivity)
+ }
- @Test
- fun checkVisibility_bottomAppLayerIsAlwaysVisible() {
- checkResults {
- LayersTraceSubject.assertThat(it)
- .showsLayer(sImeActivity)
- .forAllEntries()
- }
- }
+ all("bottomAppWindowIsAlwaysVisible", bugId = 156223549) {
+ this.showsAppWindow(sImeActivity)
+ }
+ }
- @Test
- fun checkVisibility_dividerLayerIsAlwaysVisible() {
- checkResults {
- LayersTraceSubject.assertThat(it)
- .showsLayer(DOCKED_STACK_DIVIDER)
- .forAllEntries()
- }
- }
+ layersTrace {
+ navBarLayerIsAlwaysVisible()
+ statusBarLayerIsAlwaysVisible()
+ noUncoveredRegions(rotation)
+ navBarLayerRotatesAndScales(rotation)
+ statusBarLayerRotatesScales(rotation)
- @Test
- @FlakyTest
- fun checkPosition_appsStartingBounds() {
- val displayBounds = WindowUtils.getDisplayBounds()
- checkResults { result: TransitionResult ->
- val entries = LayersTrace.parseFrom(result.layersTrace,
- result.layersTracePath, result.layersTraceChecksum)
- Truth.assertThat(entries.entries).isNotEmpty()
- val startingDividerBounds = entries.entries[0].getVisibleBounds(
- DOCKED_STACK_DIVIDER).bounds
- val startingTopAppBounds = Region(0, 0, startingDividerBounds.right,
- startingDividerBounds.top + WindowUtils.getDockedStackDividerInset())
- val startingBottomAppBounds = Region(0,
- startingDividerBounds.bottom - WindowUtils.getDockedStackDividerInset(),
- displayBounds.right,
- displayBounds.bottom - WindowUtils.getNavigationBarHeight())
- LayersTraceSubject.assertThat(result)
- .hasVisibleRegion("SimpleActivity", startingTopAppBounds)
- .inTheBeginning()
- LayersTraceSubject.assertThat(result)
- .hasVisibleRegion("ImeActivity", startingBottomAppBounds)
- .inTheBeginning()
- }
- }
+ all("topAppLayerIsAlwaysVisible") {
+ this.showsLayer(sSimpleActivity)
+ }
- @Test
- @FlakyTest
- fun checkPosition_appsEndingBounds() {
- val displayBounds = WindowUtils.getDisplayBounds()
- checkResults { result: TransitionResult ->
- val entries = LayersTrace.parseFrom(result.layersTrace,
- result.layersTracePath, result.layersTraceChecksum)
- Truth.assertThat(entries.entries).isNotEmpty()
- val endingDividerBounds = entries.entries[entries.entries.size - 1].getVisibleBounds(
- DOCKED_STACK_DIVIDER).bounds
- val startingTopAppBounds = Region(0, 0, endingDividerBounds.right,
- endingDividerBounds.top + WindowUtils.getDockedStackDividerInset())
- val startingBottomAppBounds = Region(0,
- endingDividerBounds.bottom - WindowUtils.getDockedStackDividerInset(),
- displayBounds.right,
- displayBounds.bottom - WindowUtils.getNavigationBarHeight())
- LayersTraceSubject.assertThat(result)
- .hasVisibleRegion(sSimpleActivity, startingTopAppBounds)
- .atTheEnd()
- LayersTraceSubject.assertThat(result)
- .hasVisibleRegion(sImeActivity, startingBottomAppBounds)
- .atTheEnd()
- }
- }
+ all("bottomAppLayerIsAlwaysVisible") {
+ this.showsLayer(sImeActivity)
+ }
- @Test
- fun checkVisibility_navBarWindowIsAlwaysVisible() {
- checkResults {
- WmTraceSubject.assertThat(it)
- .showsAboveAppWindow(NAVIGATION_BAR_WINDOW_TITLE)
- .forAllEntries()
- }
- }
+ all("dividerLayerIsAlwaysVisible") {
+ this.showsLayer(DOCKED_STACK_DIVIDER)
+ }
- @Test
- fun checkVisibility_statusBarWindowIsAlwaysVisible() {
- checkResults {
- WmTraceSubject.assertThat(it)
- .showsAboveAppWindow(STATUS_BAR_WINDOW_TITLE)
- .forAllEntries()
- }
- }
+ start("appsStartingBounds", enabled = false) {
+ val displayBounds = WindowUtils.displayBounds
+ val entry = this.trace.entries.firstOrNull()
+ ?: throw IllegalStateException("Trace is empty")
+ val dividerBounds = entry.getVisibleBounds(DOCKED_STACK_DIVIDER).bounds
- @Test
- @FlakyTest(bugId = 156223549)
- fun checkVisibility_topAppWindowIsAlwaysVisible() {
- checkResults {
- WmTraceSubject.assertThat(it)
- .showsAppWindow(sSimpleActivity)
- .forAllEntries()
- }
- }
+ val topAppBounds = Region(0, 0, dividerBounds.right,
+ dividerBounds.top + WindowUtils.dockedStackDividerInset)
+ val bottomAppBounds = Region(0,
+ dividerBounds.bottom - WindowUtils.dockedStackDividerInset,
+ displayBounds.right,
+ displayBounds.bottom - WindowUtils.navigationBarHeight)
+ this.hasVisibleRegion("SimpleActivity", topAppBounds)
+ .and()
+ .hasVisibleRegion("ImeActivity", bottomAppBounds)
+ }
- @Test
- @FlakyTest(bugId = 156223549)
- fun checkVisibility_bottomAppWindowIsAlwaysVisible() {
- checkResults {
- WmTraceSubject.assertThat(it)
- .showsAppWindow(sImeActivity)
- .forAllEntries()
+ end("appsEndingBounds", enabled = false) {
+ val displayBounds = WindowUtils.displayBounds
+ val entry = this.trace.entries.lastOrNull()
+ ?: throw IllegalStateException("Trace is empty")
+ val dividerBounds = entry.getVisibleBounds(DOCKED_STACK_DIVIDER).bounds
+
+ val topAppBounds = Region(0, 0, dividerBounds.right,
+ dividerBounds.top + WindowUtils.dockedStackDividerInset)
+ val bottomAppBounds = Region(0,
+ dividerBounds.bottom - WindowUtils.dockedStackDividerInset,
+ displayBounds.right,
+ displayBounds.bottom - WindowUtils.navigationBarHeight)
+
+ this.hasVisibleRegion(sSimpleActivity, topAppBounds)
+ .and()
+ .hasVisibleRegion(sImeActivity, bottomAppBounds)
+ }
+ }
+
+ eventLog {
+ focusDoesNotChange()
+ }
+ }
}
}
companion object {
private const val sSimpleActivity = "SimpleActivity"
private const val sImeActivity = "ImeActivity"
-
- @AfterClass
- @JvmStatic
- fun teardown() {
- val device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
- if (AutomationUtils.isInSplitScreen(device)) {
- AutomationUtils.exitSplitScreen(device)
- }
- }
+ private val rotation = Surface.ROTATION_0
+ private val startRatio = Rational(1, 3)
+ private val stopRatio = Rational(2, 3)
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/SplitScreenToLauncherTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/SplitScreenToLauncherTest.kt
index fdcafdb12a78..3ae3967add43 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/SplitScreenToLauncherTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/SplitScreenToLauncherTest.kt
@@ -17,19 +17,23 @@
package com.android.server.wm.flicker.splitscreen
import android.view.Surface
-import androidx.test.InstrumentationRegistry
+import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.LargeTest
-import androidx.test.runner.AndroidJUnit4
-import androidx.test.uiautomator.UiDevice
-import com.android.server.wm.flicker.CommonTransitions
import com.android.server.wm.flicker.FlickerTestBase
-import com.android.server.wm.flicker.LayersTraceSubject
import com.android.server.wm.flicker.StandardAppHelper
-import com.android.server.wm.flicker.TransitionRunner
-import com.android.server.wm.flicker.WindowUtils
-import com.android.server.wm.flicker.WmTraceSubject
-import com.android.server.wm.flicker.helpers.AutomationUtils
-import org.junit.AfterClass
+import com.android.server.wm.flicker.dsl.flicker
+import com.android.server.wm.flicker.focusDoesNotChange
+import com.android.server.wm.flicker.helpers.exitSplitScreen
+import com.android.server.wm.flicker.helpers.isInSplitScreen
+import com.android.server.wm.flicker.helpers.launchSplitScreen
+import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
+import com.android.server.wm.flicker.navBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.navBarLayerRotatesAndScales
+import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
+import com.android.server.wm.flicker.noUncoveredRegions
+import com.android.server.wm.flicker.statusBarLayerIsAlwaysVisible
+import com.android.server.wm.flicker.statusBarLayerRotatesScales
+import com.android.server.wm.flicker.statusBarWindowIsAlwaysVisible
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -43,68 +47,67 @@ import org.junit.runners.MethodSorters
@RunWith(AndroidJUnit4::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
class SplitScreenToLauncherTest : FlickerTestBase() {
- init {
- testApp = StandardAppHelper(InstrumentationRegistry.getInstrumentation(),
- "com.android.server.wm.flicker.testapp", "SimpleApp")
- }
-
- override val transitionToRun: TransitionRunner
- get() = CommonTransitions.splitScreenToLauncher(testApp, instrumentation, uiDevice,
- Surface.ROTATION_0).includeJankyRuns().build()
-
+ private val rotation: Int = Surface.ROTATION_0
@Test
- fun checkCoveredRegion_noUncoveredRegions() {
- checkResults {
- LayersTraceSubject.assertThat(it)
- .coversRegion(WindowUtils.getDisplayBounds()).forAllEntries()
- }
- }
+ fun test() {
+ val testApp = StandardAppHelper(instrumentation,
+ "com.android.server.wm.flicker.testapp", "SimpleApp")
- @Test
- fun checkVisibility_dividerLayerBecomesInVisible() {
- checkResults {
- LayersTraceSubject.assertThat(it)
- .showsLayer(DOCKED_STACK_DIVIDER)
- .then()
- .hidesLayer(DOCKED_STACK_DIVIDER)
- .forAllEntries()
- }
- }
+ flicker(instrumentation) {
+ withTag { buildTestTag("splitScreenToLauncher", testApp, rotation) }
+ repeat { 1 }
+ setup {
+ eachRun {
+ device.wakeUpAndGoToHomeScreen()
+ testApp.open()
+ this.setRotation(rotation)
+ device.launchSplitScreen()
+ device.waitForIdle()
+ }
+ }
+ teardown {
+ eachRun {
+ testApp.exit()
+ }
+ test {
+ if (device.isInSplitScreen()) {
+ device.exitSplitScreen()
+ }
+ }
+ }
+ transitions {
+ device.exitSplitScreen()
+ }
+ assertions {
+ windowManagerTrace {
+ navBarWindowIsAlwaysVisible()
+ statusBarWindowIsAlwaysVisible()
+ }
- @Test
- fun checkVisibility_appLayerBecomesInVisible() {
- checkResults {
- LayersTraceSubject.assertThat(it)
- .showsLayer(testApp.getPackage())
- .then()
- .hidesLayer(testApp.getPackage())
- .forAllEntries()
- }
- }
+ layersTrace {
+ navBarLayerIsAlwaysVisible()
+ statusBarLayerIsAlwaysVisible()
+ noUncoveredRegions(rotation)
+ navBarLayerRotatesAndScales(rotation)
+ statusBarLayerRotatesScales(rotation)
- @Test
- fun checkVisibility_navBarWindowIsAlwaysVisible() {
- checkResults {
- WmTraceSubject.assertThat(it)
- .showsAboveAppWindow(NAVIGATION_BAR_WINDOW_TITLE).forAllEntries()
- }
- }
+ // b/161435597 causes the test not to work on 90 degrees
+ all("dividerLayerBecomesInvisible") {
+ this.showsLayer(DOCKED_STACK_DIVIDER)
+ .then()
+ .hidesLayer(DOCKED_STACK_DIVIDER)
+ }
- @Test
- fun checkVisibility_statusBarWindowIsAlwaysVisible() {
- checkResults {
- WmTraceSubject.assertThat(it)
- .showsAboveAppWindow(STATUS_BAR_WINDOW_TITLE).forAllEntries()
- }
- }
+ all("appLayerBecomesInvisible") {
+ this.showsLayer(testApp.getPackage())
+ .then()
+ .hidesLayer(testApp.getPackage())
+ }
+ }
- companion object {
- @AfterClass
- @JvmStatic
- fun teardown() {
- val device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
- if (AutomationUtils.isInSplitScreen(device)) {
- AutomationUtils.exitSplitScreen(device)
+ eventLog {
+ focusDoesNotChange(bugId = 151179149)
+ }
}
}
}
diff --git a/tests/LocalizationTest/Android.bp b/tests/LocalizationTest/Android.bp
new file mode 100644
index 000000000000..c4bfcb1d2261
--- /dev/null
+++ b/tests/LocalizationTest/Android.bp
@@ -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.
+
+android_test {
+ name: "LocalizationTest",
+ srcs: ["java/**/*.kt"],
+ libs: [
+ "android.test.runner",
+ "android.test.base",
+ "android.test.mock",
+ ],
+ static_libs: [
+ "androidx.test.core",
+ "androidx.test.ext.junit",
+ "androidx.test.rules",
+ "mockito-target-extended-minus-junit4",
+ "truth-prebuilt",
+ ],
+ jni_libs: [
+ // For mockito extended
+ "libdexmakerjvmtiagent",
+ "libstaticjvmtiagent",
+ ],
+ certificate: "platform",
+ platform_apis: true,
+ test_suites: ["device-tests"],
+ optimize: {
+ enabled: false,
+ },
+}
diff --git a/core/res/res/drawable-car-night/car_dialog_button_background.xml b/tests/LocalizationTest/AndroidManifest.xml
index 138cb38b0d87..b135443960f5 100644
--- a/core/res/res/drawable-car-night/car_dialog_button_background.xml
+++ b/tests/LocalizationTest/AndroidManifest.xml
@@ -14,19 +14,16 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_focused="true">
- <ripple android:color="#2371cd">
- <item android:id="@android:id/mask">
- <color android:color="@*android:color/car_white_1000"/>
- </item>
- </ripple>
- </item>
- <item>
- <ripple android:color="?android:attr/colorControlHighlight">
- <item android:id="@android:id/mask">
- <color android:color="@*android:color/car_white_1000"/>
- </item>
- </ripple>
- </item>
-</selector>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.android.internal.app">
+
+ <application android:debuggable="true" android:testOnly="true">
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation
+ android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.android.internal.app"
+ android:label="Localization Tests" />
+
+</manifest>
diff --git a/tests/LocalizationTest/AndroidTest.xml b/tests/LocalizationTest/AndroidTest.xml
new file mode 100644
index 000000000000..8309b4f611f8
--- /dev/null
+++ b/tests/LocalizationTest/AndroidTest.xml
@@ -0,0 +1,34 @@
+<?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.
+ -->
+<configuration description="Localization Tests.">
+ <option name="test-suite-tag" value="apct" />
+ <option name="test-suite-tag" value="apct-instrumentation" />
+
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true" />
+ <option name="install-arg" value="-t" />
+ <option name="test-file-name" value="LocalizationTest.apk" />
+ </target_preparer>
+
+ <option name="test-tag" value="LocalizationTest" />
+
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+ <option name="package" value="com.android.android.internal.app" />
+ <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
+ <option name="hidden-api-checks" value="false"/>
+ </test>
+</configuration> \ No newline at end of file
diff --git a/tests/LocalizationTest/java/com/android/internal/app/LocalizationTest.kt b/tests/LocalizationTest/java/com/android/internal/app/LocalizationTest.kt
new file mode 100644
index 000000000000..22ea97167326
--- /dev/null
+++ b/tests/LocalizationTest/java/com/android/internal/app/LocalizationTest.kt
@@ -0,0 +1,118 @@
+/*
+ * 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.android.internal.app
+
+import android.os.SystemProperties
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn
+import com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession
+import com.android.internal.R
+import com.android.internal.app.LocalePicker
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.After
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.eq
+import org.mockito.MockitoSession
+
+@RunWith(AndroidJUnit4::class)
+class LocalizationTest {
+ private val mContext = InstrumentationRegistry.getInstrumentation().context
+ private val mUnfilteredLocales =
+ mContext.getResources().getStringArray(R.array.supported_locales)
+
+ private lateinit var mMockitoSession: MockitoSession
+
+ @Before
+ fun setUp() {
+ mMockitoSession = mockitoSession()
+ .initMocks(this)
+ .spyStatic(SystemProperties::class.java)
+ .startMocking()
+ }
+
+ @After
+ fun tearDown() {
+ mMockitoSession.finishMocking()
+ }
+
+ @Test
+ fun testGetSupportedLocales_noFilter() {
+ // Filter not set.
+ setTestLocaleFilter(null)
+
+ val locales1 = LocalePicker.getSupportedLocales(mContext)
+
+ assertThat(locales1).isEqualTo(mUnfilteredLocales)
+
+ // Empty filter.
+ setTestLocaleFilter("")
+
+ val locales2 = LocalePicker.getSupportedLocales(mContext)
+
+ assertThat(locales2).isEqualTo(mUnfilteredLocales)
+ }
+
+ @Test
+ fun testGetSupportedLocales_invalidFilter() {
+ setTestLocaleFilter("**")
+
+ val locales = LocalePicker.getSupportedLocales(mContext)
+
+ assertThat(locales).isEqualTo(mUnfilteredLocales)
+ }
+
+ @Test
+ fun testGetSupportedLocales_inclusiveFilter() {
+ setTestLocaleFilter("^(de-AT|de-DE|en|ru).*")
+
+ val locales = LocalePicker.getSupportedLocales(mContext)
+
+ assertThat(locales).isEqualTo(
+ mUnfilteredLocales
+ .filter { it.startsWithAnyOf("de-AT", "de-DE", "en", "ru") }
+ .toTypedArray()
+ )
+ }
+
+ @Test
+ fun testGetSupportedLocales_exclusiveFilter() {
+ setTestLocaleFilter("^(?!de-IT|es|fr).*")
+
+ val locales = LocalePicker.getSupportedLocales(mContext)
+
+ assertThat(locales).isEqualTo(
+ mUnfilteredLocales
+ .filter { !it.startsWithAnyOf("de-IT", "es", "fr") }
+ .toTypedArray()
+ )
+ }
+
+ private fun setTestLocaleFilter(localeFilter: String?) {
+ doReturn(localeFilter).`when` { SystemProperties.get(eq("ro.localization.locale_filter")) }
+ }
+
+ private fun String.startsWithAnyOf(vararg prefixes: String): Boolean {
+ prefixes.forEach {
+ if (startsWith(it)) return true
+ }
+
+ return false
+ }
+}
diff --git a/tests/net/common/java/android/net/NetworkProviderTest.kt b/tests/net/common/java/android/net/NetworkProviderTest.kt
index b7c47c2bc223..dd3f5bebdb8e 100644
--- a/tests/net/common/java/android/net/NetworkProviderTest.kt
+++ b/tests/net/common/java/android/net/NetworkProviderTest.kt
@@ -19,23 +19,23 @@ package android.net
import android.app.Instrumentation
import android.content.Context
import android.net.NetworkCapabilities.TRANSPORT_TEST
+import android.net.NetworkProviderTest.TestNetworkCallback.CallbackEntry.OnUnavailable
+import android.net.NetworkProviderTest.TestNetworkProvider.CallbackEntry.OnNetworkRequestWithdrawn
+import android.net.NetworkProviderTest.TestNetworkProvider.CallbackEntry.OnNetworkRequested
import android.os.Build
import android.os.HandlerThread
import android.os.Looper
-import android.net.NetworkProviderTest.TestNetworkCallback.CallbackEntry.OnUnavailable
-import android.net.NetworkProviderTest.TestNetworkProvider.CallbackEntry.OnNetworkRequested
-import android.net.NetworkProviderTest.TestNetworkProvider.CallbackEntry.OnNetworkRequestWithdrawn
import androidx.test.InstrumentationRegistry
-import com.android.testutils.ArrayTrackRecord
+import com.android.net.module.util.ArrayTrackRecord
import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo
import com.android.testutils.DevSdkIgnoreRunner
-import java.util.UUID
-import kotlin.test.assertEquals
-import kotlin.test.assertNotEquals
import org.junit.After
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
+import java.util.UUID
+import kotlin.test.assertEquals
+import kotlin.test.assertNotEquals
private const val DEFAULT_TIMEOUT_MS = 5000L
private val instrumentation: Instrumentation
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 1e7fecf50d85..0f24b0c1c79b 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -4226,7 +4226,7 @@ public class ConnectivityServiceTest {
callback.expectError(SocketKeepalive.ERROR_INVALID_IP_ADDRESS);
}
- // Sanity check before testing started keepalive.
+ // Basic check before testing started keepalive.
try (SocketKeepalive ka = mCm.createSocketKeepalive(
myNet, testSocket, myIPv4, dstIPv4, executor, callback)) {
ka.start(validKaInterval);
diff --git a/tests/net/java/com/android/server/NetIdManagerTest.kt b/tests/net/java/com/android/server/NetIdManagerTest.kt
index 045f89f85e3b..6f5e740d344c 100644
--- a/tests/net/java/com/android/server/NetIdManagerTest.kt
+++ b/tests/net/java/com/android/server/NetIdManagerTest.kt
@@ -19,8 +19,8 @@ package com.android.server
import androidx.test.filters.SmallTest
import androidx.test.runner.AndroidJUnit4
import com.android.server.NetIdManager.MIN_NET_ID
-import com.android.testutils.ExceptionUtils.ThrowingRunnable
import com.android.testutils.assertThrows
+import com.android.testutils.ExceptionUtils.ThrowingRunnable
import org.junit.Test
import org.junit.runner.RunWith
import kotlin.test.assertEquals
diff --git a/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java b/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
index 5a29c2c96ba7..eb0a867d8ec1 100644
--- a/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
+++ b/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
@@ -26,8 +26,6 @@ import static android.Manifest.permission.UPDATE_DEVICE_STATS;
import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_OEM;
import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_PRODUCT;
import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_VENDOR;
-import static android.content.pm.PackageInfo.REQUESTED_PERMISSION_GRANTED;
-import static android.content.pm.PackageInfo.REQUESTED_PERMISSION_REQUIRED;
import static android.content.pm.PackageManager.GET_PERMISSIONS;
import static android.content.pm.PackageManager.MATCH_ANY_USER;
import static android.os.Process.SYSTEM_UID;
@@ -97,7 +95,6 @@ public class PermissionMonitorTest {
private static final int SYSTEM_UID1 = 1000;
private static final int SYSTEM_UID2 = 1008;
private static final int VPN_UID = 10002;
- private static final String REAL_SYSTEM_PACKAGE_NAME = "android";
private static final String MOCK_PACKAGE1 = "appName1";
private static final String MOCK_PACKAGE2 = "appName2";
private static final String SYSTEM_PACKAGE1 = "sysName1";
@@ -128,6 +125,7 @@ public class PermissionMonitorTest {
new UserInfo(MOCK_USER1, "", 0),
new UserInfo(MOCK_USER2, "", 0),
}));
+ doReturn(PackageManager.PERMISSION_DENIED).when(mDeps).uidPermission(anyString(), anyInt());
mPermissionMonitor = spy(new PermissionMonitor(mContext, mNetdService, mDeps));
@@ -140,35 +138,22 @@ public class PermissionMonitorTest {
verify(mMockPmi).getPackageList(mPermissionMonitor);
}
+ /**
+ * Remove all permissions from the uid then build new package info and setup permissions to uid
+ * for checking restricted network permission.
+ */
private boolean hasRestrictedNetworkPermission(String partition, int targetSdkVersion, int uid,
String... permissions) {
- final PackageInfo packageInfo =
- packageInfoWithPermissions(REQUESTED_PERMISSION_GRANTED, permissions, partition);
+ final PackageInfo packageInfo = buildPackageInfo(partition, uid, MOCK_USER1);
packageInfo.applicationInfo.targetSdkVersion = targetSdkVersion;
- packageInfo.applicationInfo.uid = uid;
- return mPermissionMonitor.hasRestrictedNetworkPermission(packageInfo);
+ removeAllPermissions(uid);
+ addPermissions(uid, permissions);
+ return mPermissionMonitor.hasRestrictedNetworkPermission(packageInfo.applicationInfo);
}
- private static PackageInfo systemPackageInfoWithPermissions(String... permissions) {
- return packageInfoWithPermissions(
- REQUESTED_PERMISSION_GRANTED, permissions, PARTITION_SYSTEM);
- }
-
- private static PackageInfo vendorPackageInfoWithPermissions(String... permissions) {
- return packageInfoWithPermissions(
- REQUESTED_PERMISSION_GRANTED, permissions, PARTITION_VENDOR);
- }
-
- private static PackageInfo packageInfoWithPermissions(int permissionsFlags,
- String[] permissions, String partition) {
- int[] requestedPermissionsFlags = new int[permissions.length];
- for (int i = 0; i < permissions.length; i++) {
- requestedPermissionsFlags[i] = permissionsFlags;
- }
+ private static PackageInfo packageInfoWithPartition(String partition) {
final PackageInfo packageInfo = new PackageInfo();
- packageInfo.requestedPermissions = permissions;
packageInfo.applicationInfo = new ApplicationInfo();
- packageInfo.requestedPermissionsFlags = requestedPermissionsFlags;
int privateFlags = 0;
switch (partition) {
case PARTITION_OEM:
@@ -185,85 +170,65 @@ public class PermissionMonitorTest {
return packageInfo;
}
- private static PackageInfo buildPackageInfo(boolean hasSystemPermission, int uid, int userId) {
- final PackageInfo pkgInfo;
- if (hasSystemPermission) {
- pkgInfo = systemPackageInfoWithPermissions(
- CHANGE_NETWORK_STATE, NETWORK_STACK, CONNECTIVITY_USE_RESTRICTED_NETWORKS);
- } else {
- pkgInfo = packageInfoWithPermissions(REQUESTED_PERMISSION_GRANTED, new String[] {}, "");
- }
+ private static PackageInfo buildPackageInfo(String partition, int uid, int userId) {
+ final PackageInfo pkgInfo = packageInfoWithPartition(partition);
pkgInfo.applicationInfo.uid = UserHandle.getUid(userId, UserHandle.getAppId(uid));
return pkgInfo;
}
+ /** This will REMOVE all previously set permissions from given uid. */
+ private void removeAllPermissions(int uid) {
+ doReturn(PackageManager.PERMISSION_DENIED).when(mDeps).uidPermission(anyString(), eq(uid));
+ }
+
+ /** Set up mocks so that given UID has the requested permissions. */
+ private void addPermissions(int uid, String... permissions) {
+ for (String permission : permissions) {
+ doReturn(PackageManager.PERMISSION_GRANTED)
+ .when(mDeps).uidPermission(eq(permission), eq(uid));
+ }
+ }
+
@Test
public void testHasPermission() {
- PackageInfo app = systemPackageInfoWithPermissions();
- assertFalse(mPermissionMonitor.hasPermission(app, CHANGE_NETWORK_STATE));
- assertFalse(mPermissionMonitor.hasPermission(app, NETWORK_STACK));
- assertFalse(mPermissionMonitor.hasPermission(app, CONNECTIVITY_USE_RESTRICTED_NETWORKS));
- assertFalse(mPermissionMonitor.hasPermission(app, CONNECTIVITY_INTERNAL));
-
- app = systemPackageInfoWithPermissions(CHANGE_NETWORK_STATE, NETWORK_STACK);
- assertTrue(mPermissionMonitor.hasPermission(app, CHANGE_NETWORK_STATE));
- assertTrue(mPermissionMonitor.hasPermission(app, NETWORK_STACK));
- assertFalse(mPermissionMonitor.hasPermission(app, CONNECTIVITY_USE_RESTRICTED_NETWORKS));
- assertFalse(mPermissionMonitor.hasPermission(app, CONNECTIVITY_INTERNAL));
-
- app = systemPackageInfoWithPermissions(
- CONNECTIVITY_USE_RESTRICTED_NETWORKS, CONNECTIVITY_INTERNAL);
- assertFalse(mPermissionMonitor.hasPermission(app, CHANGE_NETWORK_STATE));
- assertFalse(mPermissionMonitor.hasPermission(app, NETWORK_STACK));
- assertTrue(mPermissionMonitor.hasPermission(app, CONNECTIVITY_USE_RESTRICTED_NETWORKS));
- assertTrue(mPermissionMonitor.hasPermission(app, CONNECTIVITY_INTERNAL));
-
- app = packageInfoWithPermissions(REQUESTED_PERMISSION_REQUIRED, new String[] {
- CONNECTIVITY_USE_RESTRICTED_NETWORKS, CONNECTIVITY_INTERNAL, NETWORK_STACK },
- PARTITION_SYSTEM);
- assertFalse(mPermissionMonitor.hasPermission(app, CHANGE_NETWORK_STATE));
- assertFalse(mPermissionMonitor.hasPermission(app, NETWORK_STACK));
- assertFalse(mPermissionMonitor.hasPermission(app, CONNECTIVITY_USE_RESTRICTED_NETWORKS));
- assertFalse(mPermissionMonitor.hasPermission(app, CONNECTIVITY_INTERNAL));
-
- app = systemPackageInfoWithPermissions(CHANGE_NETWORK_STATE);
- app.requestedPermissions = null;
- assertFalse(mPermissionMonitor.hasPermission(app, CHANGE_NETWORK_STATE));
-
- app = systemPackageInfoWithPermissions(CHANGE_NETWORK_STATE);
- app.requestedPermissionsFlags = null;
- assertFalse(mPermissionMonitor.hasPermission(app, CHANGE_NETWORK_STATE));
+ addPermissions(MOCK_UID1);
+ assertFalse(mPermissionMonitor.hasPermission(CHANGE_NETWORK_STATE, MOCK_UID1));
+ assertFalse(mPermissionMonitor.hasPermission(NETWORK_STACK, MOCK_UID1));
+ assertFalse(mPermissionMonitor.hasPermission(
+ CONNECTIVITY_USE_RESTRICTED_NETWORKS, MOCK_UID1));
+ assertFalse(mPermissionMonitor.hasPermission(CONNECTIVITY_INTERNAL, MOCK_UID1));
+
+ addPermissions(MOCK_UID1, CHANGE_NETWORK_STATE, NETWORK_STACK);
+ assertTrue(mPermissionMonitor.hasPermission(CHANGE_NETWORK_STATE, MOCK_UID1));
+ assertTrue(mPermissionMonitor.hasPermission(NETWORK_STACK, MOCK_UID1));
+ assertFalse(mPermissionMonitor.hasPermission(
+ CONNECTIVITY_USE_RESTRICTED_NETWORKS, MOCK_UID1));
+ assertFalse(mPermissionMonitor.hasPermission(CONNECTIVITY_INTERNAL, MOCK_UID1));
+ assertFalse(mPermissionMonitor.hasPermission(CHANGE_NETWORK_STATE, MOCK_UID2));
+ assertFalse(mPermissionMonitor.hasPermission(NETWORK_STACK, MOCK_UID2));
+
+ addPermissions(MOCK_UID2, CONNECTIVITY_USE_RESTRICTED_NETWORKS, CONNECTIVITY_INTERNAL);
+ assertFalse(mPermissionMonitor.hasPermission(
+ CONNECTIVITY_USE_RESTRICTED_NETWORKS, MOCK_UID1));
+ assertFalse(mPermissionMonitor.hasPermission(CONNECTIVITY_INTERNAL, MOCK_UID1));
+ assertTrue(mPermissionMonitor.hasPermission(
+ CONNECTIVITY_USE_RESTRICTED_NETWORKS, MOCK_UID2));
+ assertTrue(mPermissionMonitor.hasPermission(CONNECTIVITY_INTERNAL, MOCK_UID2));
}
@Test
public void testIsVendorApp() {
- PackageInfo app = systemPackageInfoWithPermissions();
+ PackageInfo app = packageInfoWithPartition(PARTITION_SYSTEM);
assertFalse(mPermissionMonitor.isVendorApp(app.applicationInfo));
- app = packageInfoWithPermissions(REQUESTED_PERMISSION_GRANTED,
- new String[] {}, PARTITION_OEM);
+ app = packageInfoWithPartition(PARTITION_OEM);
assertTrue(mPermissionMonitor.isVendorApp(app.applicationInfo));
- app = packageInfoWithPermissions(REQUESTED_PERMISSION_GRANTED,
- new String[] {}, PARTITION_PRODUCT);
+ app = packageInfoWithPartition(PARTITION_PRODUCT);
assertTrue(mPermissionMonitor.isVendorApp(app.applicationInfo));
- app = vendorPackageInfoWithPermissions();
+ app = packageInfoWithPartition(PARTITION_VENDOR);
assertTrue(mPermissionMonitor.isVendorApp(app.applicationInfo));
}
@Test
- public void testHasNetworkPermission() {
- PackageInfo app = systemPackageInfoWithPermissions();
- assertFalse(mPermissionMonitor.hasNetworkPermission(app));
- app = systemPackageInfoWithPermissions(CHANGE_NETWORK_STATE);
- assertTrue(mPermissionMonitor.hasNetworkPermission(app));
- app = systemPackageInfoWithPermissions(NETWORK_STACK);
- assertFalse(mPermissionMonitor.hasNetworkPermission(app));
- app = systemPackageInfoWithPermissions(CONNECTIVITY_USE_RESTRICTED_NETWORKS);
- assertFalse(mPermissionMonitor.hasNetworkPermission(app));
- app = systemPackageInfoWithPermissions(CONNECTIVITY_INTERNAL);
- assertFalse(mPermissionMonitor.hasNetworkPermission(app));
- }
-
- @Test
public void testHasRestrictedNetworkPermission() {
assertFalse(hasRestrictedNetworkPermission(PARTITION_SYSTEM, VERSION_P, MOCK_UID1));
assertFalse(hasRestrictedNetworkPermission(
@@ -323,30 +288,27 @@ public class PermissionMonitorTest {
private void assertBackgroundPermission(boolean hasPermission, String name, int uid,
String... permissions) throws Exception {
when(mPackageManager.getPackageInfo(eq(name), anyInt()))
- .thenReturn(packageInfoWithPermissions(
- REQUESTED_PERMISSION_GRANTED, permissions, PARTITION_SYSTEM));
+ .thenReturn(buildPackageInfo(PARTITION_SYSTEM, uid, MOCK_USER1));
+ addPermissions(uid, permissions);
mPermissionMonitor.onPackageAdded(name, uid);
assertEquals(hasPermission, mPermissionMonitor.hasUseBackgroundNetworksPermission(uid));
}
@Test
public void testHasUseBackgroundNetworksPermission() throws Exception {
+ doReturn(VERSION_Q).when(mDeps).getDeviceFirstSdkInt();
assertFalse(mPermissionMonitor.hasUseBackgroundNetworksPermission(SYSTEM_UID));
- assertBackgroundPermission(false, SYSTEM_PACKAGE1, SYSTEM_UID);
- assertBackgroundPermission(false, SYSTEM_PACKAGE1, SYSTEM_UID, CONNECTIVITY_INTERNAL);
- assertBackgroundPermission(true, SYSTEM_PACKAGE1, SYSTEM_UID, CHANGE_NETWORK_STATE);
- assertBackgroundPermission(true, SYSTEM_PACKAGE1, SYSTEM_UID, NETWORK_STACK);
+ assertBackgroundPermission(false, "system1", SYSTEM_UID);
+ assertBackgroundPermission(false, "system2", SYSTEM_UID, CONNECTIVITY_INTERNAL);
+ assertBackgroundPermission(true, "system3", SYSTEM_UID, CHANGE_NETWORK_STATE);
assertFalse(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID1));
- assertBackgroundPermission(false, MOCK_PACKAGE1, MOCK_UID1);
- assertBackgroundPermission(true, MOCK_PACKAGE1, MOCK_UID1,
- CONNECTIVITY_USE_RESTRICTED_NETWORKS);
+ assertBackgroundPermission(false, "mock1", MOCK_UID1);
+ assertBackgroundPermission(true, "mock2", MOCK_UID1, CONNECTIVITY_USE_RESTRICTED_NETWORKS);
assertFalse(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID2));
- assertBackgroundPermission(false, MOCK_PACKAGE2, MOCK_UID2);
- assertBackgroundPermission(false, MOCK_PACKAGE2, MOCK_UID2,
- CONNECTIVITY_INTERNAL);
- assertBackgroundPermission(true, MOCK_PACKAGE2, MOCK_UID2, NETWORK_STACK);
+ assertBackgroundPermission(false, "mock3", MOCK_UID2, CONNECTIVITY_INTERNAL);
+ assertBackgroundPermission(true, "mock4", MOCK_UID2, NETWORK_STACK);
}
private class NetdMonitor {
@@ -416,13 +378,14 @@ public class PermissionMonitorTest {
// MOCK_UID1: MOCK_PACKAGE1 only has network permission.
// SYSTEM_UID: SYSTEM_PACKAGE1 has system permission.
// SYSTEM_UID: SYSTEM_PACKAGE2 only has network permission.
- doReturn(SYSTEM).when(mPermissionMonitor).highestPermissionForUid(eq(SYSTEM), anyString());
+ doReturn(SYSTEM).when(mPermissionMonitor).highestPermissionForUid(eq(SYSTEM),
+ anyString(), anyInt());
doReturn(SYSTEM).when(mPermissionMonitor).highestPermissionForUid(any(),
- eq(SYSTEM_PACKAGE1));
+ eq(SYSTEM_PACKAGE1), anyInt());
doReturn(NETWORK).when(mPermissionMonitor).highestPermissionForUid(any(),
- eq(SYSTEM_PACKAGE2));
+ eq(SYSTEM_PACKAGE2), anyInt());
doReturn(NETWORK).when(mPermissionMonitor).highestPermissionForUid(any(),
- eq(MOCK_PACKAGE1));
+ eq(MOCK_PACKAGE1), anyInt());
// Add SYSTEM_PACKAGE2, expect only have network permission.
mPermissionMonitor.onUserAdded(MOCK_USER1);
@@ -473,13 +436,15 @@ public class PermissionMonitorTest {
public void testUidFilteringDuringVpnConnectDisconnectAndUidUpdates() throws Exception {
when(mPackageManager.getInstalledPackages(eq(GET_PERMISSIONS | MATCH_ANY_USER))).thenReturn(
Arrays.asList(new PackageInfo[] {
- buildPackageInfo(/* SYSTEM */ true, SYSTEM_UID1, MOCK_USER1),
- buildPackageInfo(/* SYSTEM */ false, MOCK_UID1, MOCK_USER1),
- buildPackageInfo(/* SYSTEM */ false, MOCK_UID2, MOCK_USER1),
- buildPackageInfo(/* SYSTEM */ false, VPN_UID, MOCK_USER1)
+ buildPackageInfo(PARTITION_SYSTEM, SYSTEM_UID1, MOCK_USER1),
+ buildPackageInfo(PARTITION_SYSTEM, MOCK_UID1, MOCK_USER1),
+ buildPackageInfo(PARTITION_SYSTEM, MOCK_UID2, MOCK_USER1),
+ buildPackageInfo(PARTITION_SYSTEM, VPN_UID, MOCK_USER1)
}));
when(mPackageManager.getPackageInfo(eq(MOCK_PACKAGE1), eq(GET_PERMISSIONS))).thenReturn(
- buildPackageInfo(false, MOCK_UID1, MOCK_USER1));
+ buildPackageInfo(PARTITION_SYSTEM, MOCK_UID1, MOCK_USER1));
+ addPermissions(SYSTEM_UID,
+ CHANGE_NETWORK_STATE, NETWORK_STACK, CONNECTIVITY_USE_RESTRICTED_NETWORKS);
mPermissionMonitor.startMonitoring();
// Every app on user 0 except MOCK_UID2 are under VPN.
final Set<UidRange> vpnRange1 = new HashSet<>(Arrays.asList(new UidRange[] {
@@ -524,11 +489,11 @@ public class PermissionMonitorTest {
public void testUidFilteringDuringPackageInstallAndUninstall() throws Exception {
when(mPackageManager.getInstalledPackages(eq(GET_PERMISSIONS | MATCH_ANY_USER))).thenReturn(
Arrays.asList(new PackageInfo[] {
- buildPackageInfo(true, SYSTEM_UID1, MOCK_USER1),
- buildPackageInfo(false, VPN_UID, MOCK_USER1)
+ buildPackageInfo(PARTITION_SYSTEM, SYSTEM_UID1, MOCK_USER1),
+ buildPackageInfo(PARTITION_SYSTEM, VPN_UID, MOCK_USER1)
}));
when(mPackageManager.getPackageInfo(eq(MOCK_PACKAGE1), eq(GET_PERMISSIONS))).thenReturn(
- buildPackageInfo(false, MOCK_UID1, MOCK_USER1));
+ buildPackageInfo(PARTITION_SYSTEM, MOCK_UID1, MOCK_USER1));
mPermissionMonitor.startMonitoring();
final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(MOCK_USER1));
@@ -633,10 +598,10 @@ public class PermissionMonitorTest {
private PackageInfo setPackagePermissions(String packageName, int uid, String[] permissions)
throws Exception {
- PackageInfo packageInfo = packageInfoWithPermissions(
- REQUESTED_PERMISSION_GRANTED, permissions, PARTITION_SYSTEM);
+ final PackageInfo packageInfo = buildPackageInfo(PARTITION_SYSTEM, uid, MOCK_USER1);
when(mPackageManager.getPackageInfo(eq(packageName), anyInt())).thenReturn(packageInfo);
when(mPackageManager.getPackagesForUid(eq(uid))).thenReturn(new String[]{packageName});
+ addPermissions(uid, permissions);
return packageInfo;
}
@@ -663,14 +628,13 @@ public class PermissionMonitorTest {
public void testPackageInstallSharedUid() throws Exception {
final NetdServiceMonitor mNetdServiceMonitor = new NetdServiceMonitor(mNetdService);
- PackageInfo packageInfo1 = addPackage(MOCK_PACKAGE1, MOCK_UID1,
- new String[] {INTERNET, UPDATE_DEVICE_STATS});
+ addPackage(MOCK_PACKAGE1, MOCK_UID1, new String[] {INTERNET, UPDATE_DEVICE_STATS});
mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET
| INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1});
// Install another package with the same uid and no permissions should not cause the UID to
// lose permissions.
- PackageInfo packageInfo2 = systemPackageInfoWithPermissions();
+ final PackageInfo packageInfo2 = buildPackageInfo(PARTITION_SYSTEM, MOCK_UID1, MOCK_USER1);
when(mPackageManager.getPackageInfo(eq(MOCK_PACKAGE2), anyInt())).thenReturn(packageInfo2);
when(mPackageManager.getPackagesForUid(MOCK_UID1))
.thenReturn(new String[]{MOCK_PACKAGE1, MOCK_PACKAGE2});
@@ -701,6 +665,7 @@ public class PermissionMonitorTest {
| INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1});
when(mPackageManager.getPackagesForUid(MOCK_UID1)).thenReturn(new String[]{});
+ removeAllPermissions(MOCK_UID1);
mPermissionMonitor.onPackageRemoved(MOCK_PACKAGE1, MOCK_UID1);
mNetdServiceMonitor.expectPermission(INetd.PERMISSION_UNINSTALLED, new int[]{MOCK_UID1});
@@ -728,10 +693,12 @@ public class PermissionMonitorTest {
| INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1});
// Mock another package with the same uid but different permissions.
- PackageInfo packageInfo2 = systemPackageInfoWithPermissions(INTERNET);
+ final PackageInfo packageInfo2 = buildPackageInfo(PARTITION_SYSTEM, MOCK_UID1, MOCK_USER1);
when(mPackageManager.getPackageInfo(eq(MOCK_PACKAGE2), anyInt())).thenReturn(packageInfo2);
when(mPackageManager.getPackagesForUid(MOCK_UID1)).thenReturn(new String[]{
MOCK_PACKAGE2});
+ removeAllPermissions(MOCK_UID1);
+ addPermissions(MOCK_UID1, INTERNET);
mPermissionMonitor.onPackageRemoved(MOCK_PACKAGE1, MOCK_UID1);
mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET, new int[]{MOCK_UID1});
@@ -743,9 +710,6 @@ public class PermissionMonitorTest {
// necessary permission.
final Context realContext = InstrumentationRegistry.getContext();
final PermissionMonitor monitor = new PermissionMonitor(realContext, mNetdService);
- final PackageManager manager = realContext.getPackageManager();
- final PackageInfo systemInfo = manager.getPackageInfo(REAL_SYSTEM_PACKAGE_NAME,
- GET_PERMISSIONS | MATCH_ANY_USER);
- assertTrue(monitor.hasPermission(systemInfo, CONNECTIVITY_USE_RESTRICTED_NETWORKS));
+ assertTrue(monitor.hasPermission(CONNECTIVITY_USE_RESTRICTED_NETWORKS, SYSTEM_UID));
}
}
diff --git a/tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java b/tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java
index 551498f2c0cc..e83d2a90bffa 100644
--- a/tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java
+++ b/tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java
@@ -23,11 +23,12 @@ import static android.net.NetworkStats.TAG_NONE;
import static android.net.NetworkStats.UID_ALL;
import static android.net.NetworkStatsHistory.FIELD_ALL;
import static android.net.NetworkTemplate.buildTemplateMobileAll;
+import static android.net.NetworkUtils.multiplySafeByRational;
import static android.os.Process.myUid;
import static android.text.format.DateUtils.HOUR_IN_MILLIS;
import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
-import static com.android.server.net.NetworkStatsCollection.multiplySafe;
+import static com.android.testutils.MiscAssertsKt.assertThrows;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
@@ -505,23 +506,25 @@ public class NetworkStatsCollectionTest {
}
@Test
- public void testMultiplySafe() {
- assertEquals(25, multiplySafe(50, 1, 2));
- assertEquals(100, multiplySafe(50, 2, 1));
+ public void testMultiplySafeRational() {
+ assertEquals(25, multiplySafeByRational(50, 1, 2));
+ assertEquals(100, multiplySafeByRational(50, 2, 1));
- assertEquals(-10, multiplySafe(30, -1, 3));
- assertEquals(0, multiplySafe(30, 0, 3));
- assertEquals(10, multiplySafe(30, 1, 3));
- assertEquals(20, multiplySafe(30, 2, 3));
- assertEquals(30, multiplySafe(30, 3, 3));
- assertEquals(40, multiplySafe(30, 4, 3));
+ assertEquals(-10, multiplySafeByRational(30, -1, 3));
+ assertEquals(0, multiplySafeByRational(30, 0, 3));
+ assertEquals(10, multiplySafeByRational(30, 1, 3));
+ assertEquals(20, multiplySafeByRational(30, 2, 3));
+ assertEquals(30, multiplySafeByRational(30, 3, 3));
+ assertEquals(40, multiplySafeByRational(30, 4, 3));
assertEquals(100_000_000_000L,
- multiplySafe(300_000_000_000L, 10_000_000_000L, 30_000_000_000L));
+ multiplySafeByRational(300_000_000_000L, 10_000_000_000L, 30_000_000_000L));
assertEquals(100_000_000_010L,
- multiplySafe(300_000_000_000L, 10_000_000_001L, 30_000_000_000L));
+ multiplySafeByRational(300_000_000_000L, 10_000_000_001L, 30_000_000_000L));
assertEquals(823_202_048L,
- multiplySafe(4_939_212_288L, 2_121_815_528L, 12_730_893_165L));
+ multiplySafeByRational(4_939_212_288L, 2_121_815_528L, 12_730_893_165L));
+
+ assertThrows(ArithmeticException.class, () -> multiplySafeByRational(30, 3, 0));
}
/**
diff --git a/tests/utils/DummyIME/Android.bp b/tests/utils/StubIME/Android.bp
index 4a44b3b27992..668c92c86c51 100644
--- a/tests/utils/DummyIME/Android.bp
+++ b/tests/utils/StubIME/Android.bp
@@ -15,7 +15,7 @@
//
android_test {
- name: "DummyIME",
+ name: "StubIME",
srcs: ["src/**/*.java"],
sdk_version: "current",
}
diff --git a/tests/utils/DummyIME/AndroidManifest.xml b/tests/utils/StubIME/AndroidManifest.xml
index 4dc0b57e1075..bc64c671d9be 100644
--- a/tests/utils/DummyIME/AndroidManifest.xml
+++ b/tests/utils/StubIME/AndroidManifest.xml
@@ -18,20 +18,20 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.testing.dummyime">
+ package="com.android.testing.stubime">
<application android:label="Dummy IME">
<service android:name="DummyIme"
- android:permission="android.permission.BIND_INPUT_METHOD"
- android:exported="true">
+ android:permission="android.permission.BIND_INPUT_METHOD"
+ android:exported="true">
<intent-filter>
<action android:name="android.view.InputMethod"/>
</intent-filter>
<meta-data android:name="android.view.im"
- android:resource="@xml/method"/>
+ android:resource="@xml/method"/>
</service>
<activity android:name=".ImePreferences"
- android:label="Dummy IME Settings"
- android:exported="true">
+ android:label="Stub IME Settings"
+ android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
</intent-filter>
diff --git a/tests/utils/DummyIME/res/xml/method.xml b/tests/utils/StubIME/res/xml/method.xml
index 43a330e2bc93..1bb4bcd3480b 100644
--- a/tests/utils/DummyIME/res/xml/method.xml
+++ b/tests/utils/StubIME/res/xml/method.xml
@@ -21,9 +21,9 @@
<!-- for the Search Manager. -->
<input-method xmlns:android="http://schemas.android.com/apk/res/android"
- android:settingsActivity="com.android.testing.dummyime.ImePreferences">
+ android:settingsActivity="com.android.testing.stubime.ImePreferences">
<subtype
android:label="Generic"
android:imeSubtypeLocale="en_US"
android:imeSubtypeMode="keyboard" />
-</input-method> \ No newline at end of file
+</input-method>
diff --git a/tests/utils/DummyIME/src/com/android/testing/dummyime/ImePreferences.java b/tests/utils/StubIME/src/com/android/testing/stubime/ImePreferences.java
index 41036ab86596..b77525ad0a43 100644
--- a/tests/utils/DummyIME/src/com/android/testing/dummyime/ImePreferences.java
+++ b/tests/utils/StubIME/src/com/android/testing/stubime/ImePreferences.java
@@ -14,12 +14,12 @@
* limitations under the License.
*/
-package com.android.testing.dummyime;
+package com.android.testing.stubime;
import android.preference.PreferenceActivity;
/**
- * Dummy IME preference activity
+ * Stub IME preference activity
*/
public class ImePreferences extends PreferenceActivity {
diff --git a/tests/utils/DummyIME/src/com/android/testing/dummyime/DummyIme.java b/tests/utils/StubIME/src/com/android/testing/stubime/StubIme.java
index 7b7a39a702e5..8795202b3283 100644
--- a/tests/utils/DummyIME/src/com/android/testing/dummyime/DummyIme.java
+++ b/tests/utils/StubIME/src/com/android/testing/stubime/StubIme.java
@@ -14,14 +14,14 @@
* limitations under the License.
*/
-package com.android.testing.dummyime;
+package com.android.testing.stubime;
import android.inputmethodservice.InputMethodService;
/**
- * Dummy IME implementation that basically does nothing
+ * Stub IME implementation that basically does nothing
*/
-public class DummyIme extends InputMethodService {
+public class StubIme extends InputMethodService {
@Override
public boolean onEvaluateFullscreenMode() {
diff --git a/tools/hiddenapi/generate_hiddenapi_lists.py b/tools/hiddenapi/generate_hiddenapi_lists.py
index de6b4785ec37..8a282e5f0821 100755
--- a/tools/hiddenapi/generate_hiddenapi_lists.py
+++ b/tools/hiddenapi/generate_hiddenapi_lists.py
@@ -13,9 +13,7 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
-"""
-Generate API lists for non-SDK API enforcement.
-"""
+"""Generate API lists for non-SDK API enforcement."""
import argparse
from collections import defaultdict
import functools
@@ -24,27 +22,47 @@ import re
import sys
# Names of flags recognized by the `hiddenapi` tool.
-FLAG_WHITELIST = "whitelist"
-FLAG_GREYLIST = "greylist"
-FLAG_BLACKLIST = "blacklist"
-FLAG_GREYLIST_MAX_O = "greylist-max-o"
-FLAG_GREYLIST_MAX_P = "greylist-max-p"
-FLAG_GREYLIST_MAX_Q = "greylist-max-q"
-FLAG_GREYLIST_MAX_R = "greylist-max-r"
-FLAG_CORE_PLATFORM_API = "core-platform-api"
-FLAG_PUBLIC_API = "public-api"
-FLAG_SYSTEM_API = "system-api"
-FLAG_TEST_API = "test-api"
+FLAG_SDK = 'sdk'
+FLAG_UNSUPPORTED = 'unsupported'
+FLAG_BLOCKED = 'blocked'
+FLAG_MAX_TARGET_O = 'max-target-o'
+FLAG_MAX_TARGET_P = 'max-target-p'
+FLAG_MAX_TARGET_Q = 'max-target-q'
+FLAG_MAX_TARGET_R = 'max-target-r'
+FLAG_CORE_PLATFORM_API = 'core-platform-api'
+FLAG_PUBLIC_API = 'public-api'
+FLAG_SYSTEM_API = 'system-api'
+FLAG_TEST_API = 'test-api'
+
+OLD_FLAG_SDK = "whitelist"
+OLD_FLAG_UNSUPPORTED = "greylist"
+OLD_FLAG_BLOCKED = "blacklist"
+OLD_FLAG_MAX_TARGET_O = "greylist-max-o"
+OLD_FLAG_MAX_TARGET_P = "greylist-max-p"
+OLD_FLAG_MAX_TARGET_Q = "greylist-max-q"
+OLD_FLAG_MAX_TARGET_R = "greylist-max-r"
+
+OLD_FLAGS_TO_NEW = {
+ OLD_FLAG_SDK: FLAG_SDK,
+ OLD_FLAG_UNSUPPORTED: FLAG_UNSUPPORTED,
+ OLD_FLAG_BLOCKED: FLAG_BLOCKED,
+ OLD_FLAG_MAX_TARGET_O: FLAG_MAX_TARGET_O,
+ OLD_FLAG_MAX_TARGET_P: FLAG_MAX_TARGET_P,
+ OLD_FLAG_MAX_TARGET_Q: FLAG_MAX_TARGET_Q,
+ OLD_FLAG_MAX_TARGET_R: FLAG_MAX_TARGET_R,
+}
+
+NEW_FLAGS_TO_OLD = dict(zip(OLD_FLAGS_TO_NEW.values(), OLD_FLAGS_TO_NEW.keys()))
# List of all known flags.
FLAGS_API_LIST = [
- FLAG_WHITELIST,
- FLAG_GREYLIST,
- FLAG_BLACKLIST,
- FLAG_GREYLIST_MAX_O,
- FLAG_GREYLIST_MAX_P,
- FLAG_GREYLIST_MAX_Q,
- FLAG_GREYLIST_MAX_R,
+ FLAG_SDK,
+ FLAG_UNSUPPORTED,
+ FLAG_BLOCKED,
+ FLAG_MAX_TARGET_O,
+ FLAG_MAX_TARGET_P,
+ FLAG_MAX_TARGET_Q,
+ FLAG_MAX_TARGET_R,
]
ALL_FLAGS = FLAGS_API_LIST + [
FLAG_CORE_PLATFORM_API,
@@ -58,7 +76,7 @@ ALL_FLAGS_SET = set(ALL_FLAGS)
# Suffix used in command line args to express that only known and
# otherwise unassigned entries should be assign the given flag.
-# For example, the P dark greylist is checked in as it was in P,
+# For example, the max-target-P list is checked in as it was in P,
# but signatures have changes since then. The flag instructs this
# script to skip any entries which do not exist any more.
FLAG_IGNORE_CONFLICTS_SUFFIX = "-ignore-conflicts"
@@ -87,6 +105,7 @@ SERIALIZATION_REGEX = re.compile(r'.*->(' + '|'.join(SERIALIZATION_PATTERNS) + r
HAS_NO_API_LIST_ASSIGNED = lambda api, flags: not FLAGS_API_LIST_SET.intersection(flags)
IS_SERIALIZATION = lambda api, flags: SERIALIZATION_REGEX.match(api)
+
def get_args():
"""Parses command line arguments.
@@ -113,6 +132,7 @@ def get_args():
return parser.parse_args()
+
def read_lines(filename):
"""Reads entire file and return it as a list of lines.
@@ -130,8 +150,9 @@ def read_lines(filename):
lines = map(lambda line: line.strip(), lines)
return set(lines)
+
def write_lines(filename, lines):
- """Writes list of lines into a file, overwriting the file it it exists.
+ """Writes list of lines into a file, overwriting the file if it exists.
Args:
filename (string): Path to the file to be writting into.
@@ -141,6 +162,7 @@ def write_lines(filename, lines):
with open(filename, 'w') as f:
f.writelines(lines)
+
def extract_package(signature):
"""Extracts the package from a signature.
@@ -159,6 +181,7 @@ def extract_package(signature):
package_name = full_class_name.rpartition("/")[0]
return package_name.replace('/', '.')
+
class FlagsDict:
def __init__(self):
self._dict_keyset = set()
@@ -182,6 +205,36 @@ class FlagsDict:
"Please visit go/hiddenapi for more information.").format(
source, "\n".join(flags_subset - ALL_FLAGS_SET))
+ def convert_to_new_flag(self, flag):
+ """Converts old flag to a new variant.
+
+ Flags that are considered old are replaced with new versions.
+ Otherwise, it is a no-op.
+
+ Args:
+ flag: a string, representing SDK flag.
+
+ Returns:
+ A string. Result of conversion.
+
+ """
+ return OLD_FLAGS_TO_NEW.get(flag, flag)
+
+ def convert_to_old_flag(self, flag):
+ """Converts a new flag to a old variant.
+
+ No-op if there is no suitable old flag.
+ Only used to support backwards compatibility.
+
+ Args:
+ flag: a string, representing SDK flag.
+
+ Returns:
+ A string. Result of conversion.
+
+ """
+ return NEW_FLAGS_TO_OLD.get(flag, flag)
+
def filter_apis(self, filter_fn):
"""Returns APIs which match a given predicate.
@@ -212,10 +265,16 @@ class FlagsDict:
def generate_csv(self):
"""Constructs CSV entries from a dictionary.
+ Old versions of flags are used to generate the file.
+
Returns:
List of lines comprising a CSV file. See "parse_and_merge_csv" for format description.
"""
- return sorted(map(lambda api: ",".join([api] + sorted(self._dict[api])), self._dict))
+ lines = []
+ for api in self._dict:
+ flags = sorted([self.convert_to_old_flag(flag) for flag in self._dict[api]])
+ lines.append(",".join([api] + flags))
+ return sorted(lines)
def parse_and_merge_csv(self, csv_lines, source = "<unknown>"):
"""Parses CSV entries and merges them into a given dictionary.
@@ -237,17 +296,16 @@ class FlagsDict:
self._dict_keyset.update([ csv[0] for csv in csv_values ])
# Check that all flags are known.
- csv_flags = set(functools.reduce(
- lambda x, y: set(x).union(y),
- [ csv[1:] for csv in csv_values ],
- []))
+ csv_flags = set()
+ for csv in csv_values:
+ csv_flags.update([self.convert_to_new_flag(flag) for flag in csv[1:]])
self._check_flags_set(csv_flags, source)
# Iterate over all CSV lines, find entry in dict and append flags to it.
for csv in csv_values:
- flags = csv[1:]
+ flags = [self.convert_to_new_flag(flag) for flag in csv[1:]]
if (FLAG_PUBLIC_API in flags) or (FLAG_SYSTEM_API in flags):
- flags.append(FLAG_WHITELIST)
+ flags.append(FLAG_SDK)
self._dict[csv[0]].update(flags)
def assign_flag(self, flag, apis, source="<unknown>"):
@@ -271,6 +329,7 @@ class FlagsDict:
for api in apis:
self._dict[api].add(flag)
+
def main(argv):
# Parse arguments.
args = vars(get_args())
@@ -287,8 +346,8 @@ def main(argv):
flags.parse_and_merge_csv(read_lines(filename), filename)
# Combine inputs which do not require any particular order.
- # (1) Assign serialization API to whitelist.
- flags.assign_flag(FLAG_WHITELIST, flags.filter_apis(IS_SERIALIZATION))
+ # (1) Assign serialization API to SDK.
+ flags.assign_flag(FLAG_SDK, flags.filter_apis(IS_SERIALIZATION))
# (2) Merge text files with a known flag into the dictionary.
for flag in ALL_FLAGS:
@@ -314,8 +373,8 @@ def main(argv):
valid_entries = flags.filter_apis(should_add_signature_to_list)
flags.assign_flag(flag, valid_entries)
- # Assign all remaining entries to the blacklist.
- flags.assign_flag(FLAG_BLACKLIST, flags.filter_apis(HAS_NO_API_LIST_ASSIGNED))
+ # Mark all remaining entries as blocked.
+ flags.assign_flag(FLAG_BLOCKED, flags.filter_apis(HAS_NO_API_LIST_ASSIGNED))
# Write output.
write_lines(args["output"], flags.generate_csv())
diff --git a/tools/hiddenapi/generate_hiddenapi_lists_test.py b/tools/hiddenapi/generate_hiddenapi_lists_test.py
index 55c3a7d718db..321c400ef898 100755
--- a/tools/hiddenapi/generate_hiddenapi_lists_test.py
+++ b/tools/hiddenapi/generate_hiddenapi_lists_test.py
@@ -23,7 +23,7 @@ class TestHiddenapiListGeneration(unittest.TestCase):
# Initialize flags so that A and B are put on the whitelist and
# C, D, E are left unassigned. Try filtering for the unassigned ones.
flags = FlagsDict()
- flags.parse_and_merge_csv(['A,' + FLAG_WHITELIST, 'B,' + FLAG_WHITELIST,
+ flags.parse_and_merge_csv(['A,' + FLAG_SDK, 'B,' + FLAG_SDK,
'C', 'D', 'E'])
filter_set = flags.filter_apis(lambda api, flags: not flags)
self.assertTrue(isinstance(filter_set, set))
@@ -32,10 +32,10 @@ class TestHiddenapiListGeneration(unittest.TestCase):
def test_get_valid_subset_of_unassigned_keys(self):
# Create flags where only A is unassigned.
flags = FlagsDict()
- flags.parse_and_merge_csv(['A,' + FLAG_WHITELIST, 'B', 'C'])
- flags.assign_flag(FLAG_GREYLIST, set(['C']))
+ flags.parse_and_merge_csv(['A,' + FLAG_SDK, 'B', 'C'])
+ flags.assign_flag(FLAG_UNSUPPORTED, set(['C']))
self.assertEqual(flags.generate_csv(),
- [ 'A,' + FLAG_WHITELIST, 'B', 'C,' + FLAG_GREYLIST ])
+ [ 'A,' + OLD_FLAG_SDK, 'B', 'C,' + OLD_FLAG_UNSUPPORTED ])
# Check three things:
# (1) B is selected as valid unassigned
@@ -50,20 +50,21 @@ class TestHiddenapiListGeneration(unittest.TestCase):
# Test empty CSV entry.
self.assertEqual(flags.generate_csv(), [])
- # Test new additions.
+ # Test new additions. CSV generator produces values with old flags
+ # to be backwards compatible.
flags.parse_and_merge_csv([
- 'A,' + FLAG_GREYLIST,
- 'B,' + FLAG_BLACKLIST + ',' + FLAG_GREYLIST_MAX_O,
- 'C,' + FLAG_SYSTEM_API + ',' + FLAG_WHITELIST,
- 'D,' + FLAG_GREYLIST+ ',' + FLAG_TEST_API,
- 'E,' + FLAG_BLACKLIST+ ',' + FLAG_TEST_API,
+ 'A,' + FLAG_UNSUPPORTED,
+ 'B,' + FLAG_BLOCKED + ',' + FLAG_MAX_TARGET_O,
+ 'C,' + FLAG_SDK + ',' + FLAG_SYSTEM_API,
+ 'D,' + FLAG_UNSUPPORTED + ',' + FLAG_TEST_API,
+ 'E,' + FLAG_BLOCKED + ',' + FLAG_TEST_API,
])
self.assertEqual(flags.generate_csv(), [
- 'A,' + FLAG_GREYLIST,
- 'B,' + FLAG_BLACKLIST + "," + FLAG_GREYLIST_MAX_O,
- 'C,' + FLAG_SYSTEM_API + ',' + FLAG_WHITELIST,
- 'D,' + FLAG_GREYLIST+ ',' + FLAG_TEST_API,
- 'E,' + FLAG_BLACKLIST+ ',' + FLAG_TEST_API,
+ 'A,' + OLD_FLAG_UNSUPPORTED,
+ 'B,' + OLD_FLAG_BLOCKED + "," + OLD_FLAG_MAX_TARGET_O,
+ 'C,' + FLAG_SYSTEM_API + ',' + OLD_FLAG_SDK,
+ 'D,' + OLD_FLAG_UNSUPPORTED + ',' + FLAG_TEST_API,
+ 'E,' + OLD_FLAG_BLOCKED + ',' + FLAG_TEST_API,
])
# Test unknown flag.
@@ -72,16 +73,16 @@ class TestHiddenapiListGeneration(unittest.TestCase):
def test_assign_flag(self):
flags = FlagsDict()
- flags.parse_and_merge_csv(['A,' + FLAG_WHITELIST, 'B'])
+ flags.parse_and_merge_csv(['A,' + FLAG_SDK, 'B'])
# Test new additions.
- flags.assign_flag(FLAG_GREYLIST, set([ 'A', 'B' ]))
+ flags.assign_flag(FLAG_UNSUPPORTED, set([ 'A', 'B' ]))
self.assertEqual(flags.generate_csv(),
- [ 'A,' + FLAG_GREYLIST + "," + FLAG_WHITELIST, 'B,' + FLAG_GREYLIST ])
+ [ 'A,' + OLD_FLAG_UNSUPPORTED + "," + OLD_FLAG_SDK, 'B,' + OLD_FLAG_UNSUPPORTED ])
# Test invalid API signature.
with self.assertRaises(AssertionError):
- flags.assign_flag(FLAG_WHITELIST, set([ 'C' ]))
+ flags.assign_flag(FLAG_SDK, set([ 'C' ]))
# Test invalid flag.
with self.assertRaises(AssertionError):
diff --git a/tools/stats_log_api_gen/Android.bp b/tools/stats_log_api_gen/Android.bp
index e3b6db08c503..43387fc054b5 100644
--- a/tools/stats_log_api_gen/Android.bp
+++ b/tools/stats_log_api_gen/Android.bp
@@ -121,10 +121,26 @@ cc_library {
],
target: {
android: {
- shared_libs: ["libstatssocket"],
+ shared_libs: [
+ "libstatssocket",
+ "libstatspull",
+ ],
+ export_shared_lib_headers: [
+ "libstatssocket",
+ "libstatspull",
+ ],
},
host: {
- static_libs: ["libstatssocket"],
+ static_libs: [
+ "libstatssocket",
+ "libstatspull",
+ "statsd-aidl-ndk_platform",
+ ],
+ shared_libs: ["libbinder_ndk"],
+ export_static_lib_headers: [
+ "libstatssocket",
+ "libstatspull",
+ ],
},
},
}
diff --git a/tools/stats_log_api_gen/Collation.cpp b/tools/stats_log_api_gen/Collation.cpp
index 4c741c49cfdb..fe6ca558a0ee 100644
--- a/tools/stats_log_api_gen/Collation.cpp
+++ b/tools/stats_log_api_gen/Collation.cpp
@@ -72,7 +72,7 @@ static void print_error(const FieldDescriptor* field, const char* format, ...) {
SourceLocation loc;
if (field->GetSourceLocation(&loc)) {
- // TODO: this will work if we can figure out how to pass
+ // TODO(b/162454173): this will work if we can figure out how to pass
// --include_source_info to protoc
fprintf(stderr, "%s:%d: ", file->name().c_str(), loc.start_line);
} else {
@@ -111,7 +111,6 @@ static java_type_t java_type(const FieldDescriptor* field) {
case FieldDescriptor::TYPE_GROUP:
return JAVA_TYPE_UNKNOWN;
case FieldDescriptor::TYPE_MESSAGE:
- // TODO: not the final package name
if (field->message_type()->full_name() == "android.os.statsd.AttributionNode") {
return JAVA_TYPE_ATTRIBUTION_CHAIN;
} else if (field->message_type()->full_name() == "android.os.statsd.KeyValuePair") {
@@ -147,7 +146,7 @@ static java_type_t java_type(const FieldDescriptor* field) {
void collate_enums(const EnumDescriptor& enumDescriptor, AtomField* atomField) {
for (int i = 0; i < enumDescriptor.value_count(); i++) {
atomField->enumValues[enumDescriptor.value(i)->number()] =
- enumDescriptor.value(i)->name().c_str();
+ enumDescriptor.value(i)->name();
}
}
@@ -528,7 +527,7 @@ int collate_atoms(const Descriptor* descriptor, const string& moduleName, Atoms*
vector<java_type_t> signature;
errorCount += collate_atom(atom, atomDecl.get(), &signature);
- if (atomDecl->primaryFields.size() != 0 && atomDecl->exclusiveField == 0) {
+ if (!atomDecl->primaryFields.empty() && atomDecl->exclusiveField == 0) {
print_error(atomField, "Cannot have a primary field without an exclusive field: %s\n",
atomField->name().c_str());
errorCount++;
@@ -541,8 +540,7 @@ int collate_atoms(const Descriptor* descriptor, const string& moduleName, Atoms*
atomField->name().c_str());
errorCount++;
continue;
- }
- else if ((oneofAtom->name() != ONEOF_PUSHED_ATOM_NAME) &&
+ } else if ((oneofAtom->name() != ONEOF_PUSHED_ATOM_NAME) &&
(oneofAtom->name() != ONEOF_PULLED_ATOM_NAME)) {
print_error(atomField, "Atom is neither a pushed nor pulled atom: %s\n",
atomField->name().c_str());
@@ -578,7 +576,7 @@ int collate_atoms(const Descriptor* descriptor, const string& moduleName, Atoms*
printf(" ");
for (vector<java_type_t>::const_iterator jt = it->first.begin(); jt != it->first.end();
jt++) {
- printf(" %d", (int)*jt);
+ printf(" %d", static_cast<int>(*jt));
}
printf("\n");
}
@@ -589,7 +587,7 @@ int collate_atoms(const Descriptor* descriptor, const string& moduleName, Atoms*
printf(" ");
for (vector<java_type_t>::const_iterator jt = it->first.begin(); jt != it->first.end();
jt++) {
- printf(" %d", (int)*jt);
+ printf(" %d", static_cast<int>(*jt));
}
printf("\n");
}
diff --git a/tools/stats_log_api_gen/Collation.h b/tools/stats_log_api_gen/Collation.h
index e637ed945a08..5d196c4b8290 100644
--- a/tools/stats_log_api_gen/Collation.h
+++ b/tools/stats_log_api_gen/Collation.h
@@ -47,8 +47,8 @@ const int FIRST_UID_IN_CHAIN_ID = 0;
*
* `OneofDescriptor::name()` returns the name of the oneof.
*/
-const string ONEOF_PUSHED_ATOM_NAME = "pushed";
-const string ONEOF_PULLED_ATOM_NAME = "pulled";
+const char ONEOF_PUSHED_ATOM_NAME[] = "pushed";
+const char ONEOF_PULLED_ATOM_NAME[] = "pulled";
enum AnnotationId : uint8_t {
ANNOTATION_ID_IS_UID = 1,
@@ -63,7 +63,7 @@ enum AnnotationId : uint8_t {
const int ATOM_ID_FIELD_NUMBER = -1;
-const string DEFAULT_MODULE_NAME = "DEFAULT";
+const char DEFAULT_MODULE_NAME[] = "DEFAULT";
/**
* The types for atom parameters.
@@ -95,9 +95,9 @@ union AnnotationValue {
int intValue;
bool boolValue;
- AnnotationValue(const int value) : intValue(value) {
+ explicit AnnotationValue(const int value) : intValue(value) {
}
- AnnotationValue(const bool value) : boolValue(value) {
+ explicit AnnotationValue(const bool value) : boolValue(value) {
}
};
diff --git a/tools/stats_log_api_gen/java_writer.cpp b/tools/stats_log_api_gen/java_writer.cpp
index ffbe9f800736..6fcf267cf39c 100644
--- a/tools/stats_log_api_gen/java_writer.cpp
+++ b/tools/stats_log_api_gen/java_writer.cpp
@@ -42,6 +42,7 @@ static int write_java_q_logger_class(FILE* out, const SignatureInfoMap& signatur
static void write_java_annotation_constants(FILE* out) {
fprintf(out, " // Annotation constants.\n");
+ const map<AnnotationId, string>& ANNOTATION_ID_CONSTANTS = get_annotation_id_constants();
for (const auto& [id, name] : ANNOTATION_ID_CONSTANTS) {
fprintf(out, " public static final byte %s = %hhu;\n", name.c_str(), id);
}
@@ -56,6 +57,7 @@ static void write_annotations(FILE* out, int argIndex,
return;
}
const AtomDeclSet& atomDeclSet = fieldNumberToAtomDeclSetIt->second;
+ const map<AnnotationId, string>& ANNOTATION_ID_CONSTANTS = get_annotation_id_constants();
for (const shared_ptr<AtomDecl>& atomDecl : atomDeclSet) {
const string atomConstant = make_constant_name(atomDecl->name);
fprintf(out, " if (%s == code) {\n", atomConstant.c_str());
@@ -102,7 +104,7 @@ static void write_method_signature(FILE* out, const vector<java_type_t>& signatu
for (vector<java_type_t>::const_iterator arg = signature.begin(); arg != signature.end();
arg++) {
if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
- for (auto chainField : attributionDecl.fields) {
+ for (const auto& chainField : attributionDecl.fields) {
fprintf(out, ", %s[] %s", java_type_name(chainField.javaType),
chainField.name.c_str());
}
@@ -243,13 +245,15 @@ static int write_method_body(FILE* out, const vector<java_type_t>& signature,
return 0;
}
-static int write_java_methods(FILE* out, const SignatureInfoMap& signatureInfoMap,
+static int write_java_pushed_methods(FILE* out, const SignatureInfoMap& signatureInfoMap,
const AtomDecl& attributionDecl, const bool supportQ) {
for (auto signatureInfoMapIt = signatureInfoMap.begin();
signatureInfoMapIt != signatureInfoMap.end(); signatureInfoMapIt++) {
// Print method signature.
fprintf(out, " public static void write(int code");
- write_method_signature(out, signatureInfoMapIt->first, attributionDecl);
+ const vector<java_type_t>& signature = signatureInfoMapIt->first;
+ const FieldNumberToAtomDeclSet& fieldNumberToAtomDeclSet = signatureInfoMapIt->second;
+ write_method_signature(out, signature, attributionDecl);
fprintf(out, ") {\n");
// Print method body.
@@ -259,7 +263,7 @@ static int write_java_methods(FILE* out, const SignatureInfoMap& signatureInfoMa
indent = " ";
}
- int ret = write_method_body(out, signatureInfoMapIt->first, signatureInfoMapIt->second,
+ int ret = write_method_body(out, signature, fieldNumberToAtomDeclSet,
attributionDecl, indent);
if (ret != 0) {
return ret;
@@ -274,8 +278,8 @@ static int write_java_methods(FILE* out, const SignatureInfoMap& signatureInfoMa
fprintf(out, " } else {\n");
fprintf(out, " QLogger.write(code");
int argIndex = 1;
- for (vector<java_type_t>::const_iterator arg = signatureInfoMapIt->first.begin();
- arg != signatureInfoMapIt->first.end(); arg++) {
+ for (vector<java_type_t>::const_iterator arg = signature.begin();
+ arg != signature.end(); arg++) {
if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
const char* uidName = attributionDecl.fields.front().name.c_str();
const char* tagName = attributionDecl.fields.back().name.c_str();
@@ -299,18 +303,20 @@ static int write_java_methods(FILE* out, const SignatureInfoMap& signatureInfoMa
return 0;
}
-static int write_java_build_stats_event_methods(FILE* out, const SignatureInfoMap& signatureInfoMap,
+static int write_java_pulled_methods(FILE* out, const SignatureInfoMap& signatureInfoMap,
const AtomDecl& attributionDecl) {
for (auto signatureInfoMapIt = signatureInfoMap.begin();
signatureInfoMapIt != signatureInfoMap.end(); signatureInfoMapIt++) {
// Print method signature.
fprintf(out, " public static StatsEvent buildStatsEvent(int code");
- write_method_signature(out, signatureInfoMapIt->first, attributionDecl);
+ const vector<java_type_t>& signature = signatureInfoMapIt->first;
+ const FieldNumberToAtomDeclSet& fieldNumberToAtomDeclSet = signatureInfoMapIt->second;
+ write_method_signature(out, signature, attributionDecl);
fprintf(out, ") {\n");
// Print method body.
string indent("");
- int ret = write_method_body(out, signatureInfoMapIt->first, signatureInfoMapIt->second,
+ int ret = write_method_body(out, signature, fieldNumberToAtomDeclSet,
attributionDecl, indent);
if (ret != 0) {
return ret;
@@ -357,9 +363,9 @@ int write_stats_log_java(FILE* out, const Atoms& atoms, const AtomDecl& attribut
// Print write methods.
fprintf(out, " // Write methods\n");
- errors += write_java_methods(out, atoms.signatureInfoMap, attributionDecl, supportQ);
+ errors += write_java_pushed_methods(out, atoms.signatureInfoMap, attributionDecl, supportQ);
errors += write_java_non_chained_methods(out, atoms.nonChainedSignatureInfoMap);
- errors += write_java_build_stats_event_methods(out, atoms.pulledAtomsSignatureInfoMap,
+ errors += write_java_pulled_methods(out, atoms.pulledAtomsSignatureInfoMap,
attributionDecl);
if (supportWorkSource) {
errors += write_java_work_source_methods(out, atoms.signatureInfoMap);
diff --git a/tools/stats_log_api_gen/java_writer.h b/tools/stats_log_api_gen/java_writer.h
index 8b3b50588efc..afd992be6c5e 100644
--- a/tools/stats_log_api_gen/java_writer.h
+++ b/tools/stats_log_api_gen/java_writer.h
@@ -14,7 +14,8 @@
* limitations under the License.
*/
-#pragma once
+#ifndef ANDROID_STATS_LOG_API_GEN_JAVA_WRITER_H
+#define ANDROID_STATS_LOG_API_GEN_JAVA_WRITER_H
#include <stdio.h>
#include <string.h>
@@ -28,11 +29,11 @@
namespace android {
namespace stats_log_api_gen {
-using namespace std;
-
int write_stats_log_java(FILE* out, const Atoms& atoms, const AtomDecl& attributionDecl,
const string& javaClass, const string& javaPackage, const bool supportQ,
const bool supportWorkSource);
} // namespace stats_log_api_gen
} // namespace android
+
+#endif // ANDROID_STATS_LOG_API_GEN_JAVA_WRITER_H
diff --git a/tools/stats_log_api_gen/java_writer_q.cpp b/tools/stats_log_api_gen/java_writer_q.cpp
index d21e2708b724..be7cb4aeb3f8 100644
--- a/tools/stats_log_api_gen/java_writer_q.cpp
+++ b/tools/stats_log_api_gen/java_writer_q.cpp
@@ -65,7 +65,7 @@ int write_java_methods_q_schema(FILE* out, const SignatureInfoMap& signatureInfo
for (vector<java_type_t>::const_iterator arg = signature.begin(); arg != signature.end();
arg++) {
if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
- for (auto chainField : attributionDecl.fields) {
+ for (const auto& chainField : attributionDecl.fields) {
fprintf(out, ", %s[] %s", java_type_name(chainField.javaType),
chainField.name.c_str());
}
@@ -407,7 +407,7 @@ void write_java_helpers_for_q_schema_methods(FILE* out, const AtomDecl& attribut
if (requiredHelpers & JAVA_MODULE_REQUIRES_ATTRIBUTION) {
fprintf(out, "%sprivate static void writeAttributionChain(byte[] buff, int pos",
indent.c_str());
- for (auto chainField : attributionDecl.fields) {
+ for (const auto& chainField : attributionDecl.fields) {
fprintf(out, ", %s[] %s", java_type_name(chainField.javaType), chainField.name.c_str());
}
fprintf(out, ") {\n");
diff --git a/tools/stats_log_api_gen/java_writer_q.h b/tools/stats_log_api_gen/java_writer_q.h
index c511a8436416..622ef3e37bad 100644
--- a/tools/stats_log_api_gen/java_writer_q.h
+++ b/tools/stats_log_api_gen/java_writer_q.h
@@ -14,7 +14,8 @@
* limitations under the License.
*/
-#pragma once
+#ifndef ANDROID_STATS_LOG_API_GEN_JAVA_WRITER_Q_H
+#define ANDROID_STATS_LOG_API_GEN_JAVA_WRITER_Q_H
#include <stdio.h>
#include <string.h>
@@ -28,8 +29,6 @@
namespace android {
namespace stats_log_api_gen {
-using namespace std;
-
void write_java_q_logging_constants(FILE* out, const string& indent);
int write_java_methods_q_schema(FILE* out, const SignatureInfoMap& signatureInfoMap,
@@ -44,3 +43,5 @@ int write_stats_log_java_q_for_module(FILE* out, const Atoms& atoms,
} // namespace stats_log_api_gen
} // namespace android
+
+#endif // ANDROID_STATS_LOG_API_GEN_JAVA_WRITER_Q_H
diff --git a/tools/stats_log_api_gen/main.cpp b/tools/stats_log_api_gen/main.cpp
index b888ce904b31..d21018463868 100644
--- a/tools/stats_log_api_gen/main.cpp
+++ b/tools/stats_log_api_gen/main.cpp
@@ -16,7 +16,6 @@
#include "utils.h"
using namespace google::protobuf;
-using namespace std;
namespace android {
namespace stats_log_api_gen {
@@ -145,7 +144,7 @@ static int run(int argc, char const* const* argv) {
index++;
}
- if (cppFilename.size() == 0 && headerFilename.size() == 0 && javaFilename.size() == 0) {
+ if (cppFilename.empty() && headerFilename.empty() && javaFilename.empty()) {
print_usage();
return 1;
}
@@ -175,9 +174,9 @@ static int run(int argc, char const* const* argv) {
&attributionSignature);
// Write the .cpp file
- if (cppFilename.size() != 0) {
+ if (!cppFilename.empty()) {
FILE* out = fopen(cppFilename.c_str(), "w");
- if (out == NULL) {
+ if (out == nullptr) {
fprintf(stderr, "Unable to open file for write: %s\n", cppFilename.c_str());
return 1;
}
@@ -198,9 +197,9 @@ static int run(int argc, char const* const* argv) {
}
// Write the .h file
- if (headerFilename.size() != 0) {
+ if (!headerFilename.empty()) {
FILE* out = fopen(headerFilename.c_str(), "w");
- if (out == NULL) {
+ if (out == nullptr) {
fprintf(stderr, "Unable to open file for write: %s\n", headerFilename.c_str());
return 1;
}
@@ -214,24 +213,24 @@ static int run(int argc, char const* const* argv) {
}
// Write the .java file
- if (javaFilename.size() != 0) {
- if (javaClass.size() == 0) {
+ if (!javaFilename.empty()) {
+ if (javaClass.empty()) {
fprintf(stderr, "Must supply --javaClass if supplying a Java filename");
return 1;
}
- if (javaPackage.size() == 0) {
+ if (javaPackage.empty()) {
fprintf(stderr, "Must supply --javaPackage if supplying a Java filename");
return 1;
}
- if (moduleName.size() == 0) {
+ if (moduleName.empty()) {
fprintf(stderr, "Must supply --module if supplying a Java filename");
return 1;
}
FILE* out = fopen(javaFilename.c_str(), "w");
- if (out == NULL) {
+ if (out == nullptr) {
fprintf(stderr, "Unable to open file for write: %s\n", javaFilename.c_str());
return 1;
}
diff --git a/tools/stats_log_api_gen/native_writer.cpp b/tools/stats_log_api_gen/native_writer.cpp
index 0c6c0099e459..b4fb8dd8321b 100644
--- a/tools/stats_log_api_gen/native_writer.cpp
+++ b/tools/stats_log_api_gen/native_writer.cpp
@@ -24,6 +24,7 @@ namespace stats_log_api_gen {
static void write_native_annotation_constants(FILE* out) {
fprintf(out, "// Annotation constants.\n");
+ const map<AnnotationId, string>& ANNOTATION_ID_CONSTANTS = get_annotation_id_constants();
for (const auto& [id, name] : ANNOTATION_ID_CONSTANTS) {
fprintf(out, "const uint8_t %s = %hhu;\n", name.c_str(), id);
}
@@ -39,6 +40,7 @@ static void write_annotations(FILE* out, int argIndex,
return;
}
const AtomDeclSet& atomDeclSet = fieldNumberToAtomDeclSetIt->second;
+ const map<AnnotationId, string>& ANNOTATION_ID_CONSTANTS = get_annotation_id_constants();
for (const shared_ptr<AtomDecl>& atomDecl : atomDeclSet) {
const string atomConstant = make_constant_name(atomDecl->name);
fprintf(out, " if (%s == code) {\n", atomConstant.c_str());
@@ -60,8 +62,6 @@ static void write_annotations(FILE* out, int argIndex,
}
break;
case ANNOTATION_TYPE_BOOL:
- // TODO(b/151786433): Write annotation constant name instead of
- // annotation id literal.
fprintf(out, " %saddBoolAnnotation(%s%s, %s);\n", methodPrefix.c_str(),
methodSuffix.c_str(), annotationConstant.c_str(),
annotation->value.boolValue ? "true" : "false");
@@ -82,21 +82,78 @@ static void write_annotations(FILE* out, int argIndex,
}
}
-static int write_native_stats_write_methods(FILE* out, const Atoms& atoms,
+static int write_native_method_body(FILE* out, vector<java_type_t>& signature,
+ const FieldNumberToAtomDeclSet& fieldNumberToAtomDeclSet,
+ const AtomDecl& attributionDecl) {
+ int argIndex = 1;
+ fprintf(out, " AStatsEvent_setAtomId(event, code);\n");
+ write_annotations(out, ATOM_ID_FIELD_NUMBER, fieldNumberToAtomDeclSet, "AStatsEvent_",
+ "event, ");
+ for (vector<java_type_t>::const_iterator arg = signature.begin();
+ arg != signature.end(); arg++) {
+ switch (*arg) {
+ case JAVA_TYPE_ATTRIBUTION_CHAIN: {
+ const char* uidName = attributionDecl.fields.front().name.c_str();
+ const char* tagName = attributionDecl.fields.back().name.c_str();
+ fprintf(out,
+ " AStatsEvent_writeAttributionChain(event, "
+ "reinterpret_cast<const uint32_t*>(%s), %s.data(), "
+ "static_cast<uint8_t>(%s_length));\n",
+ uidName, tagName, uidName);
+ break;
+ }
+ case JAVA_TYPE_BYTE_ARRAY:
+ fprintf(out,
+ " AStatsEvent_writeByteArray(event, "
+ "reinterpret_cast<const uint8_t*>(arg%d.arg), "
+ "arg%d.arg_length);\n",
+ argIndex, argIndex);
+ break;
+ case JAVA_TYPE_BOOLEAN:
+ fprintf(out, " AStatsEvent_writeBool(event, arg%d);\n", argIndex);
+ break;
+ case JAVA_TYPE_INT: // Fall through.
+ case JAVA_TYPE_ENUM:
+ fprintf(out, " AStatsEvent_writeInt32(event, arg%d);\n", argIndex);
+ break;
+ case JAVA_TYPE_FLOAT:
+ fprintf(out, " AStatsEvent_writeFloat(event, arg%d);\n", argIndex);
+ break;
+ case JAVA_TYPE_LONG:
+ fprintf(out, " AStatsEvent_writeInt64(event, arg%d);\n", argIndex);
+ break;
+ case JAVA_TYPE_STRING:
+ fprintf(out, " AStatsEvent_writeString(event, arg%d);\n", argIndex);
+ break;
+ default:
+ // Unsupported types: OBJECT, DOUBLE, KEY_VALUE_PAIRS
+ fprintf(stderr, "Encountered unsupported type.");
+ return 1;
+ }
+ write_annotations(out, argIndex, fieldNumberToAtomDeclSet, "AStatsEvent_",
+ "event, ");
+ argIndex++;
+ }
+ return 0;
+}
+
+static int write_native_stats_write_methods(FILE* out, const SignatureInfoMap& signatureInfoMap,
const AtomDecl& attributionDecl, const bool supportQ) {
fprintf(out, "\n");
- for (auto signatureInfoMapIt = atoms.signatureInfoMap.begin();
- signatureInfoMapIt != atoms.signatureInfoMap.end(); signatureInfoMapIt++) {
+ for (auto signatureInfoMapIt = signatureInfoMap.begin();
+ signatureInfoMapIt != signatureInfoMap.end(); signatureInfoMapIt++) {
vector<java_type_t> signature = signatureInfoMapIt->first;
const FieldNumberToAtomDeclSet& fieldNumberToAtomDeclSet = signatureInfoMapIt->second;
// Key value pairs not supported in native.
- if (find(signature.begin(), signature.end(), JAVA_TYPE_KEY_VALUE_PAIR) != signature.end()) {
+ if (std::find(signature.begin(), signature.end(), JAVA_TYPE_KEY_VALUE_PAIR) !=
+ signature.end()) {
continue;
}
- write_native_method_signature(out, "int stats_write", signature, attributionDecl, " {");
+ write_native_method_signature(out, "int stats_write(", signature, attributionDecl, " {");
- int argIndex = 1;
+ // Write method body.
if (supportQ) {
+ int argIndex = 1;
fprintf(out, " StatsEventCompat event;\n");
fprintf(out, " event.setAtomId(code);\n");
write_annotations(out, ATOM_ID_FIELD_NUMBER, fieldNumberToAtomDeclSet, "event.", "");
@@ -138,78 +195,37 @@ static int write_native_stats_write_methods(FILE* out, const Atoms& atoms,
write_annotations(out, argIndex, fieldNumberToAtomDeclSet, "event.", "");
argIndex++;
}
- fprintf(out, " return event.writeToSocket();\n");
+ fprintf(out, " return event.writeToSocket();\n"); // end method body.
} else {
fprintf(out, " AStatsEvent* event = AStatsEvent_obtain();\n");
- fprintf(out, " AStatsEvent_setAtomId(event, code);\n");
- write_annotations(out, ATOM_ID_FIELD_NUMBER, fieldNumberToAtomDeclSet, "AStatsEvent_",
- "event, ");
- for (vector<java_type_t>::const_iterator arg = signature.begin();
- arg != signature.end(); arg++) {
- switch (*arg) {
- case JAVA_TYPE_ATTRIBUTION_CHAIN: {
- const char* uidName = attributionDecl.fields.front().name.c_str();
- const char* tagName = attributionDecl.fields.back().name.c_str();
- fprintf(out,
- " AStatsEvent_writeAttributionChain(event, "
- "reinterpret_cast<const uint32_t*>(%s), %s.data(), "
- "static_cast<uint8_t>(%s_length));\n",
- uidName, tagName, uidName);
- break;
- }
- case JAVA_TYPE_BYTE_ARRAY:
- fprintf(out,
- " AStatsEvent_writeByteArray(event, "
- "reinterpret_cast<const uint8_t*>(arg%d.arg), "
- "arg%d.arg_length);\n",
- argIndex, argIndex);
- break;
- case JAVA_TYPE_BOOLEAN:
- fprintf(out, " AStatsEvent_writeBool(event, arg%d);\n", argIndex);
- break;
- case JAVA_TYPE_INT: // Fall through.
- case JAVA_TYPE_ENUM:
- fprintf(out, " AStatsEvent_writeInt32(event, arg%d);\n", argIndex);
- break;
- case JAVA_TYPE_FLOAT:
- fprintf(out, " AStatsEvent_writeFloat(event, arg%d);\n", argIndex);
- break;
- case JAVA_TYPE_LONG:
- fprintf(out, " AStatsEvent_writeInt64(event, arg%d);\n", argIndex);
- break;
- case JAVA_TYPE_STRING:
- fprintf(out, " AStatsEvent_writeString(event, arg%d);\n", argIndex);
- break;
- default:
- // Unsupported types: OBJECT, DOUBLE, KEY_VALUE_PAIRS
- fprintf(stderr, "Encountered unsupported type.");
- return 1;
- }
- write_annotations(out, argIndex, fieldNumberToAtomDeclSet, "AStatsEvent_",
- "event, ");
- argIndex++;
+ int ret = write_native_method_body(out, signature, fieldNumberToAtomDeclSet,
+ attributionDecl);
+ if (ret != 0) {
+ return ret;
}
fprintf(out, " const int ret = AStatsEvent_write(event);\n");
fprintf(out, " AStatsEvent_release(event);\n");
- fprintf(out, " return ret;\n");
+ fprintf(out, " return ret;\n"); // end method body.
}
- fprintf(out, "}\n\n");
+ fprintf(out, "}\n\n"); // end method.
}
return 0;
}
-static void write_native_stats_write_non_chained_methods(FILE* out, const Atoms& atoms,
+static void write_native_stats_write_non_chained_methods(FILE* out,
+ const SignatureInfoMap& signatureInfoMap,
const AtomDecl& attributionDecl) {
fprintf(out, "\n");
- for (auto signature_it = atoms.nonChainedSignatureInfoMap.begin();
- signature_it != atoms.nonChainedSignatureInfoMap.end(); signature_it++) {
+ for (auto signature_it = signatureInfoMap.begin();
+ signature_it != signatureInfoMap.end(); signature_it++) {
vector<java_type_t> signature = signature_it->first;
// Key value pairs not supported in native.
- if (find(signature.begin(), signature.end(), JAVA_TYPE_KEY_VALUE_PAIR) != signature.end()) {
+ if (std::find(signature.begin(), signature.end(), JAVA_TYPE_KEY_VALUE_PAIR) !=
+ signature.end()) {
continue;
}
- write_native_method_signature(out, "int stats_write_non_chained", signature,
+ write_native_method_signature(out, "int stats_write_non_chained(", signature,
attributionDecl, " {");
vector<java_type_t> newSignature;
@@ -235,6 +251,35 @@ static void write_native_stats_write_non_chained_methods(FILE* out, const Atoms&
}
}
+static int write_native_build_stats_event_methods(FILE* out,
+ const SignatureInfoMap& signatureInfoMap,
+ const AtomDecl& attributionDecl) {
+ fprintf(out, "\n");
+ for (auto signatureInfoMapIt = signatureInfoMap.begin();
+ signatureInfoMapIt != signatureInfoMap.end(); signatureInfoMapIt++) {
+ vector<java_type_t> signature = signatureInfoMapIt->first;
+ const FieldNumberToAtomDeclSet& fieldNumberToAtomDeclSet = signatureInfoMapIt->second;
+ // Key value pairs not supported in native.
+ if (std::find(signature.begin(), signature.end(), JAVA_TYPE_KEY_VALUE_PAIR) !=
+ signature.end()) {
+ continue;
+ }
+ write_native_method_signature(out, "void addAStatsEvent(AStatsEventList* pulled_data, ",
+ signature, attributionDecl, " {");
+
+ fprintf(out, " AStatsEvent* event = AStatsEventList_addStatsEvent(pulled_data);\n");
+ int ret = write_native_method_body(out, signature, fieldNumberToAtomDeclSet,
+ attributionDecl);
+ if (ret != 0) {
+ return ret;
+ }
+ fprintf(out, " AStatsEvent_build(event);\n"); // end method body.
+
+ fprintf(out, "}\n\n"); // end method.
+ }
+ return 0;
+}
+
static void write_native_method_header(FILE* out, const string& methodName,
const SignatureInfoMap& signatureInfoMap,
const AtomDecl& attributionDecl) {
@@ -243,7 +288,8 @@ static void write_native_method_header(FILE* out, const string& methodName,
vector<java_type_t> signature = signatureInfoMapIt->first;
// Key value pairs not supported in native.
- if (find(signature.begin(), signature.end(), JAVA_TYPE_KEY_VALUE_PAIR) != signature.end()) {
+ if (std::find(signature.begin(), signature.end(), JAVA_TYPE_KEY_VALUE_PAIR) !=
+ signature.end()) {
continue;
}
write_native_method_signature(out, methodName, signature, attributionDecl, ";");
@@ -262,13 +308,22 @@ int write_stats_log_cpp(FILE* out, const Atoms& atoms, const AtomDecl& attributi
fprintf(out, "#include <StatsEventCompat.h>\n");
} else {
fprintf(out, "#include <stats_event.h>\n");
+
+ if (!atoms.pulledAtomsSignatureInfoMap.empty()) {
+ fprintf(out, "#include <stats_pull_atom_callback.h>\n");
+ }
}
+
+
fprintf(out, "\n");
write_namespace(out, cppNamespace);
- write_native_stats_write_methods(out, atoms, attributionDecl, supportQ);
- write_native_stats_write_non_chained_methods(out, atoms, attributionDecl);
+ write_native_stats_write_methods(out, atoms.signatureInfoMap, attributionDecl, supportQ);
+ write_native_stats_write_non_chained_methods(out, atoms.nonChainedSignatureInfoMap,
+ attributionDecl);
+ write_native_build_stats_event_methods(out, atoms.pulledAtomsSignatureInfoMap,
+ attributionDecl);
// Print footer
fprintf(out, "\n");
@@ -288,6 +343,9 @@ int write_stats_log_header(FILE* out, const Atoms& atoms, const AtomDecl& attrib
fprintf(out, "#include <vector>\n");
fprintf(out, "#include <map>\n");
fprintf(out, "#include <set>\n");
+ if (!atoms.pulledAtomsSignatureInfoMap.empty()) {
+ fprintf(out, "#include <stats_pull_atom_callback.h>\n");
+ }
fprintf(out, "\n");
write_namespace(out, cppNamespace);
@@ -337,12 +395,22 @@ int write_stats_log_header(FILE* out, const Atoms& atoms, const AtomDecl& attrib
fprintf(out, "//\n");
fprintf(out, "// Write methods\n");
fprintf(out, "//\n");
- write_native_method_header(out, "int stats_write", atoms.signatureInfoMap, attributionDecl);
+ write_native_method_header(out, "int stats_write(", atoms.signatureInfoMap, attributionDecl);
+ fprintf(out, "\n");
fprintf(out, "//\n");
fprintf(out, "// Write flattened methods\n");
fprintf(out, "//\n");
- write_native_method_header(out, "int stats_write_non_chained", atoms.nonChainedSignatureInfoMap,
+ write_native_method_header(out, "int stats_write_non_chained(", atoms.nonChainedSignatureInfoMap,
+ attributionDecl);
+ fprintf(out, "\n");
+
+ // Print pulled atoms methods.
+ fprintf(out, "//\n");
+ fprintf(out, "// Add AStatsEvent methods\n");
+ fprintf(out, "//\n");
+ write_native_method_header(out, "void addAStatsEvent(AStatsEventList* pulled_data, ",
+ atoms.pulledAtomsSignatureInfoMap,
attributionDecl);
fprintf(out, "\n");
diff --git a/tools/stats_log_api_gen/native_writer.h b/tools/stats_log_api_gen/native_writer.h
index 264d4db29fc9..4e42d1fa2809 100644
--- a/tools/stats_log_api_gen/native_writer.h
+++ b/tools/stats_log_api_gen/native_writer.h
@@ -14,7 +14,8 @@
* limitations under the License.
*/
-#pragma once
+#ifndef ANDROID_STATS_LOG_API_GEN_NATIVE_WRITER_H
+#define ANDROID_STATS_LOG_API_GEN_NATIVE_WRITER_H
#include <stdio.h>
#include <string.h>
@@ -24,8 +25,6 @@
namespace android {
namespace stats_log_api_gen {
-using namespace std;
-
int write_stats_log_cpp(FILE* out, const Atoms& atoms, const AtomDecl& attributionDecl,
const string& cppNamespace, const string& importHeader,
const bool supportQ);
@@ -35,3 +34,5 @@ int write_stats_log_header(FILE* out, const Atoms& atoms, const AtomDecl& attrib
} // namespace stats_log_api_gen
} // namespace android
+
+#endif // ANDROID_STATS_LOG_API_GEN_NATIVE_WRITER_H
diff --git a/tools/stats_log_api_gen/test_collation.cpp b/tools/stats_log_api_gen/test_collation.cpp
index 5fd728a29c07..6f78921d8f1c 100644
--- a/tools/stats_log_api_gen/test_collation.cpp
+++ b/tools/stats_log_api_gen/test_collation.cpp
@@ -24,7 +24,6 @@ namespace android {
namespace stats_log_api_gen {
using std::map;
-using std::set;
using std::vector;
/**
@@ -32,11 +31,11 @@ using std::vector;
*/
static bool map_contains_vector(const SignatureInfoMap& s, int count, ...) {
va_list args;
- vector<java_type_t> v;
+ vector<java_type_t> v(count);
va_start(args, count);
for (int i = 0; i < count; i++) {
- v.push_back((java_type_t)va_arg(args, int));
+ v[i] = static_cast<java_type_t>(va_arg(args, int));
}
va_end(args);
@@ -222,7 +221,7 @@ TEST(CollationTest, FailOnBadBinaryFieldAtom) {
Atoms atoms;
int errorCount =
collate_atoms(BadEventWithBinaryFieldAtom::descriptor(), DEFAULT_MODULE_NAME, &atoms);
- EXPECT_TRUE(errorCount > 0);
+ EXPECT_GT(errorCount, 0);
}
TEST(CollationTest, PassOnLogFromModuleAtom) {
diff --git a/tools/stats_log_api_gen/utils.cpp b/tools/stats_log_api_gen/utils.cpp
index abb89133e58e..1eaf42acf153 100644
--- a/tools/stats_log_api_gen/utils.cpp
+++ b/tools/stats_log_api_gen/utils.cpp
@@ -16,11 +16,30 @@
#include "utils.h"
-#include "android-base/strings.h"
-
namespace android {
namespace stats_log_api_gen {
+/**
+ * Inlining this method because "android-base/strings.h" is not available on
+ * google3.
+ */
+static vector<string> Split(const string& s, const string& delimiters) {
+ GOOGLE_CHECK_NE(delimiters.size(), 0U);
+
+ vector<string> result;
+
+ size_t base = 0;
+ size_t found;
+ while (true) {
+ found = s.find_first_of(delimiters, base);
+ result.push_back(s.substr(base, found - base));
+ if (found == s.npos) break;
+ base = found + 1;
+ }
+
+ return result;
+}
+
static void build_non_chained_decl_map(const Atoms& atoms,
std::map<int, AtomDeclSet::const_iterator>* decl_map) {
for (AtomDeclSet::const_iterator atomIt = atoms.non_chained_decls.begin();
@@ -29,6 +48,20 @@ static void build_non_chained_decl_map(const Atoms& atoms,
}
}
+const map<AnnotationId, string>& get_annotation_id_constants() {
+ static const map<AnnotationId, string>* ANNOTATION_ID_CONSTANTS =
+ new map<AnnotationId, string>{
+ {ANNOTATION_ID_IS_UID, "ANNOTATION_ID_IS_UID"},
+ {ANNOTATION_ID_TRUNCATE_TIMESTAMP, "ANNOTATION_ID_TRUNCATE_TIMESTAMP"},
+ {ANNOTATION_ID_PRIMARY_FIELD, "ANNOTATION_ID_PRIMARY_FIELD"},
+ {ANNOTATION_ID_PRIMARY_FIELD_FIRST_UID, "ANNOTATION_ID_PRIMARY_FIELD_FIRST_UID"},
+ {ANNOTATION_ID_EXCLUSIVE_STATE, "ANNOTATION_ID_EXCLUSIVE_STATE"},
+ {ANNOTATION_ID_TRIGGER_STATE_RESET, "ANNOTATION_ID_TRIGGER_STATE_RESET"},
+ {ANNOTATION_ID_STATE_NESTED, "ANNOTATION_ID_STATE_NESTED"}};
+
+ return *ANNOTATION_ID_CONSTANTS;
+}
+
/**
* Turn lower and camel case into upper case with underscores.
*/
@@ -102,15 +135,15 @@ const char* java_type_name(java_type_t type) {
// Writes namespaces for the cpp and header files, returning the number of
// namespaces written.
void write_namespace(FILE* out, const string& cppNamespaces) {
- vector<string> cppNamespaceVec = android::base::Split(cppNamespaces, ",");
- for (string cppNamespace : cppNamespaceVec) {
+ vector<string> cppNamespaceVec = Split(cppNamespaces, ",");
+ for (const string& cppNamespace : cppNamespaceVec) {
fprintf(out, "namespace %s {\n", cppNamespace.c_str());
}
}
// Writes namespace closing brackets for cpp and header files.
void write_closing_namespace(FILE* out, const string& cppNamespaces) {
- vector<string> cppNamespaceVec = android::base::Split(cppNamespaces, ",");
+ vector<string> cppNamespaceVec = Split(cppNamespaces, ",");
for (auto it = cppNamespaceVec.rbegin(); it != cppNamespaceVec.rend(); ++it) {
fprintf(out, "} // namespace %s\n", it->c_str());
}
@@ -123,7 +156,7 @@ static void write_cpp_usage(FILE* out, const string& method_name, const string&
for (vector<AtomField>::const_iterator field = atom->fields.begin();
field != atom->fields.end(); field++) {
if (field->javaType == JAVA_TYPE_ATTRIBUTION_CHAIN) {
- for (auto chainField : attributionDecl.fields) {
+ for (const auto& chainField : attributionDecl.fields) {
if (chainField.javaType == JAVA_TYPE_STRING) {
fprintf(out, ", const std::vector<%s>& %s", cpp_type_name(chainField.javaType),
chainField.name.c_str());
@@ -182,15 +215,15 @@ void write_native_atom_constants(FILE* out, const Atoms& atoms, const AtomDecl&
fprintf(out, "\n");
}
-void write_native_method_signature(FILE* out, const string& methodName,
+void write_native_method_signature(FILE* out, const string& signaturePrefix,
const vector<java_type_t>& signature,
const AtomDecl& attributionDecl, const string& closer) {
- fprintf(out, "%s(int32_t code", methodName.c_str());
+ fprintf(out, "%sint32_t code", signaturePrefix.c_str());
int argIndex = 1;
for (vector<java_type_t>::const_iterator arg = signature.begin(); arg != signature.end();
arg++) {
if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
- for (auto chainField : attributionDecl.fields) {
+ for (const auto& chainField : attributionDecl.fields) {
if (chainField.javaType == JAVA_TYPE_STRING) {
fprintf(out, ", const std::vector<%s>& %s", cpp_type_name(chainField.javaType),
chainField.name.c_str());
@@ -222,7 +255,7 @@ void write_native_method_call(FILE* out, const string& methodName,
for (vector<java_type_t>::const_iterator arg = signature.begin(); arg != signature.end();
arg++) {
if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
- for (auto chainField : attributionDecl.fields) {
+ for (const auto& chainField : attributionDecl.fields) {
if (chainField.javaType == JAVA_TYPE_STRING) {
fprintf(out, ", %s", chainField.name.c_str());
} else {
diff --git a/tools/stats_log_api_gen/utils.h b/tools/stats_log_api_gen/utils.h
index 73e0cb838227..13a7e2d8a54e 100644
--- a/tools/stats_log_api_gen/utils.h
+++ b/tools/stats_log_api_gen/utils.h
@@ -14,7 +14,8 @@
* limitations under the License.
*/
-#pragma once
+#ifndef ANDROID_STATS_LOG_API_GEN_UTILS_H
+#define ANDROID_STATS_LOG_API_GEN_UTILS_H
#include <stdio.h>
#include <string.h>
@@ -28,23 +29,14 @@
namespace android {
namespace stats_log_api_gen {
-using namespace std;
-
-const string DEFAULT_CPP_NAMESPACE = "android,util";
-const string DEFAULT_CPP_HEADER_IMPORT = "statslog.h";
+const char DEFAULT_CPP_NAMESPACE[] = "android,util";
+const char DEFAULT_CPP_HEADER_IMPORT[] = "statslog.h";
const int JAVA_MODULE_REQUIRES_FLOAT = 0x01;
const int JAVA_MODULE_REQUIRES_ATTRIBUTION = 0x02;
const int JAVA_MODULE_REQUIRES_KEY_VALUE_PAIRS = 0x04;
-const map<AnnotationId, string> ANNOTATION_ID_CONSTANTS = {
- {ANNOTATION_ID_IS_UID, "ANNOTATION_ID_IS_UID"},
- {ANNOTATION_ID_TRUNCATE_TIMESTAMP, "ANNOTATION_ID_TRUNCATE_TIMESTAMP"},
- {ANNOTATION_ID_PRIMARY_FIELD, "ANNOTATION_ID_PRIMARY_FIELD"},
- {ANNOTATION_ID_PRIMARY_FIELD_FIRST_UID, "ANNOTATION_ID_PRIMARY_FIELD_FIRST_UID"},
- {ANNOTATION_ID_EXCLUSIVE_STATE, "ANNOTATION_ID_EXCLUSIVE_STATE"},
- {ANNOTATION_ID_TRIGGER_STATE_RESET, "ANNOTATION_ID_TRIGGER_STATE_RESET"},
- {ANNOTATION_ID_STATE_NESTED, "ANNOTATION_ID_STATE_NESTED"}};
+const map<AnnotationId, string>& get_annotation_id_constants();
string make_constant_name(const string& str);
@@ -59,7 +51,7 @@ void write_closing_namespace(FILE* out, const string& cppNamespaces);
void write_native_atom_constants(FILE* out, const Atoms& atoms, const AtomDecl& attributionDecl);
-void write_native_method_signature(FILE* out, const string& methodName,
+void write_native_method_signature(FILE* out, const string& signaturePrefix,
const vector<java_type_t>& signature,
const AtomDecl& attributionDecl, const string& closer);
@@ -81,3 +73,5 @@ int write_java_work_source_methods(FILE* out, const SignatureInfoMap& signatureI
} // namespace stats_log_api_gen
} // namespace android
+
+#endif // ANDROID_STATS_LOG_API_GEN_UTILS_H
diff --git a/wifi/java/android/net/wifi/WifiNetworkSuggestion.java b/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
index 4d3a2c02c686..68eb1bbd8a79 100644
--- a/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
+++ b/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
@@ -943,6 +943,9 @@ public final class WifiNetworkSuggestion implements Parcelable {
*/
@Nullable
public WifiEnterpriseConfig getEnterpriseConfig() {
+ if (!wifiConfiguration.isEnterprise()) {
+ return null;
+ }
return wifiConfiguration.enterpriseConfig;
}
diff --git a/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java b/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java
index 16b4ad08a830..f0839e9b3122 100644
--- a/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java
@@ -62,6 +62,7 @@ public class WifiNetworkSuggestionTest {
assertEquals(-1, suggestion.wifiConfiguration.priority);
assertFalse(suggestion.isUserAllowedToManuallyConnect);
assertTrue(suggestion.isInitialAutoJoinEnabled);
+ assertNull(suggestion.getEnterpriseConfig());
}
/**
@@ -92,6 +93,7 @@ public class WifiNetworkSuggestionTest {
assertEquals(0, suggestion.wifiConfiguration.priority);
assertFalse(suggestion.isUserAllowedToManuallyConnect);
assertTrue(suggestion.isInitialAutoJoinEnabled);
+ assertNull(suggestion.getEnterpriseConfig());
}
/**
@@ -122,6 +124,7 @@ public class WifiNetworkSuggestionTest {
assertEquals(-1, suggestion.wifiConfiguration.priority);
assertTrue(suggestion.isUserAllowedToManuallyConnect);
assertFalse(suggestion.isInitialAutoJoinEnabled);
+ assertNull(suggestion.getEnterpriseConfig());
}
/**
@@ -152,6 +155,7 @@ public class WifiNetworkSuggestionTest {
assertEquals(-1, suggestion.wifiConfiguration.priority);
assertTrue(suggestion.isUserAllowedToManuallyConnect);
assertFalse(suggestion.isInitialAutoJoinEnabled);
+ assertNull(suggestion.getEnterpriseConfig());
}
/**
@@ -174,6 +178,7 @@ public class WifiNetworkSuggestionTest {
assertTrue(suggestion.wifiConfiguration.requirePmf);
assertFalse(suggestion.isUserAllowedToManuallyConnect);
assertTrue(suggestion.isInitialAutoJoinEnabled);
+ assertNull(suggestion.getEnterpriseConfig());
}
/**
@@ -197,6 +202,7 @@ public class WifiNetworkSuggestionTest {
assertTrue(suggestion.wifiConfiguration.requirePmf);
assertTrue(suggestion.isUserAllowedToManuallyConnect);
assertFalse(suggestion.isInitialAutoJoinEnabled);
+ assertNull(suggestion.getEnterpriseConfig());
}
@@ -230,6 +236,7 @@ public class WifiNetworkSuggestionTest {
// here.
assertTrue(suggestion.isUserAllowedToManuallyConnect);
assertTrue(suggestion.isInitialAutoJoinEnabled);
+ assertNotNull(suggestion.getEnterpriseConfig());
}
/**
@@ -286,6 +293,7 @@ public class WifiNetworkSuggestionTest {
.get(WifiConfiguration.GroupCipher.SMS4));
assertEquals("\"" + TEST_PRESHARED_KEY + "\"",
suggestion.wifiConfiguration.preSharedKey);
+ assertNull(suggestion.getEnterpriseConfig());
}
@@ -316,6 +324,7 @@ public class WifiNetworkSuggestionTest {
suggestion.wifiConfiguration.enterpriseConfig.getEapMethod());
assertEquals(TEST_WAPI_CERT_SUITE,
suggestion.wifiConfiguration.enterpriseConfig.getWapiCertSuite());
+ assertNotNull(suggestion.getEnterpriseConfig());
}
/**
@@ -345,6 +354,7 @@ public class WifiNetworkSuggestionTest {
suggestion.wifiConfiguration.enterpriseConfig.getEapMethod());
assertEquals("",
suggestion.wifiConfiguration.enterpriseConfig.getWapiCertSuite());
+ assertNotNull(suggestion.getEnterpriseConfig());
}
/**
@@ -367,6 +377,7 @@ public class WifiNetworkSuggestionTest {
assertEquals(suggestion.getPasspointConfig().getMeteredOverride(),
WifiConfiguration.METERED_OVERRIDE_METERED);
assertTrue(suggestion.isUserAllowedToManuallyConnect);
+ assertNull(suggestion.getEnterpriseConfig());
}
/**
diff --git a/wifi/tests/src/android/net/wifi/aware/TlvBufferUtilsTest.java b/wifi/tests/src/android/net/wifi/aware/TlvBufferUtilsTest.java
index 971aa8e05df2..79e95e81396a 100644
--- a/wifi/tests/src/android/net/wifi/aware/TlvBufferUtilsTest.java
+++ b/wifi/tests/src/android/net/wifi/aware/TlvBufferUtilsTest.java
@@ -267,42 +267,42 @@ public class TlvBufferUtilsTest {
@Test(expected = IllegalArgumentException.class)
public void testTlvItInvalidSizeT1L0() {
- final byte[] dummy = {
+ final byte[] testTlv = {
0, 1, 2 };
- final int dummyLength = 3;
- TlvBufferUtils.TlvIterable tlvIt10 = new TlvBufferUtils.TlvIterable(1, 0, dummy);
+ final int testLength = 3;
+ TlvBufferUtils.TlvIterable tlvIt10 = new TlvBufferUtils.TlvIterable(1, 0, testTlv);
}
@Test(expected = IllegalArgumentException.class)
public void testTlvItInvalidSizeTm3L2() {
- final byte[] dummy = {
+ final byte[] testTlv = {
0, 1, 2 };
- final int dummyLength = 3;
- TlvBufferUtils.TlvIterable tlvIt10 = new TlvBufferUtils.TlvIterable(-3, 2, dummy);
+ final int testLength = 3;
+ TlvBufferUtils.TlvIterable tlvIt10 = new TlvBufferUtils.TlvIterable(-3, 2, testTlv);
}
@Test(expected = IllegalArgumentException.class)
public void testTlvItInvalidSizeT1Lm2() {
- final byte[] dummy = {
+ final byte[] testTlv = {
0, 1, 2 };
- final int dummyLength = 3;
- TlvBufferUtils.TlvIterable tlvIt10 = new TlvBufferUtils.TlvIterable(1, -2, dummy);
+ final int testLength = 3;
+ TlvBufferUtils.TlvIterable tlvIt10 = new TlvBufferUtils.TlvIterable(1, -2, testTlv);
}
@Test(expected = IllegalArgumentException.class)
public void testTlvItInvalidSizeT1L3() {
- final byte[] dummy = {
+ final byte[] testTlv = {
0, 1, 2 };
- final int dummyLength = 3;
- TlvBufferUtils.TlvIterable tlvIt10 = new TlvBufferUtils.TlvIterable(1, 3, dummy);
+ final int testLength = 3;
+ TlvBufferUtils.TlvIterable tlvIt10 = new TlvBufferUtils.TlvIterable(1, 3, testTlv);
}
@Test(expected = IllegalArgumentException.class)
public void testTlvItInvalidSizeT3L1() {
- final byte[] dummy = {
+ final byte[] testTlv = {
0, 1, 2 };
- final int dummyLength = 3;
- TlvBufferUtils.TlvIterable tlvIt10 = new TlvBufferUtils.TlvIterable(3, 1, dummy);
+ final int testLength = 3;
+ TlvBufferUtils.TlvIterable tlvIt10 = new TlvBufferUtils.TlvIterable(3, 1, testTlv);
}
/**
diff --git a/wifi/tests/src/android/net/wifi/aware/WifiAwareAgentNetworkSpecifierTest.java b/wifi/tests/src/android/net/wifi/aware/WifiAwareAgentNetworkSpecifierTest.java
index f2961db4eb14..b65de6b9789d 100644
--- a/wifi/tests/src/android/net/wifi/aware/WifiAwareAgentNetworkSpecifierTest.java
+++ b/wifi/tests/src/android/net/wifi/aware/WifiAwareAgentNetworkSpecifierTest.java
@@ -45,7 +45,7 @@ public class WifiAwareAgentNetworkSpecifierTest {
Set<WifiAwareNetworkSpecifier> nsSet = new HashSet<>();
for (int i = 0; i < numNs; ++i) {
- nsSet.add(getDummyNetworkSpecifier(10 + i));
+ nsSet.add(getMockNetworkSpecifier(10 + i));
}
WifiAwareAgentNetworkSpecifier dut = new WifiAwareAgentNetworkSpecifier(
nsSet.toArray(new WifiAwareNetworkSpecifier[numNs]));
@@ -78,7 +78,7 @@ public class WifiAwareAgentNetworkSpecifierTest {
@Test
public void testEmptyDoesntMatchAnything() {
WifiAwareAgentNetworkSpecifier dut = new WifiAwareAgentNetworkSpecifier();
- WifiAwareNetworkSpecifier ns = getDummyNetworkSpecifier(6);
+ WifiAwareNetworkSpecifier ns = getMockNetworkSpecifier(6);
collector.checkThat("No match expected", ns.canBeSatisfiedBy(dut), equalTo(false));
}
@@ -88,9 +88,9 @@ public class WifiAwareAgentNetworkSpecifierTest {
*/
@Test
public void testSingleMatch() {
- WifiAwareNetworkSpecifier nsThis = getDummyNetworkSpecifier(6);
+ WifiAwareNetworkSpecifier nsThis = getMockNetworkSpecifier(6);
WifiAwareAgentNetworkSpecifier dut = new WifiAwareAgentNetworkSpecifier(nsThis);
- WifiAwareNetworkSpecifier nsOther = getDummyNetworkSpecifier(8);
+ WifiAwareNetworkSpecifier nsOther = getMockNetworkSpecifier(8);
collector.checkThat("Match expected", nsThis.canBeSatisfiedBy(dut), equalTo(true));
collector.checkThat("No match expected", nsOther.canBeSatisfiedBy(dut), equalTo(false));
}
@@ -105,12 +105,12 @@ public class WifiAwareAgentNetworkSpecifierTest {
Set<WifiAwareNetworkSpecifier> nsSet = new HashSet<>();
for (int i = 0; i < numNs; ++i) {
- nsSet.add(getDummyNetworkSpecifier(10 + i));
+ nsSet.add(getMockNetworkSpecifier(10 + i));
}
WifiAwareAgentNetworkSpecifier dut = new WifiAwareAgentNetworkSpecifier(
nsSet.toArray(new WifiAwareNetworkSpecifier[numNs]));
- WifiAwareNetworkSpecifier nsOther = getDummyNetworkSpecifier(10000);
+ WifiAwareNetworkSpecifier nsOther = getMockNetworkSpecifier(10000);
for (WifiAwareNetworkSpecifier nsThis: nsSet) {
collector.checkThat("Match expected", nsThis.canBeSatisfiedBy(dut), equalTo(true));
@@ -127,13 +127,13 @@ public class WifiAwareAgentNetworkSpecifierTest {
Set<WifiAwareNetworkSpecifier> nsSet = new HashSet<>();
for (int i = 0; i < numNs; ++i) {
- nsSet.add(getDummyNetworkSpecifier(10 + i));
+ nsSet.add(getMockNetworkSpecifier(10 + i));
}
WifiAwareAgentNetworkSpecifier oldNs = new WifiAwareAgentNetworkSpecifier(
nsSet.toArray(new WifiAwareNetworkSpecifier[nsSet.size()]));
- nsSet.add(getDummyNetworkSpecifier(100 + numNs));
+ nsSet.add(getMockNetworkSpecifier(100 + numNs));
WifiAwareAgentNetworkSpecifier newNs = new WifiAwareAgentNetworkSpecifier(
nsSet.toArray(new WifiAwareNetworkSpecifier[nsSet.size()]));
@@ -149,13 +149,13 @@ public class WifiAwareAgentNetworkSpecifierTest {
Set<WifiAwareNetworkSpecifier> nsSet = new HashSet<>();
for (int i = 0; i < numNs; ++i) {
- nsSet.add(getDummyNetworkSpecifier(10 + i));
+ nsSet.add(getMockNetworkSpecifier(10 + i));
}
WifiAwareAgentNetworkSpecifier newNs = new WifiAwareAgentNetworkSpecifier(
nsSet.toArray(new WifiAwareNetworkSpecifier[nsSet.size()]));
- nsSet.add(getDummyNetworkSpecifier(100 + numNs));
+ nsSet.add(getMockNetworkSpecifier(100 + numNs));
WifiAwareAgentNetworkSpecifier oldNs = new WifiAwareAgentNetworkSpecifier(
nsSet.toArray(new WifiAwareNetworkSpecifier[nsSet.size()]));
@@ -165,10 +165,10 @@ public class WifiAwareAgentNetworkSpecifierTest {
// utilities
/**
- * Returns a WifiAwareNetworkSpecifier with dummy (but valid) entries. Each can be
+ * Returns a WifiAwareNetworkSpecifier with mock (but valid) entries. Each can be
* differentiated (made unique) by specifying a different client ID.
*/
- WifiAwareNetworkSpecifier getDummyNetworkSpecifier(int clientId) {
+ WifiAwareNetworkSpecifier getMockNetworkSpecifier(int clientId) {
return new WifiAwareNetworkSpecifier(WifiAwareNetworkSpecifier.NETWORK_SPECIFIER_TYPE_OOB,
WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_INITIATOR, clientId, 0, 0, new byte[6],
null, null, 10, 5);
diff --git a/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java b/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java
index c5f98045082b..43d728bf593e 100644
--- a/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java
@@ -1585,7 +1585,7 @@ public class WifiAwareManagerTest {
public void testWifiAwareNetworkCapabilitiesParcel() throws UnknownHostException {
final Inet6Address inet6 = MacAddress.fromString(
"11:22:33:44:55:66").getLinkLocalIpv6FromEui48Mac();
- // note: dummy scope = 5
+ // note: placeholder scope = 5
final Inet6Address inet6Scoped = Inet6Address.getByAddress(null, inet6.getAddress(), 5);
final int port = 5;
final int transportProtocol = 6;